标签:android html5 webview 插件 plugin
上一篇文章说到,当利用WebViewClient或者WebChromeClient来处理由html页面传过来的请求的时候,都会将对应的服务名称,操作方法和对应的参数数据传给一个叫PluginManager的类。
PluginManager类的作用是什么?
大家知道,当利用Android原生环境的功能,比如照像机,比如相册等,这些功能都是很分散的,说不清楚什么时候是需要这些功能,什么时候是不需要这些功能的,所以我们希望能够像插件一样,需要的时候就加载进来,不需要的时候不去理他,而PluginManager类就是一个这样的管理类。
它主要负责几件事情:
1)进入HTML页面的时候,去加载我们定义好的控件。
mPluginManager = new PluginManager(this); mPluginManager.loadPlugin();
那么PluginManager怎么知道本个应用要加载多少plugin来去响应由Html页面来的请求呢?
我们是通过一个叫plugin.xml配置文件来定义的。
<plugins> <plugin name="App" class="com.lms.xxx.bridge.plugin.App" /> <plugin name="Toast" class="com.lms.xxx.plugin.Toast" /> <plugin name="Dialog" class="com.lms.xxx.bridge.plugin.Dialog" /> <plugin name="User" class="com.lms.xxx.bridge.plugin.User" /> </plugins>
可以联想到,Toast和Dialog都是Android原生环境下的显示窗口,我们虽然用html页面来实现界面,但是为了保持整个应用的一致性,我们就会用到原生环境中的Toast或者我们自定义的对话框等控件。
需要用到什么,就在这里定义什么。
我们再来看一下loadPlugin方法:
public void loadPlugin() { int identifier = context.getResources().getIdentifier("plugins", "xml", context.getPackageName()); if (identifier == 0) { pluginConfigurationMissing(); } XmlResourceParser xml = context.getResources().getXml(identifier); try { int eventType = -1; while ((eventType = xml.next()) != XmlResourceParser.END_DOCUMENT) { if (eventType == XmlResourceParser.START_TAG) { String name = xml.getName(); if ("plugin".equals(name)) { String pluginName = xml.getAttributeValue(null, "name"); String className = xml.getAttributeValue(null, "class"); configs.put(pluginName, className); } } } } catch (XmlPullParserException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
private HashMap<String, String> configs = new HashMap<String, String>(); private HashMap<String, IPlugin> plugins = new HashMap<String, IPlugin>();
在这里,在plugins.xml文件中定义的name属性就是这个服务名称。
2)根据请求的服务名称和操作方法等,为这个请求找到对应的Plugin去处理。String execResult = mPluginManager.exec("service", "action", args);
public String exec(String service, String action, JSONObject args) throws PluginNotFoundException { IPlugin plugin = getPlugin(service); ... PluginResult result = plugin.exec(action, args); ... }
在上面的逻辑可以看到,PluginManager会利用getPlugin方法拿出对应的服务,如下:
public IPlugin getPlugin(String pluginName) throws PluginNotFoundException { String className = configs.get(pluginName); if(className==null){ throw new PluginNotFoundException(pluginName); } if (plugins.containsKey(className)) { return plugins.get(className); } else { return addPlugin(className); } }
IPlugin是一个接口,其定义如下:
public interface IPlugin { public static final String SERVICE = "service"; public static final String ACTION = "action"; public static final String ARGS = "args"; /** * 执行请求 * * @param action * 功能 * @param args * 参数 * @return pluginResult 结果 */ public PluginResult exec(String action, JSONObject args)throws ActionNotFoundException;
public abstract class Plugin implements IPlugin { protected DroidHtml5 context;
比如,我们拿上面的Toast类,其就会继承Plugin,然后根据对应的服务去实现对应的逻辑,调用原生环境的Toast。
public class Toast extends Plugin { @Override public PluginResult exec(String action, JSONObject args) throws ActionNotFoundException { if ("makeTextShort".equals(action)) { return makeTextShort(args); }else if ("makeTextLong".equals(action)) { return makeTextLong(args); } else { throw new ActionNotFoundException("Toast", action); } } private PluginResult makeTextShort(JSONObject args) { try { String text = args.getString("text"); android.widget.Toast.makeText(context, text, android.widget.Toast.LENGTH_SHORT).show(); } catch (JSONException e) { e.printStackTrace(); return PluginResult.newErrorPluginResult(e.getMessage()); } return PluginResult.newEmptyPluginResult(); } private PluginResult makeTextLong(JSONObject args) { try { String text = args.getString("text"); android.widget.Toast.makeText(context, text, android.widget.Toast.LENGTH_LONG).show(); } catch (JSONException e) { e.printStackTrace(); return PluginResult.newErrorPluginResult(e.getMessage()); } return PluginResult.newEmptyPluginResult(); } }
3)从Html页面来调用。
我们在Android原生环境定义了这么一套Plugin机制,那么在Html里面,也可以有这样的一套接口方法,来对应不同的Plugin,所以我们在javascript中也会定义各种各样的对象。
比如上面描述的Toast插件,我们可以在javascript中定义一个对应的对象,如下:
var Toast = { makeTextShort : function(text) { return exec("Toast", "makeTextShort", JSON.stringify(text)); }, makeTextLong : function(text) { return exec("Toast", "makeTextLong", JSON.stringify(text)); } }
而在这里,我们就会将服务名(Toast),操作方法(makeTextShort),还有显示的内容(JSON.stringfy(text))等通过exec方法,然后利用WebChromeClient的onJsPrompt方法,将命令传递给PluginManager,由PluginManager来处理。
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { System.out.println("onJsPrompt:defaultValue:" + defaultValue + "|" + url + "," + message); JSONObject args = null; JSONObject head = null; try { // message:{"service" : "XX", "action" : "xx"} head = new JSONObject(message); if (defaultValue != null && !defaultValue.equals("")) { try { args = new JSONObject(defaultValue); } catch (Exception e) { e.printStackTrace(); } } String execResult = mPluginManager.exec(head.getString(IPlugin.SERVICE), head.getString(IPlugin.ACTION), args); result.confirm(execResult); return true;
var Toast = { makeTextShort : function(text) { return exec("Toast", "makeTextShort", JSON.stringify(text)); }, makeTextLong : function(text) { return exec("Toast", "makeTextLong", JSON.stringify(text)); } } var Dialog = { ... } var AndroidHtml5 = { .... /* * exec_asyn调用的方法 @params {JSONObject} cmd 服务名和动作命令 @params {String} args 参数 */ callNative : function(cmd, args, success, fail) { .... }, <span style="white-space:pre"> </span>... callBackJs : function(result,key) { ... } }; /* * Html5与Android同步交互接口 */ var exec = function(service, action, args) { var json = { "service" : service, "action" : action }; var result_str = prompt(JSON.stringify(json), args); var result; try { result = JSON.parse(result_str); } catch (e) { console.error(e.message); } ... } /* * Html5与Android异步交互接口 */ var exec_asyn = function(service, action, args, success, fail) { var json = { "service" : service, "action" : action }; var result = AndroidHtml5.callNative(json, args, success, fail); }
Android与WebView的插件管理机制,布布扣,bubuko.com
标签:android html5 webview 插件 plugin
原文地址:http://blog.csdn.net/linmiansheng/article/details/38383759