iOS 動態化熱修復方案

iOS 動態化熱修復方案

Warnning

純粹是技術分享,歡迎到github點贊。
https://github.com/dKingbin/DynamicOC
複製代碼

前言

iOS熱修復方案通過JSPatch事件後,也消停了好久。bang神在《JSPatch – 動態更新iOS APP》中曾提到,爲了更符合Apple的規則,即《Apple Developer Program License Agreement》 裏3.3.2提到的不可動態下發可執行代碼。 JSPatch特意繞了js的圈子,從而實現曲線救國、實現熱更新的方案。可是事實證實了Apple對於這種方案也是不承認的,根本的緣由仍是在於JSPath作得太過極致--支持絕大部分的OC/C語法。javascript

思考

既然JSPatch繞道js的方法,已經被Apple拒絕了,那麼就再次回到原點,從新出發。新的框架或者新的方案我以爲至少有一個充分條件,就是不能太極致。 Objective-C做爲一種動態的語言,所以可以動態執行全部OC語法是正常的,Aspects相似的框架也是被Apple承認的。至因而否須要運行全部的C函數,這個有待商榷。 第二個方面,則是放棄javascript/lua等相似語言做爲更新的腳本,而是採用原生的Objective-C做爲更新的腳本語言。java

動態運行C函數

C語言是沒有反射機制的,做爲一門編譯型語言,在編譯期間就已經生成機器碼。所以若是要從字符串中獲取到對應的函數指針,那麼大概有兩種方法:git

  • 創建映射表, 將函數名和函數指針創建一個映射表。
  • dlsym, 根據動態連接庫操做句柄與符號,返回符號對應的地址。

第二種是目前JSPatch採用的辦法,固然也被Apple警告了。dlsym功能很是強悍,是獲取函數指針的最優解。 第一種侷限性很是大,可是沒有用到黑魔法。github

採用Objective-C做爲更新的腳本語言

經過flex/yacc,直接解析Objective-C語法,再也不採起js/lua等腳本語言。objective-c

DynamicOC

通過上面的思考,在最近業餘中作了DynamicOC的項目,百分百原生支持採用Objective-C做爲更新的腳本語言。 固然動態運行C函數仍是採用dlsym獲取函數指針的辦法,後面會逐步改成映射表的作法。bash

原理

DynamicOC使用flex/yacc進行詞法解析和語法分析,轉爲一顆語法生成樹AST。 而後經過解析每一個節點,從而執行相應的代碼。由於採用的是Objective-C做爲腳本語言,所以極容易適配。框架

功能特色

  • 動態執行OC代碼
  • 動態執行C函數和block異步調用
  • 動態添加屬性
  • 動態替換方法
  • 動態添加方法
  • 有完善的單元測試
  • flex/yacc實現強大的OC語法解析器
  • 支持CGRect/CGSize/CGPoint/NSRange/UIEdgeInsets/CGAffineTransform經常使用結構體 ...

基本用法

動態執行block

NSString* text = @" \ __block int result = 0;\ UIView* view = [[UIView alloc]init];\ void(^blk)(int value) = ^(int value){\ view.tag = value;\ };\ blk(1024);\ return view.tag;";

ASTNode* root = [ASTUtil parseString:text];
ASTVariable* result = [root execute];
NSAssert([result.value doubleValue] == 1024, nil);
複製代碼

動態執行C函數

int echo(int value) {
return value;
}

NSString* text = @" \ [OCCfuntionHelper defineCFunction:@\"echo\" types:@\"int, int\"]; \ return echo(1024);";

ASTNode* root = [ASTUtil parseString:text];
ASTVariable* result = [root execute];
NSAssert([result.value doubleValue] == 1024, nil);
複製代碼

動態添加Property

NSString* text = @" \ [OCCfuntionHelper defineCFunction:@\"objc_setAssociatedObject\" types:@\"void,id,void *,id,unsigned int\"];\ [OCCfuntionHelper defineCFunction:@\"objc_getAssociatedObject\" types:@\"id,id,void *\"];\ NSString* key = @\"key\"; \ objc_setAssociatedObject(self, key, @(1024), 1);\ return objc_getAssociatedObject(self, key);";

ASTNode* root = [ASTUtil parseString:text];
ASTVariable* result = [root execute];
NSAssert([result.value doubleValue] == 1024, nil);
複製代碼

已支持語法

  • if/else while do/while for
  • return break continue
  • i++ i-- ++i --i
  • +i -i !i
  • + - * / %等四則運算
  • >> << & | ^ 等位運算
  • && || >= <= != > < 等比較運算
  • ?:
  • __block
  • array[i] dict[@""]
  • @666 @() @[] @{}
  • self super
  • self.property
  • self->_property
  • most of objective-c keyword

TODO

  • @available()
  • [NSString stringWithFormat:"%d",value] : use [NSString stringWithFormat:"%@",@(value)] instead。
  • dispatch_async / dispatch_after ...
  • *stop =YES, in block
  • fix bugs

Github連接在此: DynmaicOC, 以爲有幫助的能夠點個星哦!謝謝!異步

參考連接

JSPatch – 動態更新iOS APPasync

iOS 動態化的故事函數

Apple Developer Program License Agreement

滴滴 iOS 動態化方案 DynamicCocoa 的誕生與起航

相關文章
相關標籤/搜索