利用JSPatch跳過AppStore稽核,動態更新APP
hotfix的作用眾所周知,Android和iOS都有各自的技術,但是相比Android的當天釋出來說(如果你們的專案不需要灰度),iOS熱更新的意義更加重大。因為iOS稽核週期長不說,而且運氣不好會遇到各種被拒,即使申請快速稽核,也必須滿足二者之一:能夠準確的告訴蘋果復現crash的步驟,或者在特殊節日附近。 可能你費勁周折的提心吊膽和那麼多天其實也就是在某個類中加三行程式碼。
1.簡單介紹
在沒有JSPatch之前,可能有人會使用過JSCocoa。但是有著一系列複雜問題,比如原始碼已經多年沒有維護,程式碼規模巨大,不支援ARM64。如果想使用還需要升級libffi,並且嘗試相容ARM64,想編譯通過都很困難。
JSPatch的出現基本解決了上述所有問題。在一個專案中接入JSPatch的成本很低,需要動點腦筋的可能就是如何合理的提交和下載。
關於JSPatch的原理作者的部落格已經說的很清楚,本文不再說明,本文主要說的時一些接入操作相關。
如果你不是在董鉑然部落格園看到本文可點選檢視原文。
2.倉庫設定
js檔案肯定不能隨便往後臺某個資料夾一放就讓前端去下載了,雖然使用方便但是在App或者版本較多時容易混亂。建議專門搭建一個遠端倉庫,倉庫裡主要就是資料夾和js檔案,當需要提交js檔案時,從主幹遷出一個分支,在合適的地方新建資料夾並新增js檔案,然後給主幹提Pull Request, 這應該是一個麻煩但是規範的流程。資料夾結構參考下圖:
第三層資料夾裡,可以用版本名稱也可以使用build號。之後在發請求下載的時候應該是需要拼上專案appname,version等引數。
3.安全策略
安全相關工作如果沒有做好,最慘的情況是人家可以通過js檔案呼叫你的任何OC方法,我們肯定不能允許此類事情發生。一般在js檔案提交到倉庫以後後端應該對這一段js程式碼進行 md5或者更高手段的編碼,並將這段編碼與檔案存在一起,上圖中得meta.json裡存的就是這一段編碼。 之後在發請求的返回值的結構應該是大致如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{
data:
{
isUpdate: true ,
content:
"require( 'MTPoiFeedbackM' )
defineClass( 'MTFeedbackRankCell' ,{
setPoiFeedback:function(poiFeedback){
self .ORIGsetPoiFeedback(poiFeedback)
var
temColor = require( 'UIColor' ).lightGrayColor();
self .detailLbl().setTextColor(temColor);
}
})",
code: "9c944f39e57f2e50bdb85deb878cc0f798efb9b0"
}
}
|
就是首先有個欄位告訴我們較上次下載的js檔案是否有更新。如果為true再檢測下方返回的code與內容編碼後得到的code是否相同。當然這個內容也可以不直接返回而是返回一個下載的url也是完全可以的。
4.更新頻率
我之前看到很多人把使用js和下載js的程式碼都放在了didFinishLaunchingWithOptions:這個方法。我覺得有所不妥,因為如果這個app使用者一直放在手機的後臺(比如微信),並且也沒出現記憶體警告的話,這個方法應該一直不會呼叫。我建議的是:使用js檔案的程式碼放在didFinishLaunchingWithOptions: 而下載js檔案的程式碼放在applicationDidBecomeActive: 因為這個方法在程式啟動和後臺回到前臺時都會呼叫。並且我建議設定一個間隔時間,根據一些資料和權衡之後我們採用的是間隔時間設為1小時。 也就是說每次來到這個方法時,先要檢測是距離上次發請求的時間間隔是否超過1小時,超過則發請求,否則跳過。
5.接入流程
接入的方式很簡單,作者也提供了Demo程式,大致就分為幾步:
①在General 的 LinkFrameworks and Libraries裡面 新增javascriptcore.framework
這個庫裡主要用於js與oc語言的橋接,比如一些資料型別間的相互轉化。
②podfile新增 pod 'JSPatch' 並pod install
③在程式碼中新增使用js和下載js的程式碼
這裡作者也給出了示例,使用和下載
1 2 3 4 |
[JPEngine
startEngine];
NSString *sourcePath
= [[ NSBundle mainBundle]
pathForResource:@ "demo" ofType:@ "js" ];
NSString *script
= [ NSString stringWithContentsOfFile:sourcePath
encoding: NSUTF8StringEncoding error: nil ];
[JPEngine
evaluateScript:script];
|
1 2 3 4 |
[ NSURLConnection sendAsynchronousRequest:[
|