讓別人的小程序運行在本身的app中

概要

本文包括的內容:css

  • 小程序在微信開發者工具中,經過構建生成真正的執行代碼和安裝包,****.wxapkg。wxml和wxss在構建這一步就被轉換成了html和css(virtual-DOM)。微信開發者工具中能夠獲得構建腳本和各個版本的js運行SDK文件。
  • 小程序是以wxapkg文件的形式下發的,能夠拿到wxapkg後解壓拿到執行代碼。同時解壓微信.ipa拿到當前的js運行SDK文件,主要是WAWebView.js和WAService.js。
  • 小程序在App中執行時的時候分爲三個不一樣的模塊,View/Service/Natvie,各司其職。
  • 實現過程遇到大量的細節和坑。

介紹小程序原理的文章比較多,這篇講的比較細:微信小程序架構分析。這篇文章的做者也成功的實現了wept,讓小程序運行在本身的webapp裏。html

參考最多的是微店的Hera,完成度很是高的小程序框架,可以將小程序的demo代碼在web/iOS/android運行起來,並且實現了不少工具。Hera的問題是開發於比較早期的版本,不兼容最新的版本了。Hera還有一個問題是他修改了小程序構建以後的目錄結構,採用了service.html做爲service部分的入口,跟小程序自己的實現尚有有一些區別。因此Hera只可以構建執行本身編寫的小程序,不能執行別人編寫的小程序。vue

個人目標是可以運行其它人開發的app,意味着我只能經過逆向的方式拿到wxapkg。可是由於拿不到源碼,因此要儘量在構建環節跟小程序保持一致。python

通過數週的掙扎,目前已經實現了運行官方demo。已經達到"可行"的階段,可是還遠遠談不上「可用」,由於須要實現小程序大量的API,這是個體力活,依賴我的的力量難以完成。android

構建

官方demo小程序原先的目錄分爲幾類文件:git

  • 配置: 在這個目錄中,app.json裏保存了頁面信息、tabbar信息、網絡超時配置等等。 config.js保存了騰訊雲後臺服務解決方案的配置。
  • js文件: js定義了各類函數接口邏輯
  • wxml: 相似於html,定義了頁面結構
  • wxss: 相似css
demo
├── app.js
├── app.json
├── app.wxss
├── config.js
├── image
│   ├── green_tri.png
│   ├── ...
├── page
│   ├── API
│   │   ├── index.js
│   │   ├── index.json
│   │   ├── index.wxml
│   │   ├── index.wxss
│   │   ├── pages
│   │   │   ├── action-sheet
│   │   │   │   ├── action-sheet.js
│   │   │   │   ├── action-sheet.json
│   │   │   │   ├── action-sheet.wxml
│   │   │   │   └── action-sheet.wxss
│   │   │   ├── ...
│   │   └── resources
│   │       └── ...
│   ├── ...
├── project.config.json
├── util
│   └── util.js
└── vendor
    └── qcloud-weapp-client-sdk
        ├── ...

複製代碼

通過小程序的開發環境構建後,生成了一個*.wxapkg文件。 這個文件能夠經過從越獄的iPhone或者root的安卓手機上拿到。有部分人用charles經過https抓包拿到了下載連接,也拿到了包。 拿到後要進行解包。有大神已經經過反編譯安卓apk的方式拿到了解包部分的代碼,而後用python重寫了一遍。源碼見wechat-app-unpackgithub

解包後獲得的目錄以下:web

1.wxapkg_dir
├── app-config.json
├── app-service.js
├── app-service.js.map
├── image
│   ├── green_tri.png
│   ├── ...
├── page
│   ├── API
│   │   ├── index.html
│   │   ├── pages
│   │   │   ├── action-sheet
│   │   │   │   └── action-sheet.html
│   │   │   ├── ...
│   │   └── resources
│   │       └── kind
│   │           ├── api.png
│   │           ├── ...
│   ├── ...
└── page-frame.html
複製代碼

轉換過程能夠分爲三部分:算法

  • 從wxml/wxss到html。 page-frame.html裏定義了全部的virtural-dom,來自全部的wxss和wxml的轉換,文件很是大。 page.html裏很簡單,就是從page-frame.html裏提取對應的virtual-dom。包括wxss和wxml對應的邏輯。
  • app-service.js是從以前全部的js文件轉換而來。
  • app-config.json是從app.json轉換而來。

openVendor命令能夠在小程序中獲取到構建腳本wcc和wcsc, 以及各個版本小程序的執行SDK ****.wxvpkg,這個SDK也能夠用wechat-app-unpack解開,解開后里面就是WAService.js和WAWebView.js等代碼。json

wxml/wxss的構建原理

wxss 轉換成了css,wxml轉換成了inject_js,實際上就是virtual_dom。 是用什麼工具轉換的?小程序裏是叫wcc和wcsc。在開源工具hera本身實現了一套wxss-transpiler和wxml-transpiler。而hera的前身wept是直接使用wcc和wcsc。 咱們爲了減小維護成本,直接採用wcc和wcsc。 由於咱們沒有wcc和wcsc的源碼,因此只能藉助wxss-transpiler和wxml-transpiler來幫助咱們理解wxml/wxss的構建原理。

wxss-transpiler調用了一個PostCSS的插件,用來處理wxss。 PostCSS 提供了一種方式用 JavaScript 代碼來處理 CSS。它負責把 CSS 代碼解析成抽象語法樹結構(Abstract Syntax Tree,AST),再交由插件來進行處理。插件基於 CSS 代碼的 AST 所能進行的操做是多種多樣的,好比能夠支持變量和混入(mixin),增長瀏覽器相關的聲明前綴,或是把使用未來的 CSS 規範的樣式規則轉譯(transpile)成當前的 CSS 規範支持的格式。

wxml-transpiler:實現了一個轉譯器的工做,好比postcss也是轉譯器,包括解釋器(parser),代碼轉換器(Transformer),代碼生成器(Generator)。這個是閉源的。

  • 根據輸入的列表,讀取全部文件
  • 調用VUE的HTML Parser,解析輸入的標籤及屬性,生成一顆DOM樹。vue解決不了的js語言,用babylon庫來處理。(Parse)
  • 在解析組件的標籤時,對其上包含的屬性值進行解析(邊Parse邊Transform)
  • 根據已有的AST生成JS文件(Generate)

更多實現原理見這篇文章

模塊以前的通訊

image

小程序在App中執行時的時候分爲三個不一樣的模塊,View/Service/Native,各司其職。

View和Service都在WKWebView中執行,互相沒法調用。他們之間經過Native層通訊。

Native和WebView之間經過webkit.messagehandler和evaluateJavascript互相調用。

  • WeixinJSBridge.publish: view和service之間的透傳,在WKWebView之間傳遞消息。

  • WeixinJSBridge.subscribe: 註冊監聽,監聽view和service之間的消息調用。

  • WeixinJSBridge.invoke: View或者Service傳遞消息到Native,而後Native使用邏輯調用js callback。

  • WeixinJSBridge.on:監聽Native的事件。

如何執行

這裏以iOS爲例介紹Native執行過程。安卓相似。

經過解壓微信的ipa能夠拿到WAService.js和WAWebView.js兩個基礎庫文件,文件內容與hera的service.js/view.js已經有了較大的區別。 咱們採用小程序的架構和hera的兩個webView的方案,儘量模仿小程序的執行過程。

View部分

View部分是比較直觀的,就是WKWebView加載web頁。這裏須要在app-config.json裏讀取到首頁的路徑,而後加載該頁面。這個路徑下的xxx/index.html是沒法直接加載的,須要作一些處理。要引入本地執行SDK裏的index.css和view.js, 而後把page-frame.html裏的virtual-dom所有塞進該頁面。 而後loadHTML便可。

View全部的WKWebView也是要註冊WKUserContentController的,用於通訊。 經過反彙編能夠得知這個類在微信中叫YYWAWebView,調用js是直接調用-evaluateJavaScript:completionHandler:方法的。

view.js中包含的邏輯:

  • WeixinJSBridge 對象處理消息通訊: invoke invokeCallbackHandler on publish subscribe subscribe subscribeHandler。
  • Reporter 對象
  • wxparser 對象,提供 dom 到 wx element 對象之間的映射操做,提供元素操做管理和事件管理功能。
  • virtual dom 渲染算法實現,提供 diff apply render 等方法,該模塊接口基本與 virtual-dom 一致,這裏特別的地方在於它所 diff 和生成的並非原生 DOM,而是各類模擬了 DOM 接口的 wx element 對象

Service部分

Service部分的實現,Hera和微信小程序採起的了不一樣的架構。 Hera的實現較爲簡潔,跟View部分保持一致,採用了WKWebView,調用-evaluateJavaScript:completionHandler:方法執行js,js回調OC時使用WKScriptMessageHandler。 經過反彙編能夠得知這個類在微信中叫WAJSCoreService,js和OC之間的調用是採用JavascriptCore互相調用。

JavascriptCore它首先要加載app-config.json並把這個配置賦給一個全局對象__wxConfig。而後他要加載service.js是SDK基礎,再而後他要加載app-service.js,這裏麪包含了用戶編寫的js邏輯。最後它發出全局消息 WeixinJSBridge.publish('serviceReady',,);</script>喚起小程序app的初始化。

Service.js中包含的邏輯:

  • 跟 view.js 同樣的 WeixinJSBridge 兼容模塊
  • view.js 同樣的 Reporter 模塊
  • appServiceEngine 模塊,提供 Page,App,GetApp 接口

Native部分

Native執行的問題比較複雜,由於基本是黑盒,裏面發生了什麼並不知道。 hera的方案在構建過程就已經跟小程序實際的方案有所區別,會提升維護成本。因此咱們只能靠猜想來實現Native的執行過程。

Native部分就是做爲入口,運行環境,跳轉,轉發消息,實現擴展。包括網絡模塊/攝像頭/tabbar實現的都是擴展。 咱們能夠得知的是消息傳遞的協議。而後只能經過safari來調試webView,根據協議的名稱和出入參來猜想協議的內容。

主要的困難點

  • 因爲壓縮後的view.js和service.js基本不具有可讀性,而virtual-dom又完全不具有可讀性...因此就算猜中了協議,最後也每每是魔改。可維護性極差。
  • 工做量不小,由於調試困難,沒法閱讀。以後隨着小程序SDK升級,能用多久也不可知。加上也有各類微逆向的操做,小程序封上任何一個接口,都會致使撲街。可持續性極差。總之很是佩服微店的同窗能把Hera搞出來:)

小程序的性能啓發

小程序是顛覆我對Web的固有印象,最初還覺得是相似weex或者rn的調用原生的方式,沒想到幾乎徹底是運行在WKWebView之上的。

  • 採用virtual DOM,操做JS比html性能高不少,由於是diff後再操做dom,不須要所有從新渲染,快不少。
  • WKWebView,滑動60fps,在獨立於App以外的進程執行。
  • 部分邏輯Native化,好比收發網絡請求,好比數據持久化。 逐步用native組件來替換h5組件。好比tabbar。
  • 重用webView以及提早初始化webView等等技巧。

存在的問題:

  • 看消息傳遞的原理就能發現,傳遞的過程太長了,尤爲是setData:這種傳遞整個model對象,是兩次對象的深拷貝,可能會增長兩次json的序列化和反序列化,若是model對象很複雜對性能影響比較大。
  • 頁面初始化/響應速度/UI細節仍是跟原生有差距。

固然已經比純web頁強不少了。目前來看仍是隻適合輕量化的應用。受制於架構以及微信的平臺,我的認爲是對Web的替代和改善。可是就算在可見的將來,仍是很難跟native抗衡。

現代瀏覽器和操做系統之間的界限愈來愈模糊。App的"下載/安裝"過程自己就是一種妥協。只要小程序的體驗足夠好,應該沒有人會拒絕。

相關文章
相關標籤/搜索