以下是iOS app热更新的几种方案,
由于苹果在2017年3月左右更新了开发者协议, 禁止需要线上审核的应用进行热更新, 所以请大家慎用
(企业版不需要提交审核当然是可以使用的)
目前流行的热更新解决方案可以参看这篇文章:http://blog.csdn.net/chengkaizone/article/details/64122587
这里主要介绍使用framework进行热更新的方法
具体步骤:
- 封装framework ,不在介绍 可参见我的另一篇文章framework封装
- 把封装好的框架上传到服务端,我这里是上传到了我的Github
- 项目中下载框架
- 读取框架 展示
框架展示思路
1.判断本地是否存在framework
#pragma mark - 下载以及比较文件
-(void)compareAndLoadFile{
NSArray *arrFramework = [self getFilenamelistOfType:@"framework" fromDirPath:_destinationPath];
NSString *bundlePath = [NSString stringWithFormat:@"%@/%@",_destinationPath,[arrFramework lastObject]];
NSLog(@"path===%@",bundlePath);
if (![[NSFileManager defaultManager] fileExistsAtPath:bundlePath]) {
NSLog(@"文件不存在");
NSString *requestURL = Download_Url;
if(requestURL==nil || requestURL.length==0){
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"没有下载地址,不能开启" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *sureBtn = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:sureBtn];
return;
}else{
NSLog(@"去下载");
[self downloadFile];
}
}else{
NSLog(@"文件存在!");
// 重新下载文件 命名不同
[self reDownloadFile];
}
}
下载方法
-(void)downloadFile{
//下载保存的路径
NSString *savedPath = [NSHomeDirectory() stringByAppendingString:[NSString stringWithFormat:@"/Documents/HotPatch-master.zip"]];
AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer];
NSMutableURLRequest *request = [serializer requestWithMethod:@"GET" URLString:Download_Url parameters:nil error:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]initWithRequest:request];
[operation setOutputStream:[NSOutputStream outputStreamToFileAtPath:savedPath append:NO]];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
float progress = (float)totalBytesRead / totalBytesExpectedToRead;
_progressView.progress =progress;
_progressLabel.text = [NSString stringWithFormat:@"%.2f%%",progress*100];
NSLog(@"progress==%.2f",progress);
}];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation * _Nonnull operation, id _Nonnull responseObject) {
NSLog(@"下载成功");
NSString *destinationPath = [NSHomeDirectory() stringByAppendingString:[NSString stringWithFormat:@"/Documents"]];
//对下载下来的ZIP包进行解压
BOOL isScu = [SSZipArchive unzipFileAtPath:savedPath toDestination:destinationPath];
if(isScu){
NSLog(@"解压成功");
NSFileManager *fileMgr = [NSFileManager defaultManager];
BOOL bRet = [fileMgr fileExistsAtPath:savedPath];
if (bRet) {
[fileMgr removeItemAtPath:savedPath error:nil];//解压成功后删除压缩包
}
[self reloadFramework];
}else{
NSLog(@"解压失败 --- 开启失败");
}
} failure:^(AFHTTPRequestOperation * _Nonnull operation, NSError * _Nonnull error) {
NSLog(@"error===%@",error);
NSLog(@"下载失败 --- 开启失败");
}];
[operation start];
}
比较两个文件是否相同的方法:
-(void)compareFile{
NSArray *arrFramework = [self getFilenamelistOfType:@"framework" fromDirPath:_destinationPath];
NSString *bundlePath = [NSString stringWithFormat:@"%@/%@",_destinationPath,[arrFramework lastObject]];
_filePathOne = bundlePath;
NSLog(@"_filePathOne===%@",_filePathOne);
//获取framework的路径名
NSArray *arrFrameworkX = [self getFilenamelistOfType:@"framework" fromDirPath:_newPath];
NSString *bundlePathX = [NSString stringWithFormat:@"%@/%@",_newPath,[arrFrameworkX lastObject]];
_filepathTwo = bundlePathX;
NSLog(@"_filepathTwo==%@",_filepathTwo);
if ([[NSFileManager defaultManager] contentsEqualAtPath:_filePathOne andPath:_filepathTwo]) {
NSLog(@"文件相同");
[[NSFileManager defaultManager] removeItemAtPath:_destinationPathX error:nil];//删除下载的文件
[self reloadFramework];
}else{
NSLog(@"文件不同");
[[NSFileManager defaultManager] removeItemAtPath:_destinationPath error:nil];//删除旧的下载的文件
// 移动文件到Documents文件下
NSError *error = nil;
if ([[NSFileManager defaultManager] moveItemAtPath:_newPath toPath:_destinationPath error:&error] == YES){
[[NSFileManager defaultManager] removeItemAtPath:_destinationPathX error:nil];//删除旧的文件
NSLog(@"重命名成功!");
[self reloadFramework];
}else{
NSLog(@"Unable to move file: %@", [error localizedDescription]);
}
}
}
加载framework的方法
#pragma mark - 加载framework
-(void)reloadFramework{
NSArray *arrFramework = [self getFilenamelistOfType:@"framework" fromDirPath:_destinationPath];
NSString *bundlePath = [NSString stringWithFormat:@"%@/%@",_destinationPath,[arrFramework lastObject]];
NSLog(@"bundlePath==%@",bundlePath);
_filePathOne = bundlePath;
NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
if (!bundle || ![bundle load]) {
NSLog(@"bundle加载出错");
}
// 下载的framework的封装的文件名
NSString *className = @"HotPatchViewController";
NSString *classtype = @"UIViewController";
Class loadClass = [bundle classNamed:className];
if (!loadClass) {
NSLog(@"获取失败");
}
if([classtype isEqualToString:@"UIViewController"]){
NSLog(@"成功了。。。");
UIViewController *uvc = (UIViewController*)[loadClass new];
[self.navigationController pushViewController:uvc animated:YES];
}
}
最后项目源码:Cxm的Github