From 3e5a52ceeedc18804a6d11650c748ef4ee991cb1 Mon Sep 17 00:00:00 2001 From: Dave Johnson Date: Tue, 30 Aug 2011 16:52:56 -0700 Subject: [PATCH] Add overrideUrlLoading overriding ... yeah ... to plugins by the plugin adding a and implmenting the onOverrideUrlLoading(...) method --- framework/src/com/phonegap/api/IPlugin.java | 9 +- .../com/phonegap/api/PhonegapActivity.java | 7 ++ framework/src/com/phonegap/api/Plugin.java | 4 + .../src/com/phonegap/api/PluginManager.java | 88 ++++++++++++------- 4 files changed, 77 insertions(+), 31 deletions(-) diff --git a/framework/src/com/phonegap/api/IPlugin.java b/framework/src/com/phonegap/api/IPlugin.java index 5da8e563..7edb30a2 100755 --- a/framework/src/com/phonegap/api/IPlugin.java +++ b/framework/src/com/phonegap/api/IPlugin.java @@ -87,4 +87,11 @@ public interface IPlugin { */ void onActivityResult(int requestCode, int resultCode, Intent intent); -} + /** + * By specifying a 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); +} \ No newline at end of file diff --git a/framework/src/com/phonegap/api/PhonegapActivity.java b/framework/src/com/phonegap/api/PhonegapActivity.java index 558bad40..30e3c615 100755 --- a/framework/src/com/phonegap/api/PhonegapActivity.java +++ b/framework/src/com/phonegap/api/PhonegapActivity.java @@ -47,4 +47,11 @@ public abstract class PhonegapActivity extends Activity { * @param plugin The plugin on which onActivityResult is to be called */ 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); } diff --git a/framework/src/com/phonegap/api/Plugin.java b/framework/src/com/phonegap/api/Plugin.java index 282f60f4..7efd2ed2 100755 --- a/framework/src/com/phonegap/api/Plugin.java +++ b/framework/src/com/phonegap/api/Plugin.java @@ -104,6 +104,10 @@ public abstract class Plugin implements IPlugin { public void onActivityResult(int requestCode, int resultCode, Intent intent) { } + public boolean onOverrideUrlLoading(String url) { + return false; + } + /** * Send generic JavaScript statement back to JavaScript. * success(...) and error(...) should be used instead where possible. diff --git a/framework/src/com/phonegap/api/PluginManager.java b/framework/src/com/phonegap/api/PluginManager.java index 90de9778..04080072 100755 --- a/framework/src/com/phonegap/api/PluginManager.java +++ b/framework/src/com/phonegap/api/PluginManager.java @@ -9,6 +9,7 @@ package com.phonegap.api; import java.io.IOException; import java.util.HashMap; +import java.util.Iterator; import java.util.Map.Entry; import org.json.JSONArray; @@ -17,6 +18,7 @@ import org.xmlpull.v1.XmlPullParserException; import android.content.Intent; import android.content.res.XmlResourceParser; +import android.util.Log; import android.webkit.WebView; /** @@ -25,7 +27,7 @@ import android.webkit.WebView; * Calling native plugin code can be done by calling PluginManager.exec(...) * from JavaScript. */ -public final class PluginManager { +public final class PluginManager { private HashMap plugins = new HashMap(); private HashMap services = new HashMap(); @@ -33,6 +35,10 @@ public final class PluginManager { private final PhonegapActivity ctx; 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 urlMap = new HashMap(); + /** * Constructor. * @@ -53,14 +59,17 @@ public final class PluginManager { if (id == 0) { pluginConfigurationMissing(); } XmlResourceParser xml = ctx.getResources().getXml(id); int eventType = -1; + String pluginClass = "", pluginName = ""; while (eventType != XmlResourceParser.END_DOCUMENT) { if (eventType == XmlResourceParser.START_TAG) { String strNode = xml.getName(); if (strNode.equals("plugin")) { - String name = xml.getAttributeValue(null, "name"); - String value = xml.getAttributeValue(null, "value"); + pluginClass = xml.getAttributeValue(null, "value"); + pluginName = xml.getAttributeValue(null, "name"); //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 { @@ -101,14 +110,9 @@ public final class PluginManager { boolean runAsync = async; try { final JSONArray args = new JSONArray(jsonArgs); - String clazz = this.services.get(service); - Class c = null; - if (clazz != null) { - c = getClassByName(clazz); - } - if (isPhoneGapPlugin(c)) { - final IPlugin plugin = this.addPlugin(clazz, c); - final PhonegapActivity ctx = this.ctx; + final IPlugin plugin = this.getPlugin(service); + final PhonegapActivity ctx = this.ctx; + if (plugin != null) { runAsync = async && !plugin.isSynch(action); if (runAsync) { // 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) { System.out.println("ERROR: "+e.toString()); cr = new PluginResult(PluginResult.Status.JSON_EXCEPTION); @@ -175,7 +177,11 @@ public final class PluginManager { */ @SuppressWarnings("unchecked") 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 */ @SuppressWarnings("unchecked") - private IPlugin addPlugin(String className, Class clazz) { - if (this.plugins.containsKey(className)) { - return this.getPlugin(className); - } - try { - IPlugin plugin = (IPlugin)clazz.newInstance(); - this.plugins.put(className, plugin); - plugin.setContext(this.ctx); - plugin.setView(this.app); - return plugin; - } - catch (Exception e) { + private IPlugin addPlugin(String pluginName, String className) { + try { + Class c = getClassByName(className); + if (isPhoneGapPlugin(c)) { + IPlugin plugin = (IPlugin)c.newInstance(); + this.plugins.put(className, plugin); + plugin.setContext(this.ctx); + plugin.setView(this.app); + return plugin; + } + } catch (Exception e) { e.printStackTrace(); System.out.println("Error adding plugin "+className+"."); } @@ -224,12 +229,18 @@ public final class PluginManager { /** * Get the loaded plugin. * + * If the plugin is not already loaded then load it. + * * @param className The class of the loaded plugin. * @return */ - private IPlugin getPlugin(String className) { - IPlugin plugin = this.plugins.get(className); - return plugin; + private IPlugin getPlugin(String pluginName) { + String className = this.services.get(pluginName); + 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> it = this.urlMap.entrySet().iterator(); + while (it.hasNext()) { + HashMap.Entry pairs = it.next(); + if (url.startsWith(pairs.getKey())) { + return this.getPlugin(pairs.getValue()).onOverrideUrlLoading(url); + } + } + return false; + } + private void pluginConfigurationMissing() { System.err.println("====================================================================================="); System.err.println("ERROR: plugin.xml is missing. Add res/xml/plugins.xml to your project.");