转载:http://www.jianshu.com/p/dc527de06b5e
需求
1.在打开APP的时候进行网络请求,检查是否有网络更新。
2.如果有网络更新,下载新的版本,再次打开APP的时候,就直接连接到新的内容。
具体功能的实现:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [[UpdateDataLoader sharedInstance] createPath]; [[UpdateDataLoader sharedInstance] getAppVersion]; [self testCopy]; //检查更新并下载,有更新则直接下载,无则保持默认配置 //定义加载bundle的URL NSURL *jsCodeLocation; NSString* iOSBundlePath = [[UpdateDataLoader sharedInstance] iOSFileBundlePath]; if ([[NSFileManager defaultManager] fileExistsAtPath:iOSBundlePath]) { jsCodeLocation = [NSURL URLWithString:[iOSBundlePath stringByAppendingString:@"/index.ios.jsbundle"]]; }else{ jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; } NSLog(@"jsCodeLocation%@",jsCodeLocation); RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"CMEngineRoom" initialProperties:nil launchOptions:launchOptions]; rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; [DownLoadTool defaultDownLoadTool].view = rootView; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; UIViewController *rootViewController = [UIViewController new]; rootViewController.view = rootView; self.window.rootViewController = rootViewController; [self.window makeKeyAndVisible]; return YES; }
上述代码是在Appdelegate中的实现,关键点有两个:
1.实现对版本号的数据持久化存储。
2.如何加载沙盒路径下的js.bundle文件。
实现数据持久化的方法
在三种数据持久化得方式中,我选择了plist文件去存储版本号和下载路径。
实现从本地文件夹中获取bundle并加载
在这里,有以下几个问题需要去解决:
- 如何下载?
- 下载完毕后如何解压?
- 解压完成后如何配置文件?
首先解决如何下载的问题,在这里我选择了第三方AFNetworking 3.0来实现对文件的下载。
使得下载主动进行。
在下载完毕之后的block回调中,是在主线程中进行的,在这里就可以进行一些UI的更新。
注意在完成之后返回的文件路径filePath为:
file:///*********
直接进行使用发现,获取不到文件。
必须将file:///去掉才能解决问题。
利用nsstring提供的方法来实现。
在这里需要注意的是每个下载的设置默认是被挂起的,所以在设置完毕之后,需要调用
[downloadTask resume]使得下载主动进行。
OK解决的下载问题,现在来解决解压问题,解压方式我选择了第三方提供的SSZipArchive.
最后,来解决一下如何配置的问题:
在各种文档里都没有找到说明如何加载一个现有的js.bundle文件。
经过我个人的几番尝试,我找到了如下方法:
NSURL *jsCodeLocation; jsCodeLocation = [NSURL URLWithString:iOSBundlePath]; RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"Dingla" initialProperties:nil launchOptions:launchOptions];
iOSBUndlepath为沙盒内的文件路径。
至此,iOS的热更新就实现了。
源码实现
DownloadTool.h
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface DownLoadTool : NSObject @property (nonatomic,strong) NSString *zipPath; @property (nonatomic,strong) UIView* view; + (DownLoadTool *) defaultDownLoadTool; //根据url下载相关文件 -(void)downLoadWithUrl:(NSString*)url; //解压压缩包 -(BOOL)unZip; //删除压缩包 -(void)deleteZip; @end
DownloadTool.m
#import "DownLoadTool.h" #import "SSZipArchive.h" #import "AFURLSessionManager.h" #import "UpdateDataLoader.h" @implementation DownLoadTool + (DownLoadTool *) defaultDownLoadTool{ static DownLoadTool *sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken,^{ sharedInstance = [[DownLoadTool alloc] init]; }); return sharedInstance; } //下载了一个dmg文件 //https://www.baidu.com/link?url=AH4YJUtQK3tB6D6BARqSkZzQsax38iBawDvAXK1wVGVplkkmuhf7mkpc6barjlavO6ysikDjimVG7d0l8KAFvorDmM3K_T5aIES89-JdQEG&wd=&eqid=e165a7c1000050c3000000035993b22c -(void)downLoadWithUrl:(NSString*)url{ //根据url下载相关文件 NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration]; NSURL *URL = [NSURL URLWithString:url]; NSURLRequest *request = [NSURLRequest requestWithURL:URL]; NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) { //获取下载进度 NSLog(@"Progress is %f",downloadProgress.fractionCompleted); } destination:^NSURL *(NSURL *targetPath,NSURLResponse *response) { //有返回值的block,返回文件存储路径 NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil]; NSURL* targetPathUrl = [documentsDirectoryURL URLByAppendingPathComponent:@"kiOSFileName"]; return [targetPathUrl URLByAppendingPathComponent:[response suggestedFilename]]; } completionHandler:^(NSURLResponse *response,NSURL *filePath,NSError *error) { if(error){ //下载出现错误 NSLog(@"%@",error); }else{ // [self showPromptWithStr:@"更新完毕。请重新启动******!"]; //下载成功 NSLog(@"File downloaded to: %@",filePath); self.zipPath = [[filePath absoluteString] substringFromIndex:7]; //下载成功后更新本地存储信息 NSDictionary*infoDic=@{@"bundleVersion":@3,@"downloadUrl":url}; [UpdateDataLoader sharedInstance].versionInfo=infoDic; [[UpdateDataLoader sharedInstance] writeAppVersionInfoWithDictiony:[UpdateDataLoader sharedInstance].versionInfo]; //解压并删除压缩包 if ([self unZip]) { [self deleteZip]; }; } }]; [downloadTask resume]; } //解压压缩包 -(BOOL)unZip{ if (self.zipPath == nil) { return NO; } //检查Document里有没有bundle文件夹 NSString* path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) objectAtIndex:0]; NSString* bundlePath = [path stringByAppendingPathComponent:@"kiOSfileSetName"]; BOOL isDir; //如果有,则删除后解压,如果没有则直接解压 if ([[NSFileManager defaultManager] fileExistsAtPath:bundlePath isDirectory:&isDir]&&isDir) { [[NSFileManager defaultManager] removeItemAtPath:bundlePath error:nil]; } NSString *zipPath = self.zipPath; NSString *destinationPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,YES) objectAtIndex:0]stringByAppendingString:@"/IOSBundle"]; BOOL success = [SSZipArchive unzipFileAtPath:zipPath toDestination:destinationPath]; return success; } //删除压缩包 -(void)deleteZip{ NSError* error = nil; [[NSFileManager defaultManager] removeItemAtPath:self.zipPath error:&error]; } @end
UpdateDataLoader.h
#import <Foundation/Foundation.h> @interface UpdateDataLoader : NSObject @property (nonatomic,strong) NSDictionary* versionInfo; + (UpdateDataLoader *) sharedInstance; //创建bundle路径 -(void)createPath; //获取版本信息 -(void)getAppVersion; -(void)writeAppVersionInfoWithDictiony:(NSDictionary*)info; -(NSString*)iOSFileBundlePath; @end
UpdateDataLoader.m
#import "UpdateDataLoader.h" #import "DownLoadTool.h" @implementation UpdateDataLoader + (UpdateDataLoader *) sharedInstance { static UpdateDataLoader *sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken,^{ sharedInstance = [[UpdateDataLoader alloc] init]; }); return sharedInstance; } //创建bundle路径 -(void)createPath{ if([self getVersionPlistPath]){ return; } NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,YES); NSString *path = [paths lastObject]; NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *directryPath = [path stringByAppendingPathComponent:@"IOSBundle"]; [fileManager createDirectoryAtPath:directryPath withIntermediateDirectories:YES attributes:nil error:nil]; NSString *filePath = [directryPath stringByAppendingPathComponent:@"Version.plist"]; [fileManager createFileAtPath:filePath contents:nil attributes:nil]; } //获取版本信息 -(void)getAppVersion{ //从服务器上获取版本信息,与本地plist存储的版本进行比较 //假定返回的结果集 /*{ bundleVersion = 2; downloadUrl = "www.baidu.com"; }*/ //1.获取本地plist文件的版本号 假定为2 NSString* plistPath=[self getVersionPlistPath]; NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath]; NSInteger localV=[data[@"bundleVersion"]integerValue]; localV=2; //2 服务器版本 假定为3 NSInteger serviceV=3 ; if(serviceV>localV){ //下载bundle文件 存储在 Doucuments/IOSBundle/下 NSString*url=@"https://www.baidu.com/link?url=AH4YJUtQK3tB6D6BARqSkZzQsax38iBawDvAXK1wVGVplkkmuhf7mkpc6barjlavO6ysikDjimVG7d0l8KAFvorDmM3K_T5aIES89-JdQEG&wd=&eqid=e165a7c1000050c3000000035993b22c"; [[DownLoadTool defaultDownLoadTool] downLoadWithUrl:url]; }else{ } } //获取Bundle 路径 -(NSString*)iOSFileBundlePath{ //获取沙盒路径 NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,YES); NSString* path = [paths objectAtIndex:0]; NSLog(@"the save version file's path is :%@",path); //填写文件名 NSString* filePath = [path stringByAppendingPathComponent:@"/IOSBundle"]; return filePath; } //获取版本信息储存的文件路径 -(NSString*)getVersionPlistPath{ //获取沙盒路径 NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,YES); NSString* path = [paths objectAtIndex:0]; NSLog(@"the save version file's path is :%@",path); //填写文件名 NSString* filePath = [path stringByAppendingPathComponent:@"/IOSBundle/Version.plist"]; NSLog(@"文件路径为:%@",filePath); return filePath; } //创建或修改版本信息 -(void)writeAppVersionInfoWithDictiony:(NSDictionary*)dictionary{ NSString* filePath = [self getVersionPlistPath]; [dictionary writeToFile:filePath atomically:YES]; }原文链接:https://www.f2er.com/react/303117.html