iOS熱修復方案可行性研究以及Aspects修復方案的實踐

前言:

伴隨著企業的快速發展,承載著移動互聯網業務的App的更新迭代要求越來越高。尤其是在中國,App的迭代速度很快,有時App需要緊急發版來處理線上業務和技術等問題。由于Apple審核制度的限制,在Apple提速了審核速度的情況下,大多數App審核往往需要1到2天。但是這仍舊無法滿足App快速更新的需求。所以,想不通過發版,解決線上問題的方案一直為iOS端技術研發人員所青睞。

但是隨著公開版本的JSPatch被Apple拒絕。熱更新這個概念似乎冷了下來。但是App更新與審核速度的矛盾從沒有解決。分析、構思,探索和找尋解決這個問題的合理方案。

理論可行性分析:

查閱了幾種熱更新的方案,JSPatch、Aspects、Stringer、TTPatch。分別對其實現原理、上架審核現狀以及文檔和資料完備性等方面進行分析。

拒絕JSPatch:

關于Apple拒絕JSPath事件的分析。

Apple對于App的開發傾向于Native。但是拒絕JSPatch并不是因為其使用了JS動態下發代碼,而是因為這種方式存在著安全漏洞。可能被第三方篡改造成隱患。正式因為這樣,所以在市面上滴滴出行App仍舊存在熱更新。從一些資料上看到,滴滴的方案是從技術層面上對于下發的JS代碼做了安全性校驗。使得滴滴的App能夠識別這些JS是由滴滴下發的。從而避免了Apple拒絕JSPatch熱更新的安全漏洞。所以,重要的是安全性。而不是熱更新的手段。

關于Aspects方案:

Aspects的原理與消息轉發機制密切相關。Aspects主要是利用了forwardInvocation進行轉發,Aspects其實利用和kvo類似的原理,通過動態創建子類的方式,把對應的對象isa指針指向創建的子類,然后把子類的forwardInvocation的IMP替成__ASPECTS_ARE_BEING_CALLED__,假設要hook的方法名XX,在子類中添加一個Aspects_XX的方法,然后將Aspects_XX的IMP指向原來的XX方法的IMP,這樣方便后面調用原始的方法,再把要hook的方法XX的IMP指向_objc_msgForward,這樣就進入了消息轉發流程,而forwardInvocation的IMP被替換成了__ASPECTS_ARE_BEING_CALLED__,這樣就會進入__ASPECTS_ARE_BEING_CALLED__進行攔截處理,這樣整個流程大概結束。

關于Stringer方案:

雖然Stringer聲稱速度快又好,但是怎奈查看github庫,當前開發版本號是0.3.0,可以認為是還不夠成熟。并且其公開文檔、資料極少。Demo也不完備。這給實際應用帶來了麻煩。

綜合分析:

于是有了滴滴的 DynamicCocoa 這種方案,繞了一個更大的道,從編譯階段入手,通過 clang 把 OC 代碼編譯成自己定制的 JS 格式,再動態下發去執行,做到原生開發,動態運行,主打動態添加功能,當然順便把修 bug 也給支持了。手機 QQ 內部也有一個類似的方案,不過更進一步,他們通過 clang 把 OC 代碼編譯成自己定制的字節碼動態下發,然后開發一個虛擬機去執行(驚呆了),同樣實現了原生開發,動態運行,都是 NB 得很的方案。只要底層處理做得足夠好,也是個成本低收益高的方案,不過目前都還沒開源,還沒能看到實際效果和可靠的源碼。

綜合查閱以上幾個熱更新方案,遴選出Aspects方案。原因是,此方案可以實現需要的代碼修復功能,而且Aspects庫與iOS庫相關。這可以作為通過審核的有力依據。

This is stable and used in hundreds of apps since it’s part of PSPDFKit,

an iOS PDF framework that ships with apps like Dropbox or Evernote.

綜上如果你是企業賬號那么方案就是JSPatch 1.7.2版本加自己管理補丁,因為他這個平臺超過1萬會收費.但是人家js轉OC的代碼轉換器都有了開發成本很低的。

如果是需要上架的App,并且團隊的后臺安全性沒有得到充分保證的情況下,Aspects是穩妥的方案。

Aspects深入分析:

理論分析--面向切面(AOP)編程:

通過預編譯和運行期動態代理實現給程序動態統一添加功能的一種技術。可以實現不修改原始類的實現無入侵式改變應用行為,相對來講,實現簡單,易于維護。可以在需要的某一個類或實例中添加一些我們自己的實現,只針對某個切面進行Hook操作,這個就是面向切面的概念(AOP,aspect-oriented programming),框架Aspects是 AOP 編程的框架。

AOP是采用使用運行時hook方法實現的原理(iOS的消息轉發、swzziling)。

Aspects可以做什么:

AOP在開發中是一個非常重要的思想,我們希望將需求分離到非業務邏輯的方法中,盡可能的不影響業務邏輯的代碼。主要的應用場景大概有以下幾種:

參數校驗:網絡請求前的參數校驗,返回數據的格式校驗等等;

無痕埋點:統一處理埋點,降低代碼耦合度;

頁面統計:幫助統計頁面訪問量;

事務處理:攔截指定事件,添加觸發事件;

異常處理:發生異常時使用面向切面的方式進行處理;

熱修復:AOP可以讓我們在某方法執行前后或者直接替換為另一段代碼,我們可以根據這個思路,實現bug修復.

Aspects使用注意事項:

會有額外的系統開銷,要避免高頻調用。hook方法不能修改 @"retain", @"release", @"autorelease", @"forwardInvocation:"。hook類中的dealloc方法只能AspectPositionBefore。Aspects會產生額外開銷,性能不高,不建議高頻調用。

關于封裝庫的使用經驗:

JS替換實例方法會覆蓋原類和其分類的方法實現。注意有返回值和無返回值JS方法的靈活運用。注意無參數、有參數、多參數JS方法的調用。JS方法同樣可以修改某一類中代理方法的實現。與一般方法相同。JS修改方法,可以獲得上下文,參數,方法名。可以根據具體需要來進行邏輯處理。

部分JS代碼:

fixInstanceMethodAfter('UBTestViewController', 'initViewLayout', function(instance, originInvocation, originArguments){

? ? //runVoidInstanceWithNoParamter(instance, 'showProgressForCommit');

? ? //runVoidInstanceWith1Paramter(instance, 'showText:','這是熱更新測試');//替換某個方法,為該類的已有方法

? ? //下面是用JS語法設置OC的實例對象

? ? var coffeeVo = runClassWithNoParamter('UBCoffeeModel', 'new');

? ? runVoidInstanceWith1Paramter(coffeeVo, 'setBrand:','luckin');

? ? runVoidInstanceWith1Paramter(coffeeVo, 'setPrice:','16');

? ? runVoidInstanceWith1Paramter(instance, 'setCoffee:',coffeeVo);

? ? //runVoidInstanceWith2Paramter(instance, 'resetMyCoffee::',coffeeVo);

? ? console.log('這是熱更新測試 替換方法驗證##');

});

對于block可以參考如下代碼。

//參數作為方法的參數,在JS中的調用(makeMyCoffeeComplete:的參數在原OC實現是一個block)

fixInstanceMethodReplace('UBTestViewController', 'makeMyCoffeeComplete:', function(instance, originInvocation, originArguments){

? ? if (originArguments[0]) {//取出參數,這里在對應的OC中,這個參數是block也就是function

? ? ? ? var callback = originArguments[0];

? ? ? ? callback(20);//block? 作為參數,直接調用

? ? }

? ? console.log('這是熱更新測試 替換block方法驗證##' + originArguments[0]);

});

部分對Aspects的封裝代碼(借鑒了網上搜到的信息):

+ (void)_runVoidInstanceWithInstance:(id)instance selector:(NSString *)selector obj1:(id)obj1 obj2:(id)obj2 {

#pragma clang diagnostic push

#pragma clang diagnostic ignored "-Warc-performSelector-leaks"

? ? [instance performSelector:NSSelectorFromString(selector) withObject:obj1 withObject:obj2];

#pragma clang diagnostic pop

}

+ (void)_runVoidInstanceWithInstance:(id)instance selector:(NSString *)selector withObjects:(NSArray *)objects {

#pragma clang diagnostic push

#pragma clang diagnostic ignored "-Warc-performSelector-leaks"

? ? [[UBFreeFixManger sharedInstance] performSelector:NSSelectorFromString(selector) target:instance? withObjects:objects];

#pragma clang diagnostic pop

}

+ (void)_runVoidInstanceWithInstance:(id)instance selector:(NSString *)selector {

#pragma clang diagnostic push

#pragma clang diagnostic ignored "-Warc-performSelector-leaks"

? ? [instance performSelector:NSSelectorFromString(selector)];

#pragma clang diagnostic pop

}

特別的,基于Aspects的熱修復,其目的是“熱修復”,也僅僅是熱修復。不建議通過這種方式隨意修改一般功能邏輯。我想這也是基于Aspects的熱修復能得到Apple認可的原因。

以上可行性分析很多資料借鑒和來源于網絡,Aspects方案經過筆者仔細實踐。Demo源碼可以留言索取。

參考資料:

1、TTPatch【類JSPatch】<有成功案例、JS代碼下發,轉成原生代碼>

《TTPatch使用》

http://www.lxweimin.com/p/470a9e49b4f2

2、iOS中OC轉Javascript的工具

https://blog.csdn.net/u013602835/article/details/52777461

3、Aspects<數百成功案例、JS代碼下發,轉成原生代碼>

http://www.lxweimin.com/p/2c93446d86bd

4、《iOS AOP框架Aspects實現原理》

http://www.lxweimin.com/p/0d43db446c5b

5、《輕量級低風險 iOS 熱更新方案》

https://mp.weixin.qq.com/s/2re_s3NmOvE9RXlbGQqGDA

6、《iOSHotFixDemo

https://github.com/3KK3/iOSHotFixDemo/tree/master/iOSHotFixDemo

7、《OS 2020 熱更新》

https://blog.csdn.net/u013712343/article/details/107932706

8、《《【iOS 教程】亮劍: Stinger到底能比Aspects快多少》

https://blog.csdn.net/weixin_47143210/article/details/105603880

9、iOS使用Aspects做簡單熱修復原理

https://www.pianshen.com/article/9576238931/

10、動態交換方法實現

https://blog.csdn.net/WangErice/article/details/51211328

11、iOS AOP框架Aspects實現原理

http://www.lxweimin.com/p/0d43db446c5b

12、Mac啟動本地服務

http://www.lxweimin.com/p/90d5fa728861

13、熱更新方案

https://srxboys.github.io/2018/06/03/%E7%83%AD%E6%9B%B4%E6%96%B0%E6%96%B9%E6%A1%88/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
禁止轉載,如需轉載請通過簡信或評論聯系作者。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,362評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,577評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,486評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,852評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,600評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,944評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,108評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,652評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,385評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,616評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,798評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,205評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,537評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,334評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,570評論 2 379