上一篇文章说到,当利用WebViewClient或者WebChromeClient来处理由html页面传过来的请求的时候,都会将相应的服务名称,操作方法和相应的參数数据传给一个叫PluginManager的类。

PluginManager类的作用是什么?

大家知道,当利用Android原生环境的功能。比方照像机。比方相冊等,这些功能都是非常分散的,说不清楚什么时候是须要这些功能,什么时候是不须要这些功能的,所以我们希望可以像插件一样。须要的时候就载入进来,不须要的时候不去理他,而PluginManager类就是一个这种管理类。

它主要负责几件事情:

1)进入HTML页面的时候,去载入我们定义好的控件。

  1. mPluginManager = new PluginManager(this);
  2. mPluginManager.loadPlugin();

那么PluginManager怎么知道本个应用要载入多少plugin来去响应由Html页面来的请求呢?

我们是通过一个叫plugin.xml配置文件来定义的。

  1. <plugins>
  2. <plugin name="App" class="com.lms.xxx.bridge.plugin.App" />
  3. <plugin name="Toast" class="com.lms.xxx.plugin.Toast" />
  4. <plugin name="Dialog" class="com.lms.xxx.bridge.plugin.Dialog" />
  5. <plugin name="User" class="com.lms.xxx.bridge.plugin.User" />
  6. </plugins>

比方在上面的配置文件里,我们会载入App, Toast, Dialog 和 User 这几个plugin。

能够联想到,Toast和Dialog都是Android原生环境下的显示窗体,我们尽管用html页面来实现界面,可是为了保持整个应用的一致性,我们就会用到原生环境中的Toast或者我们自己定义的对话框等控件。

须要用到什么,就在这里定义什么。

我们再来看一下loadPlugin方法:

  1. public void loadPlugin() {
  2. int identifier = context.getResources().getIdentifier("plugins", "xml",
  3. context.getPackageName());
  4. if (identifier == 0) {
  5. pluginConfigurationMissing();
  6. }
  7.  
  8. XmlResourceParser xml = context.getResources().getXml(identifier);
  9. try {
  10.  
  11. int eventType = -1;
  12. while ((eventType = xml.next()) != XmlResourceParser.END_DOCUMENT) {
  13. if (eventType == XmlResourceParser.START_TAG) {
  14. String name = xml.getName();
  15. if ("plugin".equals(name)) {
  16. String pluginName = xml.getAttributeValue(null, "name");
  17. String className = xml.getAttributeValue(null, "class");
  18. configs.put(pluginName, className);
  19. }
  20.  
  21. }
  22. }
  23.  
  24. } catch (XmlPullParserException e) {
  25. e.printStackTrace();
  26. } catch (IOException e) {
  27. e.printStackTrace();
  28. }
  29. }

能够看到,这就是解析plugins.xml文件。然后将相应的插件类名给放到configs中,configs定义例如以下:

  1. private HashMap<String, String> configs = new HashMap<String, String>();
  2. private HashMap<String, IPlugin> plugins = new HashMap<String, IPlugin>();

通过loadPlugin方法,我们就将在plugins.xml中定义好的插件,给载入到configs中去了。configs里存放的仅仅是类名。而plugins存放的才是实现,只是我们这里不须要关心这个。

在这里。在plugins.xml文件里定义的name属性就是这个服务名称。

2)依据请求的服务名称和操作方法等,为这个请求找到相应的Plugin去处理。

  1. String execResult = mPluginManager.exec("service", "action", args);

看一下exec方法,

  1. public String exec(String service, String action, JSONObject args) throws PluginNotFoundException {
  2. IPlugin plugin = getPlugin(service);
  3. ...
  4. PluginResult result = plugin.exec(action, args);
  5. ...
  6. }

在上面的逻辑能够看到。PluginManager会利用getPlugin方法拿出相应的服务,例如以下:

  1. public IPlugin getPlugin(String pluginName) throws PluginNotFoundException {
  2. String className = configs.get(pluginName);
  3. if(className==null){
  4. throw new PluginNotFoundException(pluginName);
  5. }
  6. if (plugins.containsKey(className)) {
  7. return plugins.get(className);
  8. } else {
  9. return addPlugin(className);
  10. }
  11. }

这样,我们就拿到了一个实现了IPlugin接口中的Plugin实现类。

IPlugin是一个接口,其定义例如以下:

  1. public interface IPlugin {
  2.  
  3. public static final String SERVICE = "service";
  4. public static final String ACTION = "action";
  5. public static final String ARGS = "args";
  6.  
  7. /**
  8. * 运行请求
  9. *
  10. * @param action
  11. * 功能
  12. * @param args
  13. * 參数
  14. * @return pluginResult 结果
  15. */
  16. public PluginResult exec(String action, JSONObject args)throws ActionNotFoundException;

里面定义的最重要的方法就是exec方法。每个我们自己定义的插件都要实现这个接口,只是在这里。我们先实现了一个抽象基类Plugin。在里面实现一些公共的逻辑,而对于详细的实现,再由Plugin的子类去继承。

  1. public abstract class Plugin implements IPlugin {
  2.  
  3. protected DroidHtml5 context;

比方,我们拿上面的Toast类。其就会继承Plugin。然后依据相应的服务去实现相应的逻辑,调用原生环境的Toast。

  1. public class Toast extends Plugin {
  2.  
  3. @Override
  4. public PluginResult exec(String action, JSONObject args)
  5. throws ActionNotFoundException {
  6. if ("makeTextShort".equals(action)) {
  7. return makeTextShort(args);
  8. }else if ("makeTextLong".equals(action)) {
  9. return makeTextLong(args);
  10. } else {
  11. throw new ActionNotFoundException("Toast", action);
  12. }
  13.  
  14. }
  15.  
  16. private PluginResult makeTextShort(JSONObject args) {
  17.  
  18. try {
  19. String text = args.getString("text");
  20. android.widget.Toast.makeText(context, text, android.widget.Toast.LENGTH_SHORT).show();
  21. } catch (JSONException e) {
  22. e.printStackTrace();
  23. return PluginResult.newErrorPluginResult(e.getMessage());
  24. }
  25. return PluginResult.newEmptyPluginResult();
  26. }
  27.  
  28. private PluginResult makeTextLong(JSONObject args) {
  29.  
  30. try {
  31. String text = args.getString("text");
  32. android.widget.Toast.makeText(context, text, android.widget.Toast.LENGTH_LONG).show();
  33. } catch (JSONException e) {
  34. e.printStackTrace();
  35. return PluginResult.newErrorPluginResult(e.getMessage());
  36. }
  37. return PluginResult.newEmptyPluginResult();
  38. }
  39.  
  40. }

从上面的代码。相信大家非常easy就行理解了Plugin机制了。

3)从Html页面来调用。

我们在Android原生环境定义了这么一套Plugin机制。那么在Html里面,也能够有这种一套接口方法,来相应不同的Plugin,所以我们在javascript中也会定义各种各样的对象。

比方上面描写叙述的Toast插件,我们能够在javascript中定义一个相应的对象。例如以下:

  1. var Toast = {
  2.  
  3. makeTextShort : function(text) {
  4.  
  5. return exec("Toast", "makeTextShort", JSON.stringify(text));
  6. },
  7. makeTextLong : function(text) {
  8.  
  9. return exec("Toast", "makeTextLong", JSON.stringify(text));
  10. }
  11.  
  12. }

这里,我们能够看到Toast的makeTextShort方法,会调用上一篇文章中讲到的exec方法,由于弹窗显示这样的东西肯定是同步的,不会说做了一会流程,突然间就跑出一个框来。告诉我,你刚才做错了。对吧。

而在这里,我们就会将服务名(Toast)。操作方法(makeTextShort)。还有显示的内容(JSON.stringfy(text))等通过exec方法,然后利用WebChromeClient的onJsPrompt方法。将命令传递给PluginManager,由PluginManager来处理。

  1. public boolean onJsPrompt(WebView view, String url, String message,
  2. String defaultValue, JsPromptResult result) {
  3.  
  4. System.out.println("onJsPrompt:defaultValue:" + defaultValue + "|" + url + "," + message);
  5. JSONObject args = null;
  6. JSONObject head = null;
  7. try {
  8. // message:{"service" : "XX", "action" : "xx"}
  9. head = new JSONObject(message);
  10. if (defaultValue != null && !defaultValue.equals("")) {
  11. try {
  12. args = new JSONObject(defaultValue);
  13. } catch (Exception e) {
  14. e.printStackTrace();
  15. }
  16. }
  17.  
  18. String execResult = mPluginManager.exec(head.getString(IPlugin.SERVICE),
  19. head.getString(IPlugin.ACTION), args);
  20.  
  21. result.confirm(execResult);
  22. return true;

4)我们会把这些定义的插件对象,还有同步(exec),异步运行(exec_sync)的方法都写到一个javascript文件里,方便统一管理,所以一般这个文件内容就会像以下这样:

  1. var Toast = {
  2. makeTextShort : function(text) {
  3.  
  4. return exec("Toast", "makeTextShort", JSON.stringify(text));
  5. },
  6. makeTextLong : function(text) {
  7.  
  8. return exec("Toast", "makeTextLong", JSON.stringify(text));
  9. }
  10. }
  11. var Dialog = {
  12. ...
  13. }
  14. var AndroidHtml5 = {
  15. ....
  16. /*
  17. * exec_asyn调用的方法 @params {JSONObject} cmd 服务名和动作命令 @params {String} args 參数
  18. */
  19. callNative : function(cmd, args, success, fail) {
  20. ....
  21. },
  22. <span style="white-space:pre"> </span>...
  23. callBackJs : function(result,key) {
  24. ...
  25. }
  26. };
  27.  
  28. /*
  29. * Html5与Android同步交互接口
  30. */
  31. var exec = function(service, action, args) {
  32. var json = {
  33. "service" : service,
  34. "action" : action
  35. };
  36. var result_str = prompt(JSON.stringify(json), args);
  37.  
  38. var result;
  39. try {
  40. result = JSON.parse(result_str);
  41. } catch (e) {
  42. console.error(e.message);
  43. }
  44. ...
  45. }
  46. /*
  47. * Html5与Android异步交互接口
  48. */
  49. var exec_asyn = function(service, action, args, success, fail) {
  50. var json = {
  51. "service" : service,
  52. "action" : action
  53. };
  54.  
  55. var result = AndroidHtml5.callNative(json, args, success, fail);
  56.  
  57. }

结束。

Android与WebView的插件管理机制的更多相关文章

  1. 正确认识Android的内存管理机制,合理关闭进程 (一)

    随着大家收货后会有很多乐粉晒内存,为啦方便大家,在网上搜集了一些相关Andriod管理的相关机制合理管理内存,整理下发个贴. 首先要知道Android系统是基于Linux 2.6内核开发的开源操作系统 ...

  2. Android内存进程管理机制

    参考文章: http://www.apkbus.com/android-104940-1-1.htmlhttp://blog.sina.com.cn/s/blog_3e3fcadd0100yjo2.h ...

  3. Android内存管理机制之一:low memory killer

    转载自http://www.miui.com/thread-29268-1-1.html 准备写这个专题之前,心里是有点忐忑的.首先Android内存管理机制相当复杂,想要讲清楚比较困难:其次对于绝大 ...

  4. Android内存管理机制

    相信一步步走过来的Android从业者,每个人都会遇到OOM的情况.如何避免和防范OOM的出现,对于每一个程序员来说确实是一门必不可少的能力. 今天我们就谈谈在Android平台下内存的管理之道,开始 ...

  5. 【朝花夕拾】Android性能篇之(六)Android进程管理机制

    前言        Android系统与其他操作系统有个很不一样的地方,就是其他操作系统尽可能移除不再活动的进程,从而尽可能保证多的内存空间,而Android系统却是反其道而行之,尽可能保留进程.An ...

  6. Android包管理机制(二)PackageInstaller安装APK

    前言 在本系列上一篇文章Android包管理机制(一)PackageInstaller的初始化中我们学习了PackageInstaller是如何初始化的,这一篇文章我们接着学习PackageInsta ...

  7. Android包管理机制(一) PackageInstaller的初始化

    前言 包管理机制是Android中的重要机制,是应用开发和系统开发需要掌握的知识点之一. 包指的是Apk.jar和so文件等等,它们被加载到Android内存中,由一个包转变成可执行的代码,这就需要一 ...

  8. Android_对android虚拟机的理解,包括内存管理机制垃圾回收机制。dalvik和art区别

    虚拟机很小,空间很小,谈谈移动设备的虚拟机的大小限制 16M ,谈谈加载图片的时候怎么处理大图片的,outmemoryExceptionBitmapFactory.option 垃圾回收,没有引用的对 ...

  9. Android开发——Android 6.0权限管理机制详解

    .Android 6.0运行时主动请求权限 3.1  检测和申请权限 下面的例子介绍上面列出的读写SD卡的使用例子,可以使用以下的方式解决: public boolean isGrantExterna ...

随机推荐

  1. 【bzoj1053】[HAOI2007]反素数ant

    对于任何正整数x,其约数的个数记作g(x).例如g(1)=1.g(6)=4.如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数.例如,整数1,2,4,6等都是反质数 ...

  2. 不吹不黑,关于 Java 类加载器的这一点,市面上没有任何一本图书讲到

    类加载器第7弹: 实战分析Tomcat的类加载器结构(使用Eclipse MAT验证) 还是Tomcat,关于类加载器的趣味实验 了不得,我可能发现了Jar 包冲突的秘密 重写类加载器,实现简单的热替 ...

  3. PHPCMS内链设置,PHPCMS关联链接设置

    需求: 在网站中的关键词,自动加上链接. 在PHPCMS中叫做“关联链接”,在DEDECMS中叫做TAG标签. 第1步:后台 -> 扩展 -> 关联链接 -> 添加关联链接: 第2步 ...

  4. AC日记——猴子 cogs 2043

    2043. 猴子 ★★   输入文件:monkeya.in   输出文件:monkeya.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 有n只猴子,第一只尾巴挂在树上 ...

  5. Linux 嵌入式启动以及优化

    转载:http://www.embeddedlinux.org.cn/html/jishuzixun/201312/19-2717.html 第一步: BootLoader -- U boot   1 ...

  6. filter和spring 的interceptor都是单例的,都不是线程安全的

    Filter 是在 Servlet 容器启动时就初始化的,因此可以认为是以单例对象存在的,如果一个请求线程对其中的成员变量修改的话,会影响到其他的请求线程,因此认为是多线程不安全的.

  7. 邁向IT專家成功之路的三十則鐵律 鐵律十八:IT人求職之道-文化

    IT人所從事的工作是一個求新求變速度最快的行業,因此您所待的企業IT部門或資訊公司,其組織文化將關係到您在這間公司服務期間,是否能夠快速成長的決定因素.遇到不良的組織文化建議您三個就可以走人了,千萬別 ...

  8. Mac下安装和使用GunPG(GPG)

    GPG是加解密的工具,亦可以用于签名.非对称加解密.需要公钥和私钥. mac下安装:brew install gpg 使用gpg工具校验下载文件的完整性,从官网下载KEYS和asc文件:gpg --i ...

  9. pycharm的todo和fixme标记,标志为今后再做和bug点

    使用方法,及查看方法: https://blog.csdn.net/xiemanR/article/details/73368440

  10. uva 11374 最短路+记录路径 dijkstra最短路模板

    UVA - 11374 Airport Express Time Limit:1000MS   Memory Limit:Unknown   64bit IO Format:%lld & %l ...