需求
1.在打開APP的時(shí)候進(jìn)行網(wǎng)絡(luò)請求盯滚,檢查是否有網(wǎng)絡(luò)更新筋帖。
2.如果有網(wǎng)絡(luò)更新迅耘,下載新的版本贱枣,再次打開APP的時(shí)候,就直接連接到新的內(nèi)容颤专。
具體功能的實(shí)現(xiàn):
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UpdataLoader* upLoatder = [UpdataLoader shareUpLoader];
//保證存放路徑是存在的
[upLoatder createPath];
//檢查更新并下載纽哥,有更新則直接下載,無則保持默認(rèn)配置
[upLoatder getAppVersion];
//定義加載bundle的URL
NSURL *jsCodeLocation;
NSString* iOSBundlePath = [[upLoatder iOSFileBundlePath] stringByAppendingPathComponent:@"index.ios.bundle"];
if ([[NSFileManager defaultManager] fileExistsAtPath:iOSBundlePath]) {
jsCodeLocation = [NSURL URLWithString:iOSBundlePath];
}else{
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
}
// NSLog(@"jsCodeLocation%@",jsCodeLocation);
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"******"
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中的實(shí)現(xiàn)栖秕,關(guān)鍵點(diǎn)有兩個(gè):
1.實(shí)現(xiàn)對版本號的數(shù)據(jù)持久化存儲春塌。
2.如何加載沙盒路徑下的js.bundle文件。
實(shí)現(xiàn)數(shù)據(jù)持久化的方法
在三種數(shù)據(jù)持久化得方式中簇捍,我選擇了plist文件去存儲版本號和下載路徑只壳。
//獲取版本信息儲存的文件路徑
-(NSString*)getVersionPlistPath{
//獲取沙盒路徑
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* path = [paths objectAtIndex:0];
NSLog(@"the save version file's path is :%@",path);
//填寫文件名
NSString* filePath = [path stringByAppendingPathComponent:kVersionPlist];
// NSLog(@"文件路徑為:%@",filePath);
return filePath;
}
//創(chuàng)建或修改版本信息
-(void)writeAppVersionInfoWithDictiony:(NSDictionary*)dictionary{
NSString* filePath = [self getVersionPlistPath];
[dictionary writeToFile:filePath atomically:YES];
}
分為兩步,第一步確定存儲路徑暑塑,第二步將要存儲的信息調(diào)用
[dictionary writeToFile:filePath atomically:YES];
的方法去寫入本地路徑吼句。
實(shí)現(xiàn)從本地文件夾中獲取bundle并加載
在這里,有以下幾個(gè)問題需要去解決:
- 如何下載事格?
- 下載完畢后如何解壓惕艳?
- 解壓完成后如何配置文件搞隐?
首先解決如何下載的問題,在這里我選擇了第三方AFNetworking 3.0來實(shí)現(xiàn)對文件的下載远搪。
-(void)downLoadWithUrl:(NSString*)url{
[self showPromptWithStr:@"發(fā)現(xiàn)新的版本劣纲,開始下載..."];
//根據(jù)url下載相關(guān)文件
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) {
//獲取下載進(jìn)度
// 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){
//下載出現(xiàn)錯誤
NSLog(@"%@",error);
}else{
[self showPromptWithStr:@"更新完畢谁鳍。請重新啟動******癞季!"];
//下載成功
NSLog(@"File downloaded to: %@", filePath);
self.zipPath = [[filePath absoluteString] substringFromIndex:7];
//下載成功后更新本地存儲信息
[[UpdataLoader shareUpLoader] writeAppVersionInfoWithDictiony:[UpdataLoader shareUpLoader].versionInfo];
//解壓并刪除壓縮包
if ([self unZip]) {
[self deleteZip];
};
}
}];
[downloadTask resume];
}
在這里需要注意的是每個(gè)下載的設(shè)置默認(rèn)是被掛起的,所以在設(shè)置完畢之后倘潜,需要調(diào)用
[downloadTask resume];
使得下載主動進(jìn)行绷柒。
在下載完畢之后的block回調(diào)中,是在主線程中進(jìn)行的窍荧,在這里就可以進(jìn)行一些UI的更新辉巡。
注意在完成之后返回的文件路徑filePath為:
file:///*********
直接進(jìn)行使用發(fā)現(xiàn),獲取不到文件蕊退。
必須將file:///去掉才能解決問題郊楣。
利用nsstring提供的方法來實(shí)現(xiàn)。
self.zipPath = [[filePath absoluteString] substringFromIndex:7];
OK解決的下載問題瓤荔,現(xiàn)在來解決解壓問題净蚤,解壓方式我選擇了第三方提供的SSZipArchive.
代碼如下:
//解壓壓縮包
-(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, NSUserDomainMask, YES) objectAtIndex:0];
BOOL success = [SSZipArchive unzipFileAtPath:zipPath
toDestination:destinationPath];
return success;
}
//刪除壓縮包
-(void)deleteZip{
NSError* error = nil;
[[NSFileManager defaultManager] removeItemAtPath:self.zipPath error:&error];
}
最后今瀑,來解決一下如何配置的問題:
在各種文檔里都沒有找到說明如何加載一個(gè)現(xiàn)有的js.bundle文件。
經(jīng)過我個(gè)人的幾番嘗試点把,我找到了如下方法:
NSURL *jsCodeLocation;
jsCodeLocation = [NSURL URLWithString:iOSBundlePath];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"Dingla"
initialProperties:nil
launchOptions:launchOptions];
iOSBUndlepath為沙盒內(nèi)的文件路徑橘荠。
至此,iOS的熱更新就實(shí)現(xiàn)了郎逃。
git倉庫點(diǎn)我
2017.09.14 PS:
因?yàn)槲恼聦懙谋容^早哥童,源碼我已經(jīng)刪除了。
感謝這位同學(xué)將代碼補(bǔ)全褒翰。
附上地址點(diǎn)我