iOS热修复(动态Framework)
gybddp
9年前
来自: http://finalshares.com/read-6951
上次降到了利用jspatch实现热修复,那么今天我就简单说一下关于动态framework 来进行动态修复;
犹豫存在较复杂的解耦,所以我将整个app写成一个Framework;
1、这里是一个比较简单的app 首先需要写一个管理类去管理分配这些资源,
/** * 主程序和此动态库的关系枢纽,也就是从“主程序”到“动态库内封装的程序”的入口方法 * * @param rootViewController “主程序”中引导 * @param bundle 此动态库在document文件中的路径,用于xib的加载和图片的加载 */ - (void)bootLoader:(id)rootViewController WithBundle:(NSBundle *)bundle;
实现方法:
- (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]; }
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]; }
在这里推荐做一些后台逻辑去验证文件的完整和正确性。
也可以对生成的Framework进行加密压缩处理。
综上所述:这就可以实现动态的更新包替换,但是更推荐分模块去加载,这样做的好处不用多说,但是存在一定的技术难度和对整个项目的把控,同样不要盲目的去实现,实现计算工程难度。