背景介紹
IOS平臺提交審核的周期太長,快則45天,慢則半個月或者20天,如果碰到圣誕節等假日,可能一個月都有可能,如果碰到被拒,那就更坑爹了,那時基本靠人品。現在蘋果的審核周期變短了,有可能是12天審核就通過了,具體是不是以后都是這么快,就不清楚了。
JSPatch利用javascript調用任何Objective-C原生接口,替換任意的Objective-C原生接口,修復線上bug。主要通過下發JS腳本替換原生Objective-C代碼。
JSPatch:GitHub地址
SDK接入
準備
該demo的GitHub地址
-
在JSPatch平臺上注冊賬號,添加新App,會生成唯一AppKey
- 在該平臺下載SDK解壓后將JSPatch.framework拖入項目
- 添加依賴框架libz.dylib和JavaScriptCore.framework
添加代碼
在AppDelegate.m的didFinishLaunchingWithOptions中添加如下代碼:
//添加頭文件
#import <JSPatch/JSPatch.h>
//1
[JSPatch startWithAppKey:JSPatchKey] //JSPatchKey是創建App獲得的AppKey
//2
[JSPatch sync]
//1中startWithAppKey傳入平臺申請的appKey,啟動JSPatch SDK,同時會自動執行已下載到本地的patch.
//2中sync與JSPatch平臺后臺更新,詢問是否有patch更新,如果有更新會自動下載并執行。startWithAppKey并不會詢問后臺patch更新,必須調用sync方法。
注意:實時性不高的App只需在didFinishLaunchingWithOptions處調用一次,用戶啟動時就會同步patch信息;實時性要求高的App,在applicationDidBecomeActive處調用,用戶每次喚醒App時就同步一次后臺
測試本地腳本
在上線之前需要對腳本進行本地測試查看運行是否正常,注意JSPatch平臺規范,JS腳本文件名必須是main.js。SDK提供了方法+testScriptInBundle用于發布前測試,調用該方法后,JSPatch會在當前項目的bundle尋找main.js。
注意:+testScriptInBundle不能與+startWithAppKey一起調用,+testScriptInBundle只能用于本地測試,測試完需刪除
Demo本地實例
新建一個工程,在Main.storyboard中添加UITableView,并添加相應約束,具體如圖,設置距離上下左右的距離都是0:
設置好tableView的delegate和dataSource之后,在ViewController中定義一個數組,并初始化:
self.dataArray = [NSMutableArray arrayWithObjects:@"one",@"two",@"three",@"four",@"five", nil];
之后設置tableView的相關委托代理的方法,如下:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 5;
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString* cellIdentifier=@"cell";
UITableViewCell* cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell==nil) {
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text=[self.dataArray objectAtIndex:indexPath.row];
return cell;
}
運行結果如下:
OK,Done!一切看起來非常好。
動手修改Demo
在numberOfRowsInSection方法中,替換 return 5
為 return 6
,如下:
// return 5;
return 6; //超出dataArray的數組范圍
這樣在cellForRowAtIndexPath方法中獲取數組中的數據就會超出范圍,因為數組中只有5條數據,而我們返回了6行,少了一行。如果這種錯誤出現在線上版本導致App崩潰,那上傳新版本的話,耗時比較長,所以我們現在用JSPatch來解決。
按照我們上面講的到JSPatch官網下載SDK,然后把JSPatch.framework拖入項目中
-
添加JavaScriptCore.framework和libz.tbd依賴框架(tbd是xcode7新增的一種文件)
-
AppDelegate中添加JSPatch/JSPatch.h頭文件,在didFinishLaunchingWithOptions中輸入:
[JSPatch startWithAppKey:JSPatchKey]; [JSPatch sync];
由于我們這個不是線上產品,只是在本地測試,所以我們注釋掉該代碼,替換為
JSPatch testScriptInBundle
,注意該行代碼測試完本地之后需刪除。-
通過vi編寫main.js,也可以用其他的編輯器
defineClass("ViewController", { tableView_cellForRowAtIndexPath: function(tableView, indexPath) { var cell = tableView.dequeueReusableCellWithIdentifier("cell") if (!cell) { cell = require('UITableViewCell').alloc().initWithStyle_reuseIdentifier(0, "cell") } cell.textLabel().setText("1") return cell },
}
)
```
我只是把ViewController中的cellForRowAtIndexPath中每行顯示的數據顯示為1,這樣就可以避免崩潰了,當然根據自己的需要自行修改,具體可以參考JSPatch基礎用法。結果如下:
線上版本
-
進入JSPatch平臺后臺,在我的App中添加App版本
該版本號可以通過項目TARGETS->General->version找到。版本號必須一致,JSPatch平臺只對該版本號下發js腳本。
- 點擊剛添加的版本,上傳main.js即可。上傳可以直接全量下發,也可選擇開發預覽或灰度或條件下發,也可以使用自定義RSA key對腳本進行加密簽名。上傳完成后,對應版本App會請求下載腳本保持到本地,這樣線上bug就修復了
- 若后續需要對這個腳本進行修改,可以重新上傳,App客戶端會在請求時發現腳本已更新,下載最新腳本覆蓋原來的,下次啟動時執行。想直接取消某個App版本的JS腳本,直接在App版本界面刪除此App版本,App客戶端請求時發現腳本已被刪除,即可刪除本地js腳本,下次啟動不再加載。
開發預覽
從SDK1.4支持發布腳本時先針對開發版本下發。
首先開啟開發模式,建議只在debug模式下開啟。
[JSPatch startAppWithKey:JSPatchKey]
#ifdef DEBUG
[JSPatch setupDevelopment]
#endif
[JSPatch sync]
接著在圖中下發:
灰度和條件下發
-
灰度:SDK1.2以上,按比例下發,可以修改灰度值,直至全量下發
-
條件下發:只有滿足條件設備才會執行,可以通過條件語句規則篩選。需要事先通過+setupUserData,支持多個字段,用NSDictionary表示,比如:
[JSPatch setupUserData:@{@"userID":userID,@"isMale":isMale}]
,需要在setupWithAppKey之前調用。
條件更新:后面的條件更新不會影響之前的條件,之前的條件依然滿足。想撤銷條件全量發布,提交空條件即可。SDK內置2個信息可供條件判斷:iOS和isPad,iOS版本號只會精確到2位。
自定義RSA密鑰和安全問題
為避免js腳本傳輸過程被中間人篡改,我們需要對js文件進行RSA簽名加密,具體流程:
- 服務端
- 計算js文件MD5值
- 用RSA私鑰對MD值加密,與JS文件一起下發給客戶端
- 客服端
- 拿到加密數據,用RSA公鑰解密出MD5值
- 本地計算返回的js文件MD5值
- 對比2個MD5值,相等則校驗通過,保存JS文件到本地
當保存到本地時,越獄機器會有點風險,我們可以通過對稱加密保存,然后讀取時解密。
客戶端和JSPatch后臺默認有一對RSA密鑰,默認會對這對密鑰進行加解密驗證。也可以自定義RSA密鑰。
自定義RSA密鑰
-
生成RSA密鑰。在終端輸入下列代碼后再當前目錄就有rsa_private_key.pem和rsa_public_key.pem。密鑰長度可選1024/2048/3072/4096...
openssl > genrsa -out rsa_private_key.pem 1024 pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
SDK設置RSA Public Key。客戶端接入SDK后調用
+setupRSAPublicKey:
設置定義的RSA Public Key,必須在+sync
之前調用。Public Key以字符串方式傳入,換行處需要手動加換行符\n。使用Private Key下發腳本。下發腳本時勾選使用自定義RSA Key 選項,選擇本地的rsa_private_key.pem與腳本一起上傳。JSPatch平臺使用上傳的Private Key對腳本MD5值進行加密,然后下發客戶端。客戶端通過第二部設置的Public Key對腳本進行驗證,通過則運行。注意:上傳的rsa_private_key.pem只是一次性使用,用戶必須保存rsa_private_key.pem文件
相關
JSPatch官網:http://www.jspatch.com/
總結
JSPatch的介紹就到此為止,歡迎指正,謝謝!!!