技术架构

HTML5+ 基座扩展采用三层结构,JS层、PluginBridge层和Native层。 三层功能分别是:
JS层: 在Webview页面调用,触发Native层代码,获取执行结果。
PluginBridge层: 将JS层请求进行处理,触发Native层扩展插件代码。
Native层: 插件扩展的平台原生代码,负责执行业务逻辑并执行结果返回到请求页面。

开发者在开发扩展插件时需要为扩展插件编写对应的JS API,JS API将在HTML页面中触发调用对应Native扩展方法的请求,并负责接收运行结果。

开发者在编写扩展插件的JS时需要调用Javascript Plugin Bridge的API用来完成对Native层代码的调用和运行结果的返回。在实际应用中,开发者可以根据扩展方法的实际需求不同,将插件的扩展方法设置为同步执行或异步执行。

同步执行的扩展方法会阻塞当前JS代码的执行,直到Native层插件扩展方法执行完毕。异步扩展方法不会阻塞当前JS代码的执行,使用者需要设置回调方法接收Native层返回的执行结果,开发者需要在插件中调用 Native plugin brigde的方法将执行结果返回到请求页面。

工程示例请参考SDK内包含的HBuilder-Integrate工程,工程里已经整合了插件开发和集成方式的示例。

扩展插件工作流程

异步方法的执行不会阻塞当前JS的运行,方法的执行结果会通过回调的方式返回。
插件异步扩展方法:

同步方法的执行会阻塞当前JS的运行,方法执行完成后可直接获取执行的结果。
插件同步扩展方法:

扩展插件JS API 编写

开发者在实现JS层API时首先要定义一个插件类的别名,并需要在Android工程的assets\data\properties.xml文件中声明插件类别名和Native层扩展插件类的对应关系

复制代码<properties>  <features>  <feature name="plugintest" value="com.example.H5PlusPlugin.PGPlugintest"></feature>
</properties>  

示例中为方便查看删除了其他插件的代码,开发者在可根据5+应用使用插件的情况进行增删修改。
Feature节点下声明的插件将会在调用时创建相应的对象。

JS扩展方法的实现

同步返回JS扩展方法实现
在实现同步扩展方法时,开发者需要调用JS Plugin Bridge的window.plus.bridge.execSync()
方法,该方法可同步获取Native插件返回的运行结果。

复制代码void plus.bridge.execSync( String service, String action, Array<String> args );  

service: 插件类别名
action: 调用Native层插件方法名称。
args: 参数列表。

异步返回JS扩展方法实现
在实现异步扩展方法时,开发者需要调用JS Plugin Bridge的plus.bridge.exec()方法,该方法会通知Native层插件执行指定方法,运行结果会通过回调的方式通知JS层

复制代码void plus.bridge.exec( String service, String action, Array<String> args );  

service: 插件类别名
action: 调用Native层插件方法名称。
args: 参数列表。

扩展插件JS API代码示例:

复制代码! function(root, factory) {  if (typeof exports == 'object' && typeof module != 'undefined') {  module.exports = factory()  } else if (typeof define == 'function' && define.amd) {  define(factory)  } else {  /**  * 插件对象直接扩展到 window 对象上  * 这个对象的名字,需要自己填写一下。例如:plugintest  */  var moduleName = 'plugintest';  root[moduleName] = factory()  }
}(this, function() {  var _BARCODE = 'plugintest';  var plugintest = {  PluginTestFunction: function(Argus1, Argus2, Argus3, Argus4, successCallback, errorCallback) {  var success = typeof successCallback !== 'function' ? null : function(args) {  successCallback(args);  },  fail = typeof errorCallback !== 'function' ? null : function(code) {  errorCallback(code);  };  callbackID = plus.bridge.callbackId(success, fail);  return plus.bridge.exec(_BARCODE, "PluginTestFunction", [callbackID, Argus1, Argus2, Argus3, Argus4]);  },  PluginTestFunctionArrayArgu: function(Argus, successCallback, errorCallback) {  var success = typeof successCallback !== 'function' ? null : function(args) {  successCallback(args);  },  fail = typeof errorCallback !== 'function' ? null : function(code) {  errorCallback(code);  };  callbackID = plus.bridge.callbackId(success, fail);  return plus.bridge.exec(_BARCODE, "PluginTestFunctionArrayArgu", [callbackID, Argus]);  },  PluginTestFunctionSync: function(Argus1, Argus2, Argus3, Argus4) {  return plus.bridge.execSync(_BARCODE, "PluginTestFunctionSync", [Argus1, Argus2, Argus3, Argus4]);  },  PluginTestFunctionSyncArrayArgu: function(Argus) {  return plus.bridge.execSync(_BARCODE, "PluginTestFunctionSyncArrayArgu", [Argus]);  }  };  return plugintest;
});  

Html使用示例

复制代码<!DOCTYPE HTML>
<html>  <head>  <meta charset="utf-8"/>  <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>  <meta name="HandheldFriendly" content="true"/>  <meta name="MobileOptimized" content="320"/>  <title>H5Plugin</title>  <script type="text/javascript" src="./js/common.js"></script>  <script type="text/javascript" src="./js/test.js"></script>  <script type="text/javascript">  function pluginShow() {  plus.plugintest.PluginTestFunction("Html5","Plus","AsyncFunction","MultiArgument!", function( result ) {alert( result[0]  + "_" + result[1]  + "_" + result[2]  + "_" + result[3] );},function(result){alert(result)});  }  function pluginShowArrayArgu() {  plus.plugintest.PluginTestFunctionArrayArgu( ["Html5","Plus","AsyncFunction","ArrayArgument!"], function( result ) {alert( result );},function(result){alert(result)});  }  function pluginGetString()  {  alert(plus.plugintest.PluginTestFunctionSync("Html5","Plus","SyncFunction","MultiArgument!"));  }  function pluginGetStringArrayArgu()  {  var Argus = plus.plugintest.PluginTestFunctionSyncArrayArgu(["Html5","Plus","SyncFunction","ArrayArgument!"]);  alert( Argus.RetArgu1 + "_" +  Argus.RetArgu2 + "_" + Argus.RetArgu3  + "_" + Argus.RetArgu4 );  }  </script>  <link rel="stylesheet" href="./css/common.css" type="text/css" charset="utf-8"/>  </head>  <body>  <header>  <div class="nvbt" onclick="back();"><div class="iback"></div></div>  <div class="nvtt">PluginTest</div>  </header>  <div id="dcontent" class="dcontent">  <br/>  <div class="button" onclick="pluginShow()">PluginTestFunction()</div>  <div class="button" onclick="pluginShowArrayArgu()">PluginTestFunctionArrayArgu()</div>  <div class="button" onclick="pluginGetString()">PluginTestFunctionSync()</div>  <div class="button" onclick="pluginGetStringArrayArgu()">PluginTestFunctionSyncArrayArgu()</div>      <br/>  </div>  </body>
</html>  

uni-app 使用示例
uni-app 中无需主动监听 plusready,可以直接调用 plus 相关的 API。

复制代码<template>  <view>  <button @click="pluginShow">pluginShow</button>  </view>
</template>
<script>
// 扩展的 js 文件的位置:common/plugins.js  var plugins = require('../../common/plugins.js')  export default {  data() {  return {  plugins: plugins  };  },  methods: {  pluginShow() {  this.plugins.PluginTestFunction("Html5", "Plus", "AsyncFunction", "MultiArgument!", function(result) {  console.log(result[0] + "_" + result[1] + "_" + result[2] + "_" + result[3]);  }, function(result) {  console.log(result)  });  }  }  }
</script>
<style>  </style>  

Android第三方插件开发指导

准备

首先要下载HTML5+基座的Android版SDK点击下载解压后将HBuilder-Integrate工程导入到ADT中。

uni-app插件开发

android平台:uni-app插件开发

老接口实现方式

开发步骤

创建插件类
开发者创建的扩展插件类应当继承自“IFeature”类实现第三方插件扩展。
创建插件类需要引入的包

复制代码import io.dcloud.common.DHInterface.AbsMgr;
import io.dcloud.common.DHInterface.IFeature;
import io.dcloud.common.DHInterface.IWebview;
import io.dcloud.common.util.JSUtil;  

实现接口类的“excute”方法
excute方法负责接收由html页面发起的扩展插件调用请求,并负责根据传入参数运行执行对应的业务。
“execute”方法的“action”参数传入的是JS类的方法名,类型为String。开发者需要在方法中通过字符串匹配来处理请求的逻辑。“pArgs”参数为字符串列表对象,如JS层调用的方法有传入参数,会通过该参数传递到Native的方法中,方法的传入顺序和JS层传入顺序一致。
开发者在实现同步和异步接口运行结果返回时调用的API是不同的
同步执行方法:
同步执行方法在返回结果时可以直接将结果以return的形式返回给js层,返回的结果需要调用

复制代码JSUtil.wrapJsVar("Html5 Plus Plugin Hello1!",true);  

处理要返回的字符串,也可调用其他方法处理其他返回值类型(参考io.dclod.util.JSUtil的返回方法)。
异步执行方法:
异步方法开发者需要调用

复制代码JSUtil.execCallback(pWebview, cbId, (which==AlertDialog.BUTTON_POSITIVE)?"ok":"cancel", JSUtil.OK, false, false);   

代码实例

复制代码package com.example.H5PlusPlugin;  import io.dcloud.common.DHInterface.AbsMgr;
import io.dcloud.common.DHInterface.IFeature;
import io.dcloud.common.DHInterface.IWebview;
import io.dcloud.common.util.JSUtil;  import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;  import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.os.Build;  public class PGPlugintest implements IFeature
{  @Override  public void init(AbsMgr arg0, String arg1) {  // TODO Auto-generated method stub  }  @SuppressWarnings("deprecation")  @TargetApi(Build.VERSION_CODES.CUPCAKE)  @SuppressLint("NewApi")  @Override  public String execute(final IWebview pWebview, final String action, final String[] pArgs) {  // TODO Auto-generated method stub  //Context context = pWebview.getContext();  if ("PluginTestFunction".equals(action))  {  String CallBackID = pArgs[0];  JSONArray newArray = new JSONArray();  newArray.put(pArgs[1]);  newArray.put(pArgs[2]);  newArray.put(pArgs[3]);  newArray.put(pArgs[4]);  JSUtil.execCallback(pWebview, CallBackID, newArray, JSUtil.OK, false);  }  else if("PluginTestFunctionArrayArgu".equals(action))  {  String ReturnString = null;  String CallBackID =  pArgs[0];  JSONArray newArray = null;  try {  newArray = new JSONArray(pArgs[1]);           String inValue1 = newArray.getString(0);  String inValue2 = newArray.getString(1);  String inValue3 = newArray.getString(2);  String inValue4 = newArray.getString(3);  ReturnString = inValue1 + "-" + inValue2 + "-" + inValue3 + "-" + inValue4;  } catch (JSONException e) {  // TODO Auto-generated catch block  e.printStackTrace();  }  JSUtil.execCallback(pWebview, CallBackID, ReturnString, JSUtil.OK, false);  }else if("PluginTestFunctionSync".equals(action))  {  String inValue1 = pArgs[0];  String inValue2 = pArgs[1];  String inValue3 = pArgs[2];  String inValue4 = pArgs[3];  String ReturnValue = inValue1 + "-" + inValue2 + "-" + inValue3 + "-" + inValue4;  return JSUtil.wrapJsVar(ReturnValue,true);  }else if("PluginTestFunctionSyncArrayArgu".equals(action))  {  JSONArray newArray = null;  JSONObject retJSONObj = null;  try {  newArray = new JSONArray(pArgs[0]);  String inValue1 = newArray.getString(0);  String inValue2 = newArray.getString(1);  String inValue3 = newArray.getString(2);  String inValue4 = newArray.getString(3);  retJSONObj = new JSONObject();  retJSONObj.putOpt("RetArgu1", inValue1);  retJSONObj.putOpt("RetArgu2", inValue2);  retJSONObj.putOpt("RetArgu3", inValue3);  retJSONObj.putOpt("RetArgu4", inValue4);  } catch (JSONException e1) {  // TODO Auto-generated catch block  e1.printStackTrace();  }         return JSUtil.wrapJsVar(retJSONObj);  }  return null;  }  @Override  public void dispose(String arg0) {  // TODO Auto-generated method stub  }
}  

新接口实现方式

创建插件类
创建一个继承自StandardFeature的类,实现第三方插件扩展。
创建插件类需要引入的包
import io.dcloud.DHInterface.IWebview;
import io.dcloud.DHInterface.StandardFeature;
import io.dcloud.util.JSUtil;
实现扩展方法
Native层扩展插件的方法名需要和JS Plugin Bridge里windows.plus.bridge.exec()或windows.plus.bridge.execSync()方法的第二个传入参数相同,否则无法调用到指定的方法。

复制代码public void PluginTestFunction(IWebview pWebview, JSONArray array)  

扩展方法有两个传入参数
IWebview pWebview 发起请求的webview,
JSONArray array JS请求传入的参数

开发者在实现同步和异步接口运行结果返回时调用的API是不同的
同步执行方法:
同步执行方法在返回结果时可以直接将结果以return的形式返回给js层,返回的结果需要调用

复制代码JSUtil.wrapJsVar("Html5 Plus Plugin Hello1!",true);  

处理要返回的字符串,也可调用其他方法处理其他返回值类型(参考io.dclod.util.JSUtil的返回方法)。
异步执行方法:
异步方法开发者需要调用

复制代码JSUtil.execCallback(pWebview, cbId, (which==AlertDialog.BUTTON_POSITIVE)?"ok":"cancel", JSUtil.OK, false, false);   

代码示例

复制代码
package com.example.H5PlusPlugin;
import io.dcloud.common.DHInterface.IWebview;
import io.dcloud.common.DHInterface.StandardFeature;
import io.dcloud.common.util.JSUtil;  import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;  public class PGPlugintest extends StandardFeature
{     public void PluginTestFunction(IWebview pWebview, JSONArray array)  {  String CallBackID = array.optString(0);  JSONArray newArray = new JSONArray();  newArray.put(array.optString(1));  newArray.put(array.optString(2));  newArray.put(array.optString(3));  newArray.put(array.optString(4));  JSUtil.execCallback(pWebview, CallBackID, newArray, JSUtil.OK, false);  }  public void PluginTestFunctionArrayArgu(IWebview pWebview, JSONArray array)  {  String ReturnString = null;  String CallBackID =  array.optString(0);  JSONArray newArray = null;  try {  newArray = new JSONArray( array.optString(1));            String inValue1 = newArray.getString(0);  String inValue2 = newArray.getString(1);  String inValue3 = newArray.getString(2);  String inValue4 = newArray.getString(3);  ReturnString = inValue1 + "-" + inValue2 + "-" + inValue3 + "-" + inValue4;  } catch (JSONException e) {  // TODO Auto-generated catch block  e.printStackTrace();  }  JSUtil.execCallback(pWebview, CallBackID, ReturnString, JSUtil.OK, false);  }  public String PluginTestFunctionSyncArrayArgu(IWebview pWebview, JSONArray array)  {  JSONArray newArray = null;  JSONObject retJSONObj = null;  try {  newArray = array.optJSONArray(0);  String inValue1 = newArray.getString(0);  String inValue2 = newArray.getString(1);  String inValue3 = newArray.getString(2);  String inValue4 = newArray.getString(3);  retJSONObj = new JSONObject();  retJSONObj.putOpt("RetArgu1", inValue1);  retJSONObj.putOpt("RetArgu2", inValue2);  retJSONObj.putOpt("RetArgu3", inValue3);  retJSONObj.putOpt("RetArgu4", inValue4);  } catch (JSONException e1) {  // TODO Auto-generated catch block  e1.printStackTrace();  }         return JSUtil.wrapJsVar(retJSONObj);  }  public String PluginTestFunctionSync(IWebview pWebview, JSONArray array)  {  String inValue1 = array.optString(0);  String inValue2 = array.optString(1);  String inValue3 = array.optString(2);  String inValue4 = array.optString(3);  String ReturnValue = inValue1 + "-" + inValue2 + "-" + inValue3 + "-" + inValue4;  return JSUtil.wrapJsVar(ReturnValue,true);  }  }

三 关联JS插件名和原生类

在编写扩展插件时需要修改“/assets/data”中properties.xml文件,在其中添加JS对象名称和Android包的类名对应关系,SDK会根据对应的类名查找并生成相应的对象并执行对应的逻辑。

在应用的manifest.json文件中还需要添加扩展插件的应用使用权限

Android平台插件开发API

io.dcloud.DHInterface.IFeature

扩展插件接口类,Android平台的扩展插件应当继承自此接口类并实现接口方法。

常用方法说明:

复制代码String execute(IWebview pWebView, String action, String[] pArgs);  

执行扩展插件的方法,调用native代码实现具体的操作。
pWebView: 扩展插件方法运行的窗口
action: 调用插件方法的名称
args: 调用插件方法使用的参数列表

io.dcloud.util.JSUtil

常用方法说明:

复制代码String wrapJsVar(String value, boolean isString);  

转换JS层的返回值,也用于异步接口中回调函数的参数。
参数说明:
value: 要返回到JS层的值
isString:返回值类型是否为原始字符串
返回方法:
boolea类型: wrapJSVar( "true", false );
Number类型: wrapJsVar( "99", false );
String类型: wrapJsVar( "hello", true );
数组类型: wrapJsVar( "[1,2,3,4,5]", false );
JSON类型: wrapJsVar( "{'name':'value'}", false );

复制代码String execCallback(IWebview pWebView, String pCallbackId, String pMessage, int pStatus, boolean isJson, boolean pKeepCallback);  

触发扩展插件中的回调方法。

参数说明:
pWebView:扩展插件方法运行的窗口
pCallbackId:回调函数的唯一标识
pMessage:回调函数的参数
pStatus:操作是否成功,成功则使用JSUtil.OK,否则使用错误代码
isJson:回调函数参数是否为JSON数据
pKeepCallback:是否可多次触发回调函数

术语字典

JS Plugin Bridge: H5+ Plugin Bridge层JS部分API,用户通过调用相应的API触发Native层扩展插件相应方法的调用。
Native Plugin Bridge: H5+ Plugin Bridge层Native部分API,开发者通过实现接口类方法,实现由JS层触发Native层扩展插件逻辑。开发者调用API实现Native扩展方法运行结果得返回。
Native层插件:开发者使用原生语言实现的5+扩展插件,可被JS层通知调用。
插件类别名:JS层字符串,用来声明JS方法和Native层插件的对应关系

转自:https://ask.dcloud.net.cn/article/66

Android平台第三方插件开发指导(dcloud)相关推荐

  1. 哪些公司开发android输入法软件,六款Android平台第三方输入法软件横评

    虽然现在非智能手机在第三方应用上已经有了相当大的进步,不少已经支持软件后台运行,与智能手机一样可以同时挂QQ.听音乐.看网页等等.不过安装第三方输入法仍然还只是智能手机的专利.记得第一次在诺基亚668 ...

  2. Android云打包平台,Android平台云端打包使用的DCloud公用证书(安卓证书)

    HBuilder|HBuilderX应用云端打包Android平台默认使用的DCloud公用证书,其信息如下: MD5: 59:20:1C:F6:58:92:02:CB:2C:DA:B2:67:52: ...

  3. android第三方launcher,目前Android平台最好的Launcher

    由于Blackberry Priv无法Root,也无法刷其他的Room,因此可以折腾的也就只有Launcher了.其实Priv自带Launcher就已经很不错了,尤其是对于某些应用,上滑以预览的方式打 ...

  4. Android平台开发指导(Android Porting Guide)

    本文为Android平台开发人员和Android设备制造商提供了底层开发指导.如果你对Android的上层应用开发很感兴趣,请访问Android Developers Site. 关于这份指导书 这份 ...

  5. cocos2dx使用了第三方库照样移植android平台-解决iconv库的移植问题

    好记性不如烂笔头 cocos2dx使用了第三方库照样移植android平台-解决iconv库的移植问题 http://www.zaojiahua.com/iconv.html

  6. DCloud之Android平台应用启动时读写手机存储、访问设备信息(如IMEI)等权限策略控制

    目录 一.控制缘由 二.说明 三.云端打包配置 1.读写手机存储权限 (1)源码视图配置 2.访问设备信息权限 (1)源码视图配置 四.离线打包提示语配置及弹窗配置 1.提示语配置 2.弹窗配置 五. ...

  7. android hook 第三方app_基于 VirtualApp 结合 whale hook框架实现hook第三方应用

    要点 1. whale hook framework 使用示例: 2. 参考项目:VirtualHook: 3. 按照 VirtualHook 修改 VirtualApp: 4. 编写 hook pl ...

  8. 文通Android平台证件识别SDK

    文通Android平台证件识别SDK 功能介绍 1.通过拍照界面,指导用户拍出合格证件图像. 2.采用文字识别(OCR)技术,自动提取证件信息(如姓名.证件号码.地址等)及头像. 3.识别证件种类包括 ...

  9. 基于 Android 平台的手机安全卫士的设计与实现【100010420】

    基于 Android 平台的手机安全卫士的设计与实现 第 1 章 引言 1.1 研究背景及意义 随着智能手机和网络的完美结合,使得智能机的功能越来越强大,浏览网页.网络购物.视频对话都普及到各个手机终 ...

最新文章

  1. 蚂蚁金服×西安银行 | 西安银行手机银行App的智能升级之路
  2. 使用RSClientPrint直接打印本地RDLC报表
  3. php mysql服务器配置_配置最新的PHP加MYSQL服务器
  4. 国产剧注水严重 广电总局拟将出手:剧集不得超过40集
  5. 华为手机助手上架流程_2019年各大安卓应用商店上架经验,含流程,物料,方法,建议收藏...
  6. [Servlet] 初识Servlet
  7. 分辨率、像素、像素尺寸、GSD、图片文件大小
  8. linux sd卡修复工具,免费的SD卡数据恢复工具介绍
  9. 谷歌身份验证器的使用超详细步骤
  10. 百练oj2816:红与黑
  11. 多线程 ForkJoinPool
  12. win10自带的删除电脑流氓弹窗软件工具怎么用
  13. 河南省赛 导弹发射 lis
  14. 亚马逊卖家,为什么你做不出爆品?从动森看大火之道
  15. 活的恬淡宁静  萃取生命真谛
  16. Java面试题仅供自己学习
  17. 一个简单的 Vue 头像选择器
  18. UMAX系统——智能终端的领跑者
  19. strtok是分割字符串,查找中间最长的单元
  20. Android 通过MediaMetadataRetriever获取视频封面和时长

热门文章

  1. 【20211207】【雷达】毫米波雷达(一)—— 基本原理
  2. 红孩儿编辑器的模块设计4
  3. 部署学之思在线考试项目
  4. 无法获取链接服务器 XXX 的 OLE DB 访问接口 SQLNCLI10 的架构行集 DBSCHEMA_TABLES_INFO。该访问接口支持该接口,但使用该接口时返回了失败代码。...
  5. 登陆器生成登陆器不显示服务器列表,GeeM2单机登录器读取不到列表怎么办?
  6. amcharts学习笔记
  7. Gerrit报错:Permission denied publickey的解决办法
  8. Linux deepin 15.11设置:输入时禁用触摸板
  9. java解析HL7协议报文工具 HAPI(SpringBoot版本)
  10. SpringBoot整合使用XXL-JOB