JSPatch 從入門到放棄

JSPatch 是什么

JSPatch 是一個開源項目(Github鏈接),只需要在項目里引入極小的引擎文件,就可以使用 JavaScript 調用任何 Objective-C 的原生接口,替換任意 Objective-C 原生方法。目前主要用于下發 JS 腳本替換原生 Objective-C 代碼,實時修復線上 bug。

JSPatch平臺又是什么鬼

JSPatch需要你自己搞一個服務器管理、下發腳本,還要處理安全問題,高并發問題,煩死你。JSPatch平臺封裝了SDK,你只需要繼承SDK就可以省去一堆的麻煩。

JSPatch 需要使用者有一個后臺可以下發和管理腳本,并且需要處理傳輸安全等部署工作,JSPatch 平臺幫你做了這些事,提供了腳本后臺托管,版本管理,保證傳輸安全等功能,讓你無需搭建一個后臺,無需關心部署操作,只需引入一個 SDK 即可立即使用 JSPatch。

JSPatch 平臺的 SDK 在核心代碼的基礎上增加了向平臺請求腳本/傳輸解密/版本管理等功能,只用于這個平臺。

通過 JSPatch 平臺上傳的腳本文件都會保存在七牛云存儲上,客戶端 APP 只跟七牛服務器通訊,支持高并發,CDN分布全國,速度和穩定性有保證。

SDK接入

這種問題不要問我,注冊一個賬號,建一個app獲取到appid,然后接入SDK完事兒。至于你是用cocoapods還是手動接入,全憑個人喜好。SDK接入

API主要方法

+startWithAppKey:

傳入在平臺申請的 appKey,啟動 JSPatch SDK。在-application:didFinishLaunchingWithOptions:開頭初始化第三方庫的時候一并調用初始化。

+sync

與 JSPatch 平臺后臺同步,詢問是否有 patch 更新,如果有更新會自動下載并執行。

每調用一次 +sync 就會請求一次后臺,如果app啟動的時候檢查一次就OK的話就在-application:didFinishLaunchingWithOptions:調用一次。

如果實時性要求高,就在-applicationDidBecomeActive:的時候調用。

+setupLogger:

SDK打一些請求和執行的log,默認是NSLog()輸出,如果app有自己的日志系統,并且希望自己的日志系統拿到這些log,則在+startWithAppKey之前調用這個方法。

+testScriptInBundle

寫好的腳本上線前總要測試一下吧,就是用這個方法。需要把main.js文件拖到項目中,并且不要調用+startWithAppKey:方法。

注意?。。。簻y試完成一定要刪除main.js,血淋淋的教訓是,如果不刪除,線上的腳本down下來之后,無法確定會執行哪個main.js,莫名其妙的問題,并且很難找到。切記切記

+setupCallback:

JSPatch 執行過程中的事件回調,在以下事件發生時會調用傳入的 block:

typedef NS_ENUM(NSInteger, JPCallbackType){
    JPCallbackTypeUnknow        = 0,
    JPCallbackTypeRunScript     = 1,    //執行腳本
    JPCallbackTypeUpdate        = 2,    //腳本有更新
    JPCallbackTypeUpdateDone    = 3,    //已拉取新腳本
    JPCallbackTypeCondition     = 4,    //條件下發
    JPCallbackTypeGray          = 5,    //灰度下發
};

例如
[JSPatch setupCallback:^(JPCallbackType type, NSDictionary *data, NSError *error) {
    switch (type) {
        case JPCallbackTypeUpdate: {
            NSLog(@"updated %@ %@", data, error);
            break;
        }
        case JPCallbackTypeRunScript: {
            NSLog(@"run script %@ %@", data, error);
            break;
        }
        default:
            break;
    }
}];

+setupUserData:

定義用戶屬性,在+sync:之前調用,用于條件下發,可以用來做AB測試。什么是AB測試?自己去Google啊...

[JSPatch setupUserData:@{
    @"userId": user.userId, 
    @"location": user.location,
    @"gender":user.gender,
    @"age":user.age
}];
條件下發
條件下發

發布補丁的時候選擇條件下發,寫入相應的條件就可以實現條件下發。例如圖中性別是女,年齡小于35歲的用戶顯示特定的內容。還可以選擇手機系統的版本。

+setupDevelopment

開發者預覽模式,可以在 debug 模式下測試補丁效果。

[JSPatch startAppWithKey:@""];
#ifdef DEBUG
[JSPatch setupDevelopment];
#endif
[JSPatch sync];

灰度下發

這個功能太實用了,選擇灰度下發可以按照比例灰度人數灰度下發。比例灰度例如隨機挑選 30% 的設備生效;人數灰度比如只安裝1000臺設備。應用場景:

  1. 先下發一批看看效果,如果OK就全量下發
  2. 只對部分用戶下發,顯示特定的效果(和條件下發類似)

實戰

扯了這么多終于到實戰了。

背景:

  • 項目已經集成了SDK
  • 注冊過了平臺賬號
  • 已經注冊了APP獲得了appkey
  • 已經上線了集成過JSPatch SDK的app
  • 這個上線的版本出現了大量的crash,crash率很高,不馬上解決,老板就會馬上解決你...

線上的代碼是這樣的,數組訪問越界了

@implementation DSHomeViewController

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  NSString *content = self.dataSource[[indexPath row]]; //可能會超出數組范圍導致crash
  DSGoodsViewController *controller = [[DSGoodsViewController alloc] initWithContent:content];
  [self.navigationController pushViewController:controller];
}

@end

修改源代碼

修改后的代碼

@implementation DSHomeViewController

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  if(self.dataSource.length > indexPath.row){
    NSString *content = self.dataSource[indexPath.row]; 
    DSGoodsViewController *controller = [[DSGoodsViewController alloc] initWithContent:content];
    [self.navigationController pushViewController:controller];
  }
}

@end

編寫補丁腳本

打開JSPatch代碼轉換器,原生代碼轉化為JS代碼

轉化器
轉化器

轉化成功了,但是要數組,需要修改一下。常見問題 修改之后的腳本,為了能夠知道腳本運行,第一行加上log

console.log('JSPatch Run Success');
require("DSGoodsViewController");

defineClass("DSHomeViewController", {
    tableView_didSelectRowAtIndexPath: function(tableView, indexPath) {
        var row = indexPath.row();
        if (self.dataSource().length() > row) {
            var content = self.dataSource()[row];
            var controller = DSGoodsViewController.alloc().initWithContent(content);
            self.navigationController().pushViewController(controller);
        }
    }
}, {});

測試腳本

寫好之后的腳本存為main.js放到項目中,在-application:didFinishLaunchingWithOptions:方法中打開測試

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
     //[JSPatch startWithAppKey:myAPPKey];
    //[JSPatch sync];
    [JSPatch testScriptInBundle];
    ….
}

編譯運行會看到控制臺log輸出JSPatch Run Success 然后......怎么能少了調試呢

在Safari中斷點調試

開啟 Safari 調試菜單

Safari -> 偏好設置 -> 高級 -> 勾選[在菜單欄中顯示“開發”菜單]

啟動app進行調試

啟動APP -> Safari -> 開發 -> 選擇你的機器 -> JSContext

在 iOS8 下,JSPatch 支持使用 Safari 自帶的調試工具對 JS 腳本進行斷點調試,界面大致長這樣


JS調試器
JS調試器

上傳腳本

  1. 在平臺上新建一個線上的版本
  2. 把調試通過的腳本main.js上傳到這個線上的版本
  3. 選擇全量下發(因為要搞定crash)
  4. 刪除本地的main.js
  5. 好了,等著下發之后crash率降下來,飯碗保住了

常見的問題

  1. 不能用 NSLog('xx'),應該用 console.log('xx')
  2. get property 記得加括號,例如 self.navigationItem(),而不是 self.navigationItem
  3. 私有成員變量要用 self.valueForKey()self.setValue_forKey() 接口存取
  4. block 里不能直接使用 self,應該在block外定義var myself = self;

其他更多請參見 wiki 的 基礎用法常見問題

未完待續。。。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 背景介紹 IOS平臺提交審核的周期太長,快則45天,慢則半個月或者20天,如果碰到圣誕節等假日,可能一個月都有可能...
    恒源賓館閱讀 2,277評論 10 27
  • JSPatch 是騰訊微信團隊牛人bang開源的一種通過JavaScript調用iOS原生代碼來實現熱修復或者動態...
    杭研融合通信iOS閱讀 889評論 2 23
  • JSPatch作為熱更新技術的黑科技,已經不是什么前沿的新聞了,像騰訊、美團等大公司也在使用JSPatch。前段時...
    任爾東西南北瘋閱讀 1,546評論 0 3
  • JSPatch簡介 JSPatch 是一個開源項目(Github鏈接),只需要在項目里引入極小的引擎文件,就可以使...
    zyl04401閱讀 2,272評論 0 6
  • 最近接觸到熱修復, 確實能解燃眉之急, 非常好用, 故分享給大家. 這里只講 JSPatch, 這個是現在最熱門最...
    Cean16閱讀 1,500評論 2 4