一種封裝Weex模組呼叫的方法
我們在開發Weex的過程中,肯定會用到模組的呼叫,而如果直接將客戶端的native方法暴露給前端使用,會造成一定的不便,例如客戶端某個模組的某個方法有改動,則所有的前端頁面都要進行修改,所以我們需要一種“中介軟體”的方式去遮蔽差異。
整體思路
首先我們要明確的是,這個“中介軟體”也是js程式碼,但是它向下呼叫native的模組,向上將結果傳遞給前端業務程式碼,並且獨立於所有的業務頁面,這樣業務程式碼只需要在使用的時候呼叫它就可以,而如果nativa模組有改動,我們也只要改動相應的中介軟體就可以了,業務程式碼不需要做調整。
方案一
基於這樣的需求,我們可以很快的想到一種最基礎的方式就是新建一個專案並通過npm釋出,在業務程式碼中直接引用,這種模組化的方式配合webpack應該是比較常見的一種寫法了,但是這種情況存在一個弊端,就是最終的dest js會比較的大,因為會包含我們添加了npm包,而這會導致我們Weex資源下載和載入的變慢,顯示不是一種最優解。
方案二
關於方案二可以看我之前寫的文章Vue.use原始碼學習,具體就是通過Vue的外掛機制去完成註冊。
方案三
方案三則是通過Weex本身的js service的方式去註冊,關於js service大家可以去官網檢視:ofollow,noindex">JS Service 。
通過檢視native端的原始碼發現,其實它內部就是使用了js的自執行函式來完成的註冊:
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 instanceofString) { 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可以看到:
(function(service, options){jsCode})({register: global.registerService, unregister: global.unregisterService}, {serviceName: name}
這就是拼接好的程式碼,其實就是執行jsCode部分,並且傳入了兩個引數,最終通過global這個全域性變數去註冊。
總結
上面提供了三種思路,其中方案一比較簡單,但是缺點就是會增加包的體積,導致Weex效能的下降。而方案二和方案三通過了一定的“黑魔法”去完成程式碼的載入,這裡我們需要注意的是,通過方案二或者方案三來完成功能的時候,我們需要一個獨立的js檔案來承載其中的程式碼,而這個js檔案我們可以快取到本地,在需要更新的時候進行更新就好了。