前言
facebook的react-native給我們帶來了用js寫出原生應用的同時,也使得使用RN編寫的代碼的在線升級變得可能,終於可以不通過應用市場來進行升級,極大的提升了app修bug和賦予新功能的能力。----使用h5的方式也可以做到,但是rn的用戶體驗可要遠遠超過h5啊。
一般使用RN編寫的app的線上使用方式,是將react-native bundle命令打出bundle文件和assets文件夾,直接內置到app中,app在viewcontroller或者activity中直接加載app內部的bundle文件,比如下圖。
當修改了代碼或者圖片的時候,只要app使用新的bundle文件和assets文件夾,就完成了一次在線升級。
本文主要基於以上思路,講解增量升級的解決方案。
何爲增量?
一個完整的RN-app程序通常包含以下幾個部分:
- native代碼部分-objc或者java
- js代碼部分-rn代碼、依賴的第三方庫、業務代碼等
- 圖片資源部分
native代碼別想了,沒法在線升級,要是能大家就都不使用應用市場ota升級了。
能進行在線升級的是js代碼部分和圖片資源部分,具體到代碼就是bundle文件和assets文件夾。
因爲在線升級是要走網絡的,我們要想辦法將網絡消耗降到最低,所以要使用增量升級的方式。
針對js代碼部分(即bundle文件)的增量指的是,代碼的改動有多少,增量patch的補丁就有多少,那些沒有改動的代碼部分是不在補丁的範圍內的。
針對圖片部分(即assets)的增量指的是,升級補丁包中只包含新增的圖片和有改動的圖片。
那麼在app端,下載升級補丁包,只需要和現有的版本進行合併,就能計算出最新版本的全量包。
總結下流程:()中爲例子
首先,計算增量包:新版本(v10) - 舊版本(v1到v9) = 增量包 (會有9個包,v1~v10.zip,v2~v10.zip,,,,,v9-v10.zip)
然後,app根據自己的當前版本(比如V6),下載對應的增量包(V6-V10.zip)。
最後,app中通過 舊版本(v6) + 增量包(v6~v10.zip) = 新版本(v10) ,計算出了新版本的全量包。
增量算法
assets增量算法,比較簡單,就是比對,可以很容易的比較出新增的文件,和不同的文件(使用md5)。
bundle文件的增量算法,確實比較複雜,剛開始沒有什麼頭緒,後來在leader的指引下,很幸運的找到了google寫的一個開源的庫,可以對大字符串進行diff和patch,並且支持java、objc、js等等語言,完全的滿足了我們的需求。
只用到2個接口,具體請參考github上的文檔
- 生成增量包時候:patch_make(text1, text2) => patches
- app生成全量包時候:patch_apply(patches, text1) => [text2, results]
google開源庫地址:https://github.com/bystep15/google-diff-match-patch
codepush
微軟的codepush也做了類似的事情,不過由於以下原因,我們團隊沒敢使用其作爲解決方案。
- 其增量升級僅僅是針對圖片資源的
- 其升級服務器端程序並不開源
- 其升級服務器在美國,國內訪問很慢且不穩定
不過,codepush客戶端的源碼和文檔也給我們提供了很多思路,在此感謝codepush團隊。
codepush地址:http://microsoft.github.io/code-push/
bundle要求的app最小版本
本文中一般用min-v或者appMinV表示。
因爲js代碼是依賴於native代碼的,所以,jsbundle對app的版本有要求,所以有這個概念。
試想,如果bundle依賴了一個native的一個新的接口,這個接口在v3版本的app中才發佈,如果v2版本的app升級了這個bundle,那麼必然會報錯,嚴重的可能會導致app的崩潰。
系統結構設計與各模塊職責
bundle倉庫設計
存儲全量bundle和生成增量patch
node patch 命令
在bundle目錄下放入一個符合要求【參考目錄結構說明】的新版本目錄,比如0.3.0,然後執行以下命令。
命令:node patch 版本號 , 示例:node patch 0.3.0
-d參數: node patch 版本號 -d ,如果加入-d參數,會先刪除patch目錄下的對應版本目錄,然後進行patch生成
然後在patch目錄中就會生成0.3.0的增量包,同時patch目錄下的update.json文件也會重新生成.
node update.json 命令
在patch目錄下重新生成update.json文件
目錄結構說明
bundle 存放全量bundle和全量assets的目錄,裏面的文件基本上是使用react-native bundle命令生成的
0.1.0
略
0.2.0
android
略,同ios
ios
config.json 此版本的配置信息,包含要求app的最低版本等,手動配置
index.jsbundle 全量jsbundle文件,使用react-native bundle命令生成
assets 全量圖片目錄,使用react-native bundle命令生成
0.3.0
略
patch 存放增量補丁的目錄,裏面文件都是命令生成的,無需手動維護
0.1.0
第一版本無文件
0.2.0
android
略,同ios
ios
0.1.0-0.2.0.zip 增量包.zip
0.3.0
android
略,同ios
ios
0.1.0-0.3.0.zip 增量包.zip
0.2.0-0.3.0.zip 增量包.zip
update.json 所有的升級包信息
src 存放打包用的源碼
lib 存放打包用依賴的第三方的源碼
patch.js patch命令入口
update.json.js update.json命令入口
config.json示例
{
"v": "0.3.0", //版本
"min-v": "4.0.0", //此版本要求的最小app版本
"date": "2016-01-01", //打包日期
"des": [
"修復xxbug", "添加xx功能"
]
}
update.json示例
[
{
"v": "0.1.0",
"min-v": "4.0.0",
"date": "2016-01-01",
"des": [
"修復xxbug",
"添加xx功能"
],
"iosBundleMd5": "11f82563f8fd3f22dccb80ad2297f7bc",
"androidBundleMd5": "11f82563f8fd3f22dccb80ad2297f7bc"
},
{
"v": "0.2.0",
"min-v": "4.0.0",
"date": "2016-01-01",
"des": [
"修復xxbug",
"添加xx功能"
],
"iosBundleMd5": "3ca2824b008132cee515c0ea29938ff2",
"androidBundleMd5": "3ca2824b008132cee515c0ea29938ff2"
},
{
"v": "0.3.0",
"min-v": "4.0.0",
"date": "2016-01-01",
"des": [
"修復xxbug",
"添加xx功能"
],
"iosBundleMd5": "dbb81d2383112abb50eb19970c486acd",
"androidBundleMd5": "dbb81d2383112abb50eb19970c486acd"
}
]
升級服務器設計
接口patch/query
例如:http://localhost:3000/patch/query?bundleV=0.2.0&appV=4.0.0&platform=ios
此接口會有以下4個場景的使用情況,每個場景返回的json示例已經提供在後面文檔中。
輸入參數
```
bundleV : app中的bundle版本
appV : app版本
platform : app的平臺
```
返回json各項說明
- status : 本次請求後臺是否發生了錯誤
- msg : 給用戶看的中文提示信息,靜默升級時候沒什麼用
- latestBundleV : 當前的最新bundle版本
- latestAppMinV : 最新bundle要求的app最低版本
- canUpdate : 能否升級,boolean
- canUpdateBundleV : 能升級的bundle版本
- canUpdateAppMinV : 能升級的bundle要求的app最低版本
- patchUrl : 補丁包相對地址
- platform : 平臺:ios or android
場景1
能升級,且能升級到最新版
{
status: 'success',
msg: '可以升級,bundle最新版爲0.3.0',
latestBundleV: '0.3.0',
latestAppMinV: '4.0.0',
canUpdate: true,
canUpdateBundleV: '0.3.0',
canUpdateAppMinV: '4.0.0',
patchUrl: 'patch/0.3.0/ios/0.2.0-0.3.0.zip',
platform: 'ios'
}
場景2
無需升級,已經是最新版本
{
status: 'success',
msg: '無需升級,已經是最新版本',
canUpdate: false,
platform: 'ios'
}
場景3
能升級,能升級到當前appMinV的最新bundle版本,但不是最新的bundle,想升最新bundle,必須先升app
{
status: 'success',
msg: '可以升級,但app版本3.0.0太低,只能升到bundleV0.2.0,bundleV最新爲0.3.0',
latestBundleV: '0.3.0',
latestAppMinV: '4.0.0',
canUpdate: true,
canUpdateBundleV: '0.2.0',
canUpdateAppMinV: '3.0.0',
patchUrl: 'patch/0.2.0/ios/0.1.0-0.2.0.zip',
platform: 'ios'
}
場景4
不能升級,已經是當前appMinV的最新bundle,但不是最新的bundle,想升最新bundle,必須先升app
{
status: 'success',
msg: '不能升級,當前已經是app3.0.0的最新bundle了,但不是最新bundle0.3.0,想升級bundle到最新,請先升級app',
latestBundleV: '0.3.0',
latestAppMinV: '4.0.0',
canUpdate: false,
platform: 'ios'
}
native客戶端設計
客戶端的主要工作就是發請求到升級服務器詢問是否能升級,然後根據返回的信息,下載升級包,解壓升級包,安裝升級包。
過程中要保證下載的文件是正確的(md5校驗),要保證補丁安裝之後的全量bundle文件是正確的(md5校驗)。
整個過程用戶無感知。
此部分詳細設計後邊會補充。