Add overrideUrlLoading overriding ... yeah ... to plugins by the plugin adding a <url-filter.../> and implmenting the onOverrideUrlLoading(...) method

This commit is contained in:
Dave Johnson 2011-08-30 16:52:56 -07:00
parent 8d35b1aeef
commit 3e5a52ceee
4 changed files with 77 additions and 31 deletions

View File

@ -87,4 +87,11 @@ public interface IPlugin {
*/ */
void onActivityResult(int requestCode, int resultCode, Intent intent); void onActivityResult(int requestCode, int resultCode, Intent intent);
} /**
* By specifying a <url-filter> in plugins.xml you can map a URL (using startsWith atm) to this method.
*
* @param url The URL that is trying to be loaded in the PhoneGap webview.
* @return Return true to prevent the URL from loading. Default is false.
*/
boolean onOverrideUrlLoading(String url);
}

View File

@ -47,4 +47,11 @@ public abstract class PhonegapActivity extends Activity {
* @param plugin The plugin on which onActivityResult is to be called * @param plugin The plugin on which onActivityResult is to be called
*/ */
abstract public void setActivityResultCallback(IPlugin plugin); abstract public void setActivityResultCallback(IPlugin plugin);
/**
* Load the specified URL in the PhoneGap webview.
*
* @param url The URL to load.
*/
abstract public void loadUrl(String url);
} }

View File

@ -104,6 +104,10 @@ public abstract class Plugin implements IPlugin {
public void onActivityResult(int requestCode, int resultCode, Intent intent) { public void onActivityResult(int requestCode, int resultCode, Intent intent) {
} }
public boolean onOverrideUrlLoading(String url) {
return false;
}
/** /**
* Send generic JavaScript statement back to JavaScript. * Send generic JavaScript statement back to JavaScript.
* success(...) and error(...) should be used instead where possible. * success(...) and error(...) should be used instead where possible.

View File

@ -9,6 +9,7 @@ package com.phonegap.api;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.json.JSONArray; import org.json.JSONArray;
@ -17,6 +18,7 @@ import org.xmlpull.v1.XmlPullParserException;
import android.content.Intent; import android.content.Intent;
import android.content.res.XmlResourceParser; import android.content.res.XmlResourceParser;
import android.util.Log;
import android.webkit.WebView; import android.webkit.WebView;
/** /**
@ -25,7 +27,7 @@ import android.webkit.WebView;
* Calling native plugin code can be done by calling PluginManager.exec(...) * Calling native plugin code can be done by calling PluginManager.exec(...)
* from JavaScript. * from JavaScript.
*/ */
public final class PluginManager { public final class PluginManager {
private HashMap<String, IPlugin> plugins = new HashMap<String,IPlugin>(); private HashMap<String, IPlugin> plugins = new HashMap<String,IPlugin>();
private HashMap<String, String> services = new HashMap<String,String>(); private HashMap<String, String> services = new HashMap<String,String>();
@ -33,6 +35,10 @@ public final class PluginManager {
private final PhonegapActivity ctx; private final PhonegapActivity ctx;
private final WebView app; private final WebView app;
// Map URL schemes like foo: to plugins that want to handle those schemes
// This would allow how all URLs are handled to be offloaded to a plugin
protected HashMap<String, String> urlMap = new HashMap<String,String>();
/** /**
* Constructor. * Constructor.
* *
@ -53,14 +59,17 @@ public final class PluginManager {
if (id == 0) { pluginConfigurationMissing(); } if (id == 0) { pluginConfigurationMissing(); }
XmlResourceParser xml = ctx.getResources().getXml(id); XmlResourceParser xml = ctx.getResources().getXml(id);
int eventType = -1; int eventType = -1;
String pluginClass = "", pluginName = "";
while (eventType != XmlResourceParser.END_DOCUMENT) { while (eventType != XmlResourceParser.END_DOCUMENT) {
if (eventType == XmlResourceParser.START_TAG) { if (eventType == XmlResourceParser.START_TAG) {
String strNode = xml.getName(); String strNode = xml.getName();
if (strNode.equals("plugin")) { if (strNode.equals("plugin")) {
String name = xml.getAttributeValue(null, "name"); pluginClass = xml.getAttributeValue(null, "value");
String value = xml.getAttributeValue(null, "value"); pluginName = xml.getAttributeValue(null, "name");
//System.out.println("Plugin: "+name+" => "+value); //System.out.println("Plugin: "+name+" => "+value);
this.addService(name, value); this.addService(pluginName, pluginClass);
} else if (strNode.equals("url-filter")) {
this.urlMap.put(xml.getAttributeValue(null, "value"), pluginName);
} }
} }
try { try {
@ -101,14 +110,9 @@ public final class PluginManager {
boolean runAsync = async; boolean runAsync = async;
try { try {
final JSONArray args = new JSONArray(jsonArgs); final JSONArray args = new JSONArray(jsonArgs);
String clazz = this.services.get(service); final IPlugin plugin = this.getPlugin(service);
Class c = null; final PhonegapActivity ctx = this.ctx;
if (clazz != null) { if (plugin != null) {
c = getClassByName(clazz);
}
if (isPhoneGapPlugin(c)) {
final IPlugin plugin = this.addPlugin(clazz, c);
final PhonegapActivity ctx = this.ctx;
runAsync = async && !plugin.isSynch(action); runAsync = async && !plugin.isSynch(action);
if (runAsync) { if (runAsync) {
// Run this on a different thread so that this one can return back to JS // Run this on a different thread so that this one can return back to JS
@ -150,8 +154,6 @@ public final class PluginManager {
} }
} }
} }
} catch (ClassNotFoundException e) {
cr = new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION);
} catch (JSONException e) { } catch (JSONException e) {
System.out.println("ERROR: "+e.toString()); System.out.println("ERROR: "+e.toString());
cr = new PluginResult(PluginResult.Status.JSON_EXCEPTION); cr = new PluginResult(PluginResult.Status.JSON_EXCEPTION);
@ -175,7 +177,11 @@ public final class PluginManager {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private Class getClassByName(final String clazz) throws ClassNotFoundException { private Class getClassByName(final String clazz) throws ClassNotFoundException {
return Class.forName(clazz); Class c = null;
if (clazz != null) {
c = Class.forName(clazz);
}
return c;
} }
/** /**
@ -203,18 +209,17 @@ public final class PluginManager {
* @return The plugin * @return The plugin
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private IPlugin addPlugin(String className, Class clazz) { private IPlugin addPlugin(String pluginName, String className) {
if (this.plugins.containsKey(className)) { try {
return this.getPlugin(className); Class c = getClassByName(className);
} if (isPhoneGapPlugin(c)) {
try { IPlugin plugin = (IPlugin)c.newInstance();
IPlugin plugin = (IPlugin)clazz.newInstance(); this.plugins.put(className, plugin);
this.plugins.put(className, plugin); plugin.setContext(this.ctx);
plugin.setContext(this.ctx); plugin.setView(this.app);
plugin.setView(this.app); return plugin;
return plugin; }
} } catch (Exception e) {
catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
System.out.println("Error adding plugin "+className+"."); System.out.println("Error adding plugin "+className+".");
} }
@ -224,12 +229,18 @@ public final class PluginManager {
/** /**
* Get the loaded plugin. * Get the loaded plugin.
* *
* If the plugin is not already loaded then load it.
*
* @param className The class of the loaded plugin. * @param className The class of the loaded plugin.
* @return * @return
*/ */
private IPlugin getPlugin(String className) { private IPlugin getPlugin(String pluginName) {
IPlugin plugin = this.plugins.get(className); String className = this.services.get(pluginName);
return plugin; if (this.plugins.containsKey(className)) {
return this.plugins.get(className);
} else {
return this.addPlugin(pluginName, className);
}
} }
/** /**
@ -299,6 +310,23 @@ public final class PluginManager {
} }
} }
/**
* Called when the URL of the webview changes.
*
* @param url The URL that is being changed to.
* @return Return false to allow the URL to load, return true to prevent the URL from loading.
*/
public boolean onOverrideUrlLoading(String url) {
Iterator<Entry<String, String>> it = this.urlMap.entrySet().iterator();
while (it.hasNext()) {
HashMap.Entry<String, String> pairs = it.next();
if (url.startsWith(pairs.getKey())) {
return this.getPlugin(pairs.getValue()).onOverrideUrlLoading(url);
}
}
return false;
}
private void pluginConfigurationMissing() { private void pluginConfigurationMissing() {
System.err.println("====================================================================================="); System.err.println("=====================================================================================");
System.err.println("ERROR: plugin.xml is missing. Add res/xml/plugins.xml to your project."); System.err.println("ERROR: plugin.xml is missing. Add res/xml/plugins.xml to your project.");