一种封装Weex模块调用的方法

我们在开发Weex的过程中,肯定会用到模块的调用,而如果直接将客户端的native方法暴露给前端使用,会造成一定的不便,例如客户端某个模块的某个方法有改动,则所有的前端页面都要进行修改,所以我们需要一种“中间件”的方式去屏蔽差异。

整体思路

首先我们要明确的是,这个“中间件”也是js代码,但是它向下调用native的模块,向上将结果传递给前端业务代码,并且独立于所有的业务页面,这样业务代码只需要在使用的时候调用它就可以,而如果nativa模块有改动,我们也只要改动相应的中间件就可以了,业务代码不需要做调整。

方案一

基于这样的需求,我们可以很快的想到一种最基础的方式就是新建一个项目并通过npm发布,在业务代码中直接引用,这种模块化的方式配合webpack应该是比较常见的一种写法了,但是这种情况存在一个弊端,就是最终的dest js会比较的大,因为会包含我们添加了npm包,而这会导致我们Weex资源下载和加载的变慢,显示不是一种最优解。

方案二

关于方案二可以看我之前写的文章Vue.use源码学习,具体就是通过Vue的插件机制去完成注册。

方案三

方案三则是通过Weex本身的js service的方式去注册,关于js service大家可以去官网查看:JS Service

通过查看native端的源码发现,其实它内部就是使用了js的自执行函数来完成的注册:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static boolean registerService(String name, String serviceScript, Map<String, Object> options) {
if (TextUtils.isEmpty(name) || TextUtils.isEmpty(serviceScript)) return false;

String param1 = "register: global.registerService, unregister: global.unregisterService";
String param2 = "serviceName: \"" + name + "\"";
for (String key: options.keySet()) {
// TODO - why always string?
Object value = options.get(key);
if (value instanceof String) {
param2 += ", \'" + key + "\': \'" + value + "\'";
} else {
param2 += ", \'" + key + "\': " + value;
}
}
String serviceJs = String.format(";(function(service, options){ ;%s; })({ %s }, { %s });", serviceScript, param1, param2);

WXJSService service = new WXJSService();
service.setName(name);
service.setScript(serviceScript);
service.setOptions(options);
sInstanceJSServiceMap.put(name, service);

WXBridgeManager.getInstance().execJSService(serviceJs);
return true;
}

可以看到,Weex通过拼接了一个function并执行它来注册我们自己写的code,我们提取一下这个function可以看到:

1
(function(service, options){jsCode})({register: global.registerService, unregister: global.unregisterService}, {serviceName: name}

这就是拼接好的代码,其实就是执行jsCode部分,并且传入了两个参数,最终通过global这个全局变量去注册。

总结

上面提供了三种思路,其中方案一比较简单,但是缺点就是会增加包的体积,导致Weex性能的下降。而方案二和方案三通过了一定的“黑魔法”去完成代码的加载,这里我们需要注意的是,通过方案二或者方案三来完成功能的时候,我们需要一个独立的js文件来承载其中的代码,而这个js文件我们可以缓存到本地,在需要更新的时候进行更新就好了。