JSPatch (實時修復App Store bug)學習(一)

JSPatch 是一個 iOS 動態更新框架,只需在項目中引入極小的引擎,就可以使用 JavaScript 調用任何 Objective-C 原生接口,獲得腳本語言的優勢:為項目動態添加模塊,或替換項目原生代碼動態修復 bug

基礎原理

JSPatch 能做到通過 JS 調用和改寫 OC 方法最根本的原因是 Objective-C 是動態語言,OC 上所有方法的調用/類的生成都通過 Objective-C Runtime 在運行時進行,我們可以通過類名/方法名反射得到相應的類和方法:

Class class = NSClassFromString("UIViewController");

id viewController = [[class alloc] init];

SEL selector = NSSelectorFromString("viewDidLoad");

[viewController performSelector:selector];

也可以替換某個類的方法為新的實現:

static void newViewDidLoad(id slf, SEL sel) {}

class_replaceMethod(class, selector, newViewDidLoad, @"");

還可以新注冊一個類,為類添加方法:

Class cls = objc_allocateClassPair(superCls, "JPObject", 0);

objc_registerClassPair(cls);

class_addMethod(cls, selector, implement, typedesc);

對于 Objective-C 對象模型和動態消息發送的原理已有很多文章闡述得很詳細,這里就不詳細闡述了。理論上你可以在運行時通過類名/方法名調用到任何 OC 方法,替換任何類的實現以及新增任意類。所以 JSPatch 的基本原理就是:JS 傳遞字符串給 OC,OC 通過 Runtime 接口調用和替換 OC 方法。這是最基礎的原理,實際實現過程還有很多怪要打,接下來看看具體是怎樣實現的。


JSPatch github地址 (iOSdemo 下載可以看到效果)

demo 的實現原理我用下面的一副圖來表示,邏輯更清晰,修復其他的bug 原理都差不多,只要你會寫JS 代碼 理論上是可以修復任何bug 的,還可以動態的為項目添加新的模塊

JSPatch demo的實現原理對比圖

demo 介紹:本來在一個控制器中添加一個btn,btn點擊事件沒有實現;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

//1)開啟引擎

[JPEngine startEngine];

NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"js"];

//2)加載js腳本(正常情況下是從服務器下載后才使用,達到動態修復app bug 的目的)

//在這個js 腳本里面使用運行時機制通過類名/方法名調用到任何 OC 方法,替換任何類的實現以及新增任意類,實際上調用了demo 中按鈕的點擊方法調到一個tableview控制器,demo 中Btn 的點擊跳轉到tableview的方法沒有實現,是app啟動的時候加載js,js實現了btn的點擊并且跳轉到tableview控制器,js到底是如何實現映射是呢?

NSString *script = [NSString stringWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil];

//執行js腳本

[JPEngine evaluateScript:script];

self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

JPViewController *rootViewController = [[JPViewController alloc] init];

UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];

self.window.rootViewController = navigationController;

[self.window makeKeyAndVisible];

[[UINavigationBar appearance] setBackgroundImage:nil forBarMetrics:UIBarMetricsCompact];

return YES;

}


JSPatch 實現熱更新app 修復線上app的bug 的核心是會寫js 腳本下面是js語言實現攔截按鈕的點擊事件 并且跳轉到一個TableView

defineClass('JPViewController', { ?handleBtn: function(sender) { ? ?var tableViewCtrl = JPTableViewController.alloc().init() ? ?self.navigationController().pushViewController_animated(tableViewCtrl, YES) ?}})defineClass('JPTableViewController : UITableViewController', ['data'], {

dataSource: function() {

var data = self.data();

if (data) return data;

var data = [];

for (var i = 0; i < 20; i ++) {

data.push("cell from js " + i);

}

self.setData(data)

return data;

},

numberOfSectionsInTableView: function(tableView) {

return 1;

},

tableView_numberOfRowsInSection: function(tableView, section) {

return self.dataSource().length;

},

tableView_cellForRowAtIndexPath: function(tableView, indexPath) {

var cell = tableView.dequeueReusableCellWithIdentifier("cell")

if (!cell) {

cell = require('UITableViewCell').alloc().initWithStyle_reuseIdentifier(0, "cell")

}

cell.textLabel().setText(self.dataSource()[indexPath.row()])

return cell

},

tableView_heightForRowAtIndexPath: function(tableView, indexPath) {

return 60

},

tableView_didSelectRowAtIndexPath: function(tableView, indexPath) {

var alertView = require('UIAlertView').alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles("Alert",self.dataSource()[indexPath.row()], self, "OK", ?null);

alertView.show()

},

alertView_willDismissWithButtonIndex: function(alertView, idx) {

console.log('click btn ' + alertView.buttonTitleAtIndex(idx).toJS())

}

})


參考文獻:

JSPatch 詳解整改版


______

- 作者開發經驗總結的文章推薦,持續更新學習心得筆記

[Runtime 10種用法(沒有比這更全的了)](http://www.lxweimin.com/p/3182646001d1)

[成為iOS頂尖高手,你必須來這里(這里有最好的開源項目和文章)](http://www.lxweimin.com/p/8dda0caf47ea)

[iOS逆向Reveal查看任意app 的界面](http://www.lxweimin.com/p/060745d5ecc2)

[JSPatch (實時修復App Store bug)學習(一)](http://www.lxweimin.com/p/344db07a2374)

[iOS 高級工程師是怎么進階的(補充版20+點)](http://www.lxweimin.com/p/1f2907512046)

[擴大按鈕(UIButton)點擊范圍(隨意方向擴展哦)](http://www.lxweimin.com/p/ce2d3191224f)

[最簡單的免證書真機調試(原創)](http://www.lxweimin.com/p/c724e6282819)

[通過分析微信app,學學如何使用@2x,@3x圖片](http://www.lxweimin.com/p/99f1f924ae45)

[TableView之MVVM與MVC之對比](http://www.lxweimin.com/p/d690b5d97201)

[使用MVVM減少控制器代碼實戰(減少56%)](http://www.lxweimin.com/p/f85363c82ea1)

[ReactiveCocoa添加cocoapods 配置圖文教程及坑總結](http://www.lxweimin.com/p/66f0c7e1ced8)

______

- 作者開發經驗總結的文章推薦,持續更新學習心得筆記

[Runtime 10種用法(沒有比這更全的了)](http://www.lxweimin.com/p/3182646001d1)

[成為iOS頂尖高手,你必須來這里(這里有最好的開源項目和文章)](http://www.lxweimin.com/p/8dda0caf47ea)

[iOS逆向Reveal查看任意app 的界面](http://www.lxweimin.com/p/060745d5ecc2)

[JSPatch (實時修復App Store bug)學習(一)](http://www.lxweimin.com/p/344db07a2374)

[iOS 高級工程師是怎么進階的(補充版20+點)](http://www.lxweimin.com/p/1f2907512046)

[擴大按鈕(UIButton)點擊范圍(隨意方向擴展哦)](http://www.lxweimin.com/p/ce2d3191224f)

[最簡單的免證書真機調試(原創)](http://www.lxweimin.com/p/c724e6282819)

[通過分析微信app,學學如何使用@2x,@3x圖片](http://www.lxweimin.com/p/99f1f924ae45)

[TableView之MVVM與MVC之對比](http://www.lxweimin.com/p/d690b5d97201)

[使用MVVM減少控制器代碼實戰(減少56%)](http://www.lxweimin.com/p/f85363c82ea1)

[ReactiveCocoa添加cocoapods 配置圖文教程及坑總結](http://www.lxweimin.com/p/66f0c7e1ced8)


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

推薦閱讀更多精彩內容