JSPatch (實時修復(fù)App Store bug)學(xué)習(xí)(一)

JSPatch 是一個 iOS 動態(tài)更新框架梨睁,只需在項目中引入極小的引擎,就可以使用 JavaScript 調(diào)用任何 Objective-C 原生接口,獲得腳本語言的優(yōu)勢:為項目動態(tài)添加模塊,或替換項目原生代碼動態(tài)修復(fù) bug峻仇。

基礎(chǔ)原理

JSPatch 能做到通過 JS 調(diào)用和改寫 OC 方法最根本的原因是 Objective-C 是動態(tài)語言,OC 上所有方法的調(diào)用/類的生成都通過 Objective-C Runtime 在運行時進(jìn)行票顾,我們可以通過類名/方法名反射得到相應(yīng)的類和方法:

Class class = NSClassFromString("UIViewController");

id viewController = [[class alloc] init];

SEL selector = NSSelectorFromString("viewDidLoad");

[viewController performSelector:selector];

也可以替換某個類的方法為新的實現(xiàn):

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 對象模型和動態(tài)消息發(fā)送的原理已有很多文章闡述得很詳細(xì),這里就不詳細(xì)闡述了奠骄。理論上你可以在運行時通過類名/方法名調(diào)用到任何 OC 方法豆同,替換任何類的實現(xiàn)以及新增任意類。所以 JSPatch 的基本原理就是:JS 傳遞字符串給 OC含鳞,OC 通過 Runtime 接口調(diào)用和替換 OC 方法影锈。這是最基礎(chǔ)的原理,實際實現(xiàn)過程還有很多怪要打,接下來看看具體是怎樣實現(xiàn)的鸭廷。


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

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

JSPatch demo的實現(xiàn)原理對比圖

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

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

//1)開啟引擎

[JPEngine startEngine];

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

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

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

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

//執(zhí)行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 實現(xiàn)熱更新app 修復(fù)線上app的bug 的核心是會寫js 腳本下面是js語言實現(xiàn)攔截按鈕的點擊事件 并且跳轉(zhuǎn)到一個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())

}

})


參考文獻(xiàn):

JSPatch 詳解整改版


______

- 作者開發(fā)經(jīng)驗總結(jié)的文章推薦,持續(xù)更新學(xué)習(xí)心得筆記

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

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

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

[JSPatch (實時修復(fù)App Store bug)學(xué)習(xí)(一)](http://www.reibang.com/p/344db07a2374)

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

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

[最簡單的免證書真機(jī)調(diào)試(原創(chuàng))](http://www.reibang.com/p/c724e6282819)

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

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

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

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

______

- 作者開發(fā)經(jīng)驗總結(jié)的文章推薦,持續(xù)更新學(xué)習(xí)心得筆記

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

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

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

[JSPatch (實時修復(fù)App Store bug)學(xué)習(xí)(一)](http://www.reibang.com/p/344db07a2374)

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

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

[最簡單的免證書真機(jī)調(diào)試(原創(chuàng))](http://www.reibang.com/p/c724e6282819)

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

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

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

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


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末佳晶,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子讼载,更是在濱河造成了極大的恐慌轿秧,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咨堤,死亡現(xiàn)場離奇詭異菇篡,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)一喘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進(jìn)店門驱还,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人凸克,你說我怎么就攤上這事议蟆。” “怎么了触徐?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵咪鲜,是天一觀的道長。 經(jīng)常有香客問我撞鹉,道長,這世上最難降的妖魔是什么颖侄? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任鸟雏,我火速辦了婚禮,結(jié)果婚禮上览祖,老公的妹妹穿的比我還像新娘孝鹊。我一直安慰自己,他們只是感情好展蒂,可當(dāng)我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布又活。 她就那樣靜靜地躺著,像睡著了一般锰悼。 火紅的嫁衣襯著肌膚如雪柳骄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天箕般,我揣著相機(jī)與錄音耐薯,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛曲初,可吹牛的內(nèi)容都是我干的体谒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼臼婆,長吁一口氣:“原來是場噩夢啊……” “哼抒痒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起颁褂,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤故响,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后痢虹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體被去,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年奖唯,在試婚紗的時候發(fā)現(xiàn)自己被綠了惨缆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡丰捷,死狀恐怖坯墨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情病往,我是刑警寧澤捣染,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站停巷,受9級特大地震影響耍攘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜畔勤,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一蕾各、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧庆揪,春花似錦式曲、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至内颗,卻和暖如春钧排,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背起暮。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工卖氨, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留会烙,地道東北人。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓筒捺,卻偏偏與公主長得像柏腻,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子系吭,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容