mirror of
https://github.com/apache/cordova-android.git
synced 2025-02-22 00:32:55 +08:00
[CB-352] Support initializing DroidGap with existing WebView, WebViewClient and webViewChrome.
[CB-353] Create PluginEntry object to use by PluginManager.
This commit is contained in:
parent
04b3e4d847
commit
7e70d76232
@ -64,7 +64,7 @@ public class CordovaWebViewClient extends WebViewClient {
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
|
||||
// First give any plugins the chance to handle the url themselves
|
||||
if (this.ctx.pluginManager.onOverrideUrlLoading(url)) {
|
||||
if ((this.ctx.pluginManager != null) && this.ctx.pluginManager.onOverrideUrlLoading(url)) {
|
||||
}
|
||||
|
||||
// If dialing phone (tel:5551212)
|
||||
|
@ -56,6 +56,7 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebSettings.LayoutAlgorithm;
|
||||
import android.webkit.WebView;
|
||||
@ -345,13 +346,24 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and initialize web container.
|
||||
* Create and initialize web container with default web view objects.
|
||||
*/
|
||||
public void init() {
|
||||
this.init(new WebView(DroidGap.this), new CordovaWebViewClient(this), new CordovaChromeClient(DroidGap.this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize web container with web view objects.
|
||||
*
|
||||
* @param webView
|
||||
* @param webViewClient
|
||||
* @param webChromeClient
|
||||
*/
|
||||
public void init(WebView webView, WebViewClient webViewClient, WebChromeClient webChromeClient) {
|
||||
LOG.d(TAG, "DroidGap.init()");
|
||||
|
||||
// Create web container
|
||||
this.appView = new WebView(DroidGap.this);
|
||||
// Set up web container
|
||||
this.appView = webView;
|
||||
this.appView.setId(100);
|
||||
|
||||
this.appView.setLayoutParams(new LinearLayout.LayoutParams(
|
||||
@ -359,8 +371,8 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
ViewGroup.LayoutParams.FILL_PARENT,
|
||||
1.0F));
|
||||
|
||||
this.appView.setWebChromeClient(new CordovaChromeClient(DroidGap.this));
|
||||
this.setWebViewClient(this.appView, new CordovaWebViewClient(this));
|
||||
this.appView.setWebChromeClient(webChromeClient);
|
||||
this.setWebViewClient(this.appView, webViewClient);
|
||||
|
||||
this.appView.setInitialScale(0);
|
||||
this.appView.setVerticalScrollBarEnabled(false);
|
||||
@ -393,6 +405,9 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
|
||||
// Clear cancel flag
|
||||
this.cancelLoadUrl = false;
|
||||
|
||||
// Create plugin manager
|
||||
this.pluginManager = new PluginManager(this.appView, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -498,12 +513,7 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
else {
|
||||
me.callbackServer.reinit(url);
|
||||
}
|
||||
if (me.pluginManager == null) {
|
||||
me.pluginManager = new PluginManager(me.appView, me);
|
||||
}
|
||||
else {
|
||||
me.pluginManager.reinit();
|
||||
}
|
||||
me.pluginManager.init();
|
||||
|
||||
// If loadingDialog property, then show the App loading dialog for first page of app
|
||||
String loading = null;
|
||||
@ -834,7 +844,9 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
this.appView.loadUrl("javascript:try{cordova.require('cordova/channel').onPause.fire();}catch(e){console.log('exception firing pause event from native');};");
|
||||
|
||||
// Forward to plugins
|
||||
if (this.pluginManager != null) {
|
||||
this.pluginManager.onPause(this.keepRunning);
|
||||
}
|
||||
|
||||
// If app doesn't want to run in background
|
||||
if (!this.keepRunning) {
|
||||
@ -852,8 +864,10 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
super.onNewIntent(intent);
|
||||
|
||||
//Forward to plugins
|
||||
if (this.pluginManager != null) {
|
||||
this.pluginManager.onNewIntent(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
@ -875,7 +889,9 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
this.appView.loadUrl("javascript:try{cordova.require('cordova/channel').onResume.fire();}catch(e){console.log('exception firing resume event from native');};");
|
||||
|
||||
// Forward to plugins
|
||||
if (this.pluginManager != null) {
|
||||
this.pluginManager.onResume(this.keepRunning || this.activityResultKeepRunning);
|
||||
}
|
||||
|
||||
// If app doesn't want to run in background
|
||||
if (!this.keepRunning || this.activityResultKeepRunning) {
|
||||
@ -942,8 +958,10 @@ public class DroidGap extends Activity implements CordovaInterface {
|
||||
*/
|
||||
@Deprecated
|
||||
public void addService(String serviceType, String className) {
|
||||
if (this.pluginManager != null) {
|
||||
this.pluginManager.addService(serviceType, className);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send JavaScript statement back to JavaScript.
|
||||
|
119
framework/src/org/apache/cordova/api/PluginEntry.java
Executable file
119
framework/src/org/apache/cordova/api/PluginEntry.java
Executable file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package org.apache.cordova.api;
|
||||
|
||||
import android.webkit.WebView;
|
||||
|
||||
/**
|
||||
* This class represents a service entry object.
|
||||
*/
|
||||
public class PluginEntry {
|
||||
|
||||
/**
|
||||
* The name of the service that this plugin implements
|
||||
*/
|
||||
public String service = "";
|
||||
|
||||
/**
|
||||
* The plugin class name that implements the service.
|
||||
*/
|
||||
public String pluginClass = "";
|
||||
|
||||
/**
|
||||
* The plugin object.
|
||||
* Plugin objects are only created when they are called from JavaScript. (see PluginManager.exec)
|
||||
* The exception is if the onload flag is set, then they are created when PluginManager is initialized.
|
||||
*/
|
||||
public IPlugin plugin = null;
|
||||
|
||||
/**
|
||||
* Flag that indicates the plugin object should be created when PluginManager is initialized.
|
||||
*/
|
||||
public boolean onload = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param service The name of the service
|
||||
* @param pluginClass The plugin class name
|
||||
* @param onload Create plugin object when HTML page is loaded
|
||||
*/
|
||||
public PluginEntry(String service, String pluginClass, boolean onload) {
|
||||
this.service = service;
|
||||
this.pluginClass = pluginClass;
|
||||
this.onload = onload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create plugin object.
|
||||
* If plugin is already created, then just return it.
|
||||
*
|
||||
* @return The plugin object
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public IPlugin createPlugin(WebView webView, CordovaInterface ctx) {
|
||||
if (this.plugin != null) {
|
||||
return this.plugin;
|
||||
}
|
||||
try {
|
||||
Class c = getClassByName(this.pluginClass);
|
||||
if (isCordovaPlugin(c)) {
|
||||
this.plugin = (IPlugin) c.newInstance();
|
||||
this.plugin.setContext(ctx);
|
||||
this.plugin.setView(webView);
|
||||
return plugin;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("Error adding plugin " + this.pluginClass + ".");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class.
|
||||
*
|
||||
* @param clazz
|
||||
* @return
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class getClassByName(final String clazz) throws ClassNotFoundException {
|
||||
Class c = null;
|
||||
if (clazz != null) {
|
||||
c = Class.forName(clazz);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the interfaces that a class implements and see if it implements the
|
||||
* org.apache.cordova.api.Plugin interface.
|
||||
*
|
||||
* @param c The class to check the interfaces of.
|
||||
* @return Boolean indicating if the class implements org.apache.cordova.api.Plugin
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean isCordovaPlugin(Class c) {
|
||||
if (c != null) {
|
||||
return org.apache.cordova.api.Plugin.class.isAssignableFrom(c) || org.apache.cordova.api.IPlugin.class.isAssignableFrom(c);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
*/
|
||||
package org.apache.cordova.api;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -29,7 +29,6 @@ import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.util.Log;
|
||||
import android.webkit.WebView;
|
||||
|
||||
/**
|
||||
@ -39,16 +38,20 @@ import android.webkit.WebView;
|
||||
* from JavaScript.
|
||||
*/
|
||||
public class PluginManager {
|
||||
private static String TAG = "PluginManager";
|
||||
|
||||
private HashMap<String, IPlugin> plugins = new HashMap<String,IPlugin>();
|
||||
private HashMap<String, String> services = new HashMap<String,String>();
|
||||
// List of service entries
|
||||
private final HashMap<String, PluginEntry> entries = new HashMap<String, PluginEntry>();
|
||||
|
||||
private final CordovaInterface ctx;
|
||||
private final WebView app;
|
||||
|
||||
// Flag to track first time through
|
||||
private boolean firstRun;
|
||||
|
||||
// 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>();
|
||||
protected HashMap<String, String> urlMap = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@ -59,18 +62,30 @@ public class PluginManager {
|
||||
public PluginManager(WebView app, CordovaInterface ctx) {
|
||||
this.ctx = ctx;
|
||||
this.app = app;
|
||||
this.loadPlugins();
|
||||
this.firstRun = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-init when loading a new HTML page into webview.
|
||||
* Init when loading a new HTML page into webview.
|
||||
*/
|
||||
public void reinit() {
|
||||
public void init() {
|
||||
LOG.d(TAG, "init()");
|
||||
|
||||
// Stop plugins on current HTML page and discard
|
||||
// If first time, then load plugins from plugins.xml file
|
||||
if (firstRun) {
|
||||
this.loadPlugins();
|
||||
firstRun = false;
|
||||
}
|
||||
|
||||
// Stop plugins on current HTML page and discard plugin objects
|
||||
else {
|
||||
this.onPause(false);
|
||||
this.onDestroy();
|
||||
this.plugins = new HashMap<String, IPlugin>();
|
||||
this.clearPluginObjects();
|
||||
}
|
||||
|
||||
// Start up all plugins that have onload specified
|
||||
this.startupPlugins();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,25 +93,26 @@ public class PluginManager {
|
||||
*/
|
||||
public void loadPlugins() {
|
||||
int id = ctx.getResources().getIdentifier("plugins", "xml", ctx.getPackageName());
|
||||
if (id == 0) { pluginConfigurationMissing(); }
|
||||
if (id == 0) {
|
||||
pluginConfigurationMissing();
|
||||
}
|
||||
XmlResourceParser xml = ctx.getResources().getXml(id);
|
||||
int eventType = -1;
|
||||
String pluginClass = "", pluginName = "";
|
||||
String service = "", pluginClass = "";
|
||||
boolean onload = false;
|
||||
PluginEntry entry = null;
|
||||
while (eventType != XmlResourceParser.END_DOCUMENT) {
|
||||
if (eventType == XmlResourceParser.START_TAG) {
|
||||
String strNode = xml.getName();
|
||||
if (strNode.equals("plugin")) {
|
||||
service = xml.getAttributeValue(null, "name");
|
||||
pluginClass = xml.getAttributeValue(null, "value");
|
||||
pluginName = xml.getAttributeValue(null, "name");
|
||||
//System.out.println("Plugin: "+name+" => "+value);
|
||||
this.addService(pluginName, pluginClass);
|
||||
|
||||
// Create plugin at load time if attribute "onload"
|
||||
if ("true".equals(xml.getAttributeValue(null, "onload"))) {
|
||||
this.getPlugin(pluginName);
|
||||
}
|
||||
// System.out.println("Plugin: "+name+" => "+value);
|
||||
onload = "true".equals(xml.getAttributeValue(null, "onload"));
|
||||
entry = new PluginEntry(service, pluginClass, onload);
|
||||
this.addService(entry);
|
||||
} else if (strNode.equals("url-filter")) {
|
||||
this.urlMap.put(xml.getAttributeValue(null, "value"), pluginName);
|
||||
this.urlMap.put(xml.getAttributeValue(null, "value"), service);
|
||||
}
|
||||
}
|
||||
try {
|
||||
@ -109,6 +125,26 @@ public class PluginManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all plugin objects.
|
||||
*/
|
||||
public void clearPluginObjects() {
|
||||
for (PluginEntry entry : this.entries.values()) {
|
||||
entry.plugin = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create plugins objects that have onload set.
|
||||
*/
|
||||
public void startupPlugins() {
|
||||
for (PluginEntry entry : this.entries.values()) {
|
||||
if (entry.onload) {
|
||||
entry.createPlugin(this.app, this.ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives a request for execution and fulfills it by finding the appropriate
|
||||
* Java class and calling it's execute method.
|
||||
@ -182,7 +218,7 @@ public class PluginManager {
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
System.out.println("ERROR: "+e.toString());
|
||||
System.out.println("ERROR: " + e.toString());
|
||||
cr = new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
||||
}
|
||||
// if async we have already returned at this point unless there was an error...
|
||||
@ -192,93 +228,49 @@ public class PluginManager {
|
||||
}
|
||||
ctx.sendJavascript(cr.toErrorCallbackString(callbackId));
|
||||
}
|
||||
return ( cr != null ? cr.getJSONString() : "{ status: 0, message: 'all good' }" );
|
||||
return (cr != null ? cr.getJSONString() : "{ status: 0, message: 'all good' }");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class.
|
||||
* Get the plugin object that implements the service.
|
||||
* If the plugin object does not already exist, then create it.
|
||||
* If the service doesn't exist, then return null.
|
||||
*
|
||||
* @param clazz
|
||||
* @return
|
||||
* @throws ClassNotFoundException
|
||||
* @param service The name of the service.
|
||||
* @return IPlugin or null
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class getClassByName(final String clazz) throws ClassNotFoundException {
|
||||
Class c = null;
|
||||
if (clazz != null) {
|
||||
c = Class.forName(clazz);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the interfaces that a class implements and see if it implements the
|
||||
* org.apache.cordova.api.Plugin interface.
|
||||
*
|
||||
* @param c The class to check the interfaces of.
|
||||
* @return Boolean indicating if the class implements org.apache.cordova.api.Plugin
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean isCordovaPlugin(Class c) {
|
||||
if (c != null) {
|
||||
return org.apache.cordova.api.Plugin.class.isAssignableFrom(c) || org.apache.cordova.api.IPlugin.class.isAssignableFrom(c);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add plugin to be loaded and cached. This creates an instance of the plugin.
|
||||
* If plugin is already created, then just return it.
|
||||
*
|
||||
* @param className The class to load
|
||||
* @param clazz The class object (must be a class object of the className)
|
||||
* @param callbackId The callback id to use when calling back into JavaScript
|
||||
* @return The plugin
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private IPlugin addPlugin(String pluginName, String className) {
|
||||
try {
|
||||
Class c = getClassByName(className);
|
||||
if (isCordovaPlugin(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+".");
|
||||
}
|
||||
private IPlugin getPlugin(String service) {
|
||||
PluginEntry entry = entries.get(service);
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 pluginName) {
|
||||
String className = this.services.get(pluginName);
|
||||
if (this.plugins.containsKey(className)) {
|
||||
return this.plugins.get(className);
|
||||
} else {
|
||||
return this.addPlugin(pluginName, className);
|
||||
IPlugin plugin = entry.plugin;
|
||||
if (plugin == null) {
|
||||
plugin = entry.createPlugin(this.app, this.ctx);
|
||||
}
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a class that implements a service.
|
||||
* This does not create the class instance. It just maps service name to class name.
|
||||
* Add a plugin class that implements a service to the service entry table.
|
||||
* This does not create the plugin object instance.
|
||||
*
|
||||
* @param serviceType
|
||||
* @param className
|
||||
* @param service The service name
|
||||
* @param className The plugin class name
|
||||
*/
|
||||
public void addService(String serviceType, String className) {
|
||||
this.services.put(serviceType, className);
|
||||
public void addService(String service, String className) {
|
||||
PluginEntry entry = new PluginEntry(service, className, false);
|
||||
this.addService(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a plugin class that implements a service to the service entry table.
|
||||
* This does not create the plugin object instance.
|
||||
*
|
||||
* @param entry The plugin entry
|
||||
*/
|
||||
public void addService(PluginEntry entry) {
|
||||
this.entries.put(entry.service, entry);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -287,8 +279,10 @@ public class PluginManager {
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
public void onPause(boolean multitasking) {
|
||||
for (IPlugin plugin : this.plugins.values()) {
|
||||
plugin.onPause(multitasking);
|
||||
for (PluginEntry entry : this.entries.values()) {
|
||||
if (entry.plugin != null) {
|
||||
entry.plugin.onPause(multitasking);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,8 +292,10 @@ public class PluginManager {
|
||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
||||
*/
|
||||
public void onResume(boolean multitasking) {
|
||||
for (IPlugin plugin : this.plugins.values()) {
|
||||
plugin.onResume(multitasking);
|
||||
for (PluginEntry entry : this.entries.values()) {
|
||||
if (entry.plugin != null) {
|
||||
entry.plugin.onResume(multitasking);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,8 +303,10 @@ public class PluginManager {
|
||||
* The final call you receive before your activity is destroyed.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
for (IPlugin plugin : this.plugins.values()) {
|
||||
plugin.onDestroy();
|
||||
for (PluginEntry entry : this.entries.values()) {
|
||||
if (entry.plugin != null) {
|
||||
entry.plugin.onDestroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -319,8 +317,10 @@ public class PluginManager {
|
||||
* @param data The message data
|
||||
*/
|
||||
public void postMessage(String id, Object data) {
|
||||
for (IPlugin plugin : this.plugins.values()) {
|
||||
plugin.onMessage(id, data);
|
||||
for (PluginEntry entry : this.entries.values()) {
|
||||
if (entry.plugin != null) {
|
||||
entry.plugin.onMessage(id, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,8 +328,10 @@ public class PluginManager {
|
||||
* Called when the activity receives a new intent.
|
||||
*/
|
||||
public void onNewIntent(Intent intent) {
|
||||
for (IPlugin plugin : this.plugins.values()) {
|
||||
plugin.onNewIntent(intent);
|
||||
for (PluginEntry entry : this.entries.values()) {
|
||||
if (entry.plugin != null) {
|
||||
entry.plugin.onNewIntent(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user