§ Fox2.0 插件开发指南
§ 介绍
移动平台使用osgi机制管理插件,以module为功能单位,每个moduel可包含三类文件,分别为boot插件、plugin插件和配置文件,其中boot插件是在平台启动和关闭是调用,如版本更新,缓存清理等,而plugin类型插件用于给javascript提供native能力,如拍照,文件上传下载等,而配置文件则是插件的注册信息。如下图

关于module的命名规范: 1.第三方的外设集成,我们的module的命名一般为device_xxx,例如 集成cfca的签名功能,我们就应该创建模块device_cfca。 2.pdf、图片浏览、im、崩溃日志记录等非设备访问的代码要独立建立插件,插件名规范如下core_ext_xxx, 如core_ext_pdf。 3.原则上尽量一个插件代表一个功能,这样有利于后面我们根据需求进行裁剪。
§ Boot插件开发
主要是用于APP启动过程中调用,我们一般用于做一些初始化工作,如过期文件清理,版本更新等。
§ Java 代码
package fox.core.ext.demo;
import android.util.Log;
import fox.ninetales.FXBoot;
import fox.ninetales.FXInterface;
import fox.ninetales.FXProgressContext;
/**
* Fox启动插件
* start在Activity onCreate方法中调用,当所有的boot模块都done完成后,才
* 加web页面
* stop在Activity destroy方法中调用,在所以的FXPlugin的destroy方法调用
* 后才调
*
* create by 江成
*/
public class DemoBoot extends FXBoot {
/**
* 启动
* activity onCreate方法中调用,在所有boot模块done后启动web view
* 任务完成后必须调用done或cancel方法
*
* @param fxInterface
* @param context
* @return
*/
public void start(FXInterface fxInterface, FXProgressContext context){
Log.i("demo","模块start");
context.done(FXProgressContext.Status.SUCCESS);
}
/**
* 关闭
*
* activity onDestroy方法中调用,在FXPlugin的onDestroy方法后面
*
*
* @param fxInterface
* @return
*/
public void stop(FXInterface fxInterface){
Log.i("demo","模块stop");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
§ 配置文件
配置文件需要手动在模块所在的assets目录下,新建目录metadata,并在该文件夹下新建xml配置文件,文件名的规则fox_extesion_xxx,例如在模块core_ext_demo中的配置文件的名为fox_extension_core_ext_demo.xml。
<?xml version="1.0" encoding="UTF-8"?>
<plugins>
<!--启动扩展-->
<extension point="fox.extension.boot">
<!--启动测试插件-->
<boot name="DemoBoot" class="fox.core.ext.demo.DemoBoot" text="demo启动测试">
</boot>
</extension>
</plugins>
2
3
4
5
6
7
8
9
§ Plugin插件
根据功能和范围插件主要分为FXPlugin,FXProxy,IDevice和INative几类,其中IDevice插件用于调用系统或第三方提供的外设模块,如相机、OCR、二代证等,而INative则用于集成除外设类之外的原生功能,如定位、网络等,而FXProxy则用于功能更为复杂的原生功能调用,FXPlugin功能最强但由于其复杂,也导致其比较少使用,一般用FXProxy代替。我们在原生开发的过程中选择优先顺序是INative&IDevice > FXProxy > FPlugin,也是我们根据功能分类优先选择INative或IDevice,当两个不合适的情况下才选择FXProy,而FXPlugin是最后的选择。下图是他们之间的关系

§ IDevice开发指南
IDevice插件用于集成外设调用,下面是例子
§ java
package fox.core.ext.demo;
import fox.core.ICallback;
import fox.core.plugins.device.IDevice;
/**
* Demo OCR
*
* create by 江成
*/
public class DemoOCRDevice implements IDevice {
/**
* 外设调用
*
* @param type 设备类型,以配置文件中的type对应
* @param action 动作
* @param param 参数
* @param callbackContext 回调函数
*/
public void call(String type, String action, String param, ICallback callbackContext){
//根据js传递过来的动作执行
if("test".equals(action)){
callbackContext.callback(ICallback.SUCCESS,"ok");
}else{
callbackContext.callback(ICallback.ERROR,"error");
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
§ 配置
<?xml version="1.0" encoding="UTF-8"?>
<plugins>
<!--外设模块扩展-->
<extension point="fox.extension.device">
<!--OCR测试-->
<device class="fox.core.ext.demo.DemoOCRDevice" scope="singleton"
type="ocr" typeName="OCR" devId="ocr-demo" devName="测试OCR外设"></device>
</extension>
</plugins>
2
3
4
5
6
7
8
9
配置说明
- type:设备类型,js就是根据type来调用不同的外设的
- typeName:设备类型的描述
- devId:设备的ID必须唯一
- devName:设备的描述
§ js调用
//外设测试
deviceTest:function(){
//type:配置文件上的type保持一致, action, params, callback
fox.device.call("ocr","test","外设测试",(code, message ,data)=>{
//code 0:成功,1:取消,2:失败
//调用成功后,返回数据在data中,如果失败了则message是失败消息
if(code == 0){
fox.layer.open(data);
}else{
fox.layer.open("调用失败,"+message);
}
});
}
2
3
4
5
6
7
8
9
10
11
12
13
参数说明
fox.device.call(type,action,params,callback)是外设调用的js接口,其参数为
- type:外设类型和配置文件上的保持一致
- action:动作,和与原生实现进行约定
- params:参数
- callack:回调函数
§ INative开发指南
IDevice插件用于集成简单的原生功能,下面是例子
§ java
package fox.core.ext.demo;
import fox.core.ICallback;
import fox.core.plugins.natives.INative;
/**
* Network测试
*
* create by 江成
*/
public class DemoNetworkNative implements INative {
/**
* 调用
*
* @param action 动作,配置文件&JS上的action必须一致
* @param param 参数
* @param callbackContext 回调函数
*/
public void call(String action, String param, ICallback
callbackContext){
//根据动作执行
if("wifiStatus".equals(action)){
callbackContext.callback(ICallback.SUCCESS,"ok");
}else{
callbackContext.callback(ICallback.ERROR,"unknown action");
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
####配置
<?xml version="1.0" encoding="UTF-8"?>
<plugins>
<!--native接口模块扩展-->
<extension point="fox.extension.native">
<native action="wifiStatus" class="fox.core.ext.demo.DemoNetworkNative">
</native>
</extension>
</plugins>
2
3
4
5
6
7
8
配置说明
fox.native.call(action,params,callback)是native调用的js接口,其参数为
- action:动作,和与原生实现进行约定和配置文件保持一致
- params:参数
- callack:回调函数
§ js调用
//native测试
nativeTest:function(){
// action:配置文件上的action保持一致, params, callback
fox.native.call("wifiStatus","native测试",(code, message ,data)=>{
//code 0:成功,1:取消,2:失败
//调用成功后,返回数据在data中,如果失败了则message是失败消息
if(code == 0){
fox.layer.open(data);
else{
fox.layer.open("调用失败,"+message);
}
});
}
2
3
4
5
6
7
8
9
10
11
12
13
§ FXProxy开发指南
一个插件的开发主要包括java、配置和js三部分
§ java
插件中暴露给JS调用的方法,必须加上annotation @JavascriptInterface
package fox.core.ext.demo;
import android.util.Log;
import fox.ninetales.FXProxy;
import fox.ninetales.engine.JavascriptInterface;
/**
* FXProxy测试demo,FXProy主要用于为
* Web提供native能力
*
* create by 江成
*/
public class DemoProxy extends FXProxy {
/**
* 插件创建时调用,由于Proxy初始化后只在APP关闭时才销毁,
* 所以该方法只会调用一次
*/
protected void pluginInitialize() {
Log.i("demo" ,"插件初始化,仅会执行一次");
}
/**
* 同步测试
* @param message
* @return
*/
@JavascriptInterface
public String syncFn(String message){
Log.i("demo" ,"同步执行,"+message);
return "back:"+message;
}
/**
* 异步测试
* @param message
* @return
*/
@JavascriptInterface
public void asyncFn(String message){
Log.i("demo" ,"异步执行,"+message);
String retMsg = "back:"+message;
// 成功回调
this.success(retMsg);
//失败回调
//this.error(retMsg);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
§ 配置
<?xml version="1.0" encoding="UTF-8"?>
<plugins>
<!--启动扩展-->
<extension point="fox.extension.boot">
<!--启动测试插件-->
<boot name="demoBoot" class="fox.core.ext.demo.DemoBoot" text="demo启动测试">
</boot>
</extension>
<!--插件扩展-->
<extension point="fox.extension.plugin">
<!--测试插件-->
<plugin name="demoPlugin" class="fox.core.ext.demo.DemoProxy" text="测试插件">
</plugin>
</extension>
</plugins>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
§ js插件
/**
* Created by 江成
*/
(function (fox, window, factory) {
// 判断是否支持模块定义
let hasDefine = (typeof define === 'function');
if (hasDefine) {
//获取对象
let exports = factory(fox,window);
//定义模块
define(exports);
//安装插件(兼容非模块的访问方式)
window.fox.demo = exports;
} else {
//获取对象
let exports = factory(fox,window);
//安装插件
window.fox.demo = exports;
}
}(fox, window, function (fox,window) {
//定义Demo对象
let demo={
/**
* 同步测试
* @param message
*/
syncFn:function(message) {
//参数
let args = {
service: "demoPlugin", //对应FXProxy注册在配置文件上的服务名
action: "syncFn", //对应FXProxy中标志了@JavascriptInterface的方法
data: [message], //对应方法中的参数
async: false //是否异步
};
return window.fxBridge.exec(args);
},
/**
* 异步测试
* @param message
* @param callback
*/
asyncFn:function(message,callback) {
//参数
let args = {
service: "demoPlugin",//对应FXProxy注册在配置文件上的服务名
action: "asyncFn",//对应FXProxy中标志了@JavascriptInterface的方法
data: [message], //对应方法中的参数
async: true, //是否异步
callback:callback //异步回调函数
};
return window.fxBridge.exec(args);
}
};
return demo;
}));
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
§ js调用
//同步测试
demoSyncTest:function(){
let res = fox.demo.syncFn("同步测试");
fox.layer.open(res);
},
//异步测试
demoASyncTest:function(){
fox.demo.asyncFn("异步测试",(status,data)=>{
//status 0:成功,1:取消,2:失败
if(status == '0'){
fox.layer.open(data);
}else{
fox.layer.open("调用失败");
}
});
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16