iOS熱修復(動態Framework)

gybddp 8年前發布 | 11K 次閱讀 iOS開發 動態庫 Objective-C開發

來自: http://finalshares.com/read-6951

上次降到了利用jspatch實現熱修復,那么今天我就簡單說一下關于動態framework 來進行動態修復;

猶豫存在較復雜的解耦,所以我將整個app寫成一個Framework;

1、這里是一個比較簡單的app 首先需要寫一個管理類去管理分配這些資源,

/**

  • 主程序和此動態庫的關系樞紐,也就是從“主程序”到“動態庫內封裝的程序”的入口方法 *
  • @param rootViewController “主程序”中引導
  • @param bundle 此動態庫在document文件中的路徑,用于xib的加載和圖片的加載 */

    • (void)bootLoader:(id)rootViewController WithBundle:(NSBundle *)bundle;</pre>

      實現方法:

    - (void)bootLoader:(id)rootViewController WithBundle:(NSBundle )bundle
    {
    /
     初始化第一個管理Controller
     這里的重點是xib文件的加載
      通常我們在初始化xib的時候并不是很在意bundle:這個參數,一般情況下都會賦予nil值
      其實我們所用到的圖片、xib等資源文件都是在程序內部中獲取的,也就是我們常用的[NSBundle mainBundle]中獲取,所謂的NSBundle本質上就是一個路徑,mainBundle指向的是.app下。
      而如果我們不指定bundle,則會默認從.app路徑下去尋找資源。
      不過很顯然,我們的動態庫是放到“主程序”的document文件下的,所以資源文件是不可能在[NSbundle mainBundle]中獲取到的,所以這里我們需要指定bundle參數,這也是傳遞framework的路徑的意義所在
     /
    _currentBundle = bundle;
    [DataCenter shareCenter].bootLoader = bundle;
    HZRootViewController rooter = [[HZRootViewController alloc]initWithNibName:NSStringFromClass([HZRootViewController class]) bundle:bundle];
    //保存NSBundle
    rooter.bootLoader = bundle;

    [rootViewController presentViewController:rooter animated:YES completion:NULL];

    [self setRootViewController: [DataCenter shareCenter].uToken ? YES : NO WithRooter:rooter];

}</pre>

2、我們需要在app也就是這個程序殼里載入這部分代碼

- (void)setRooter
{
    NSArray paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
    NSString documentDirectory = nil;
    if ([paths count] != 0)
        documentDirectory = [paths objectAtIndex:0];

//拼接放到document中的framework路徑
NSString *libName = @"HZDelivery.framework";
NSString *destLibPath = [documentDirectory stringByAppendingPathComponent:libName];

//判斷一下有沒有這個文件的存在 如果沒有直接跳出
NSFileManager *manager = [NSFileManager defaultManager];
if (![manager fileExistsAtPath:destLibPath]) {
    NSLog(@"There isn't have the file");
    return;
}

//復制到程序中
NSError *error = nil;

//使用NSBundle加載動態庫
NSBundle *frameworkBundle = [NSBundle bundleWithPath:destLibPath];
if (frameworkBundle && [frameworkBundle load]) {
    NSLog(@"bundle load framework success.");
}else {
    NSLog(@"bundle load framework err:%@",error);
    return;
}

/*
 *通過NSClassFromString方式讀取類
 *PacteraFramework 為動態庫中入口類
 */
Class pacteraClass = NSClassFromString(@"HZDeliveryManager");
if (!pacteraClass) {
    NSLog(@"Unable to get TestDylib class");
    return;
}

/*
 *初始化方式采用下面的形式
  alloc init的形式是行不通的
  同樣,直接使用PacteraFramework類初始化也是不正確的
 *通過- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
  方法調用入口方法(bootLoader:WithBundle:),并傳遞參數(withObject:self withObject:frameworkBundle)
 */
NSObject *pacteraObject = [pacteraClass new];
[pacteraObject performSelector:@selector(bootLoader:WithBundle:) withObject:self withObject:frameworkBundle];

}</pre>

在這里推薦做一些后臺邏輯去驗證文件的完整和正確性。

也可以對生成的Framework進行加密壓縮處理。

綜上所述:這就可以實現動態的更新包替換,但是更推薦分模塊去加載,這樣做的好處不用多說,但是存在一定的技術難度和對整個項目的把控,同樣不要盲目的去實現,實現計算工程難度。

</div>

 本文由用戶 gybddp 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!