ionic2熱更新外掛cordova-hot-code-push-plugin更新下載檔案
以iOS為例
說下需求:在主專案中根據需要下載子專案(或檔案),並子專案能利用主專案中的cordova-hot-code-push-plugin的跟隨主專案更新。一個是包含全部子專案的頁面,一個是選擇下載子專案後的頁面,都是iOS原生。
一、必要條件
先把要下載的專案壓縮包放在本地伺服器的 /usr/local/apache-tomcat-7.0.32/webapps/www裡面,以便下載。
2、cordova-hot-code-push-plugin外掛已安裝在專案。
3、本地伺服器已開啟。
二、下載(iOS原生做的下載)
1、首先要先設定好下載路徑,下載路徑要跟熱更新的下載更新路徑是相同的,需要注意一點,檔案不是存放在專案資料夾,是存放在專案執行的路徑
看一下拼接路徑:NSUserDefaults *user=[NSUserDefaults standardUserDefaults]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSAllLibrariesDirectory, NSUserDomainMask, YES); NSLog(@"------------paths=%@",paths); NSString *documentsDirectory = [NSString stringWithFormat:@"%@/Application Support/com.ionicframework.superappionic558256/cordova-hot-code-push-plugin/%@/www",[paths objectAtIndex:0],[user objectForKey:@"currentReleaseVersionName"]];
[paths objectAtIndex:0]:這個不必說,自然是自動獲取;
Application Support:值得一提的是這個資料夾,這個檔案是進入cordova,ionic頁面執行後出現的(個人認為進入cordova就可以有),所以,必須要進入cordova,ionic頁面先執行一次,否則沒有這個資料夾。此時,肯定有人會說,既然這樣那我直接讓做管理子專案下載的頁面控制器繼承於CDVViewController,省了前面的複雜,我利用屬性傳值測試了一下,CDVViewController與UIViewController之間push的時候要麼不傳值,要麼崩,但是,NSUserDefaults是可以的,原因大家自己去找吧;
com.ionicframework.superappionic558256:測試了一下,清空執行快取再執行,兩次生成的都是這個名字資料夾,這跟config.xml有關,由裡面的id決定;
<widget id="com.ionicframework.superappionic558256" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
cordova-hot-code-push-plugin:外掛名;
[user objectForKey:@"currentReleaseVersionName"]:當前顯示給使用者的版本,即chcp.json裡面的release對應的值。去HCPPlugin.m裡面的doLocalInit方法取值
/**
* Perform initialization of the plugin variables.執行外掛的初始化
*/
- (void)doLocalInit {
_defaultCallbackStoredResults = [[NSMutableArray alloc] init];
// init plugin config from xml
_pluginXmlConfig = [HCPXmlConfig loadFromCordovaConfigXml];
// load plugin internal preferences
_pluginInternalPrefs = [HCPPluginInternalPreferences loadFromUserDefaults];
if (_pluginInternalPrefs == nil || _pluginInternalPrefs.currentReleaseVersionName.length == 0) {
_pluginInternalPrefs = [HCPPluginInternalPreferences defaultConfig];
[_pluginInternalPrefs saveToUserDefaults];
}
NSLog(@"Currently running release version %@", _pluginInternalPrefs.currentReleaseVersionName);
//取當前版本號
NSUserDefaults *user=[NSUserDefaults standardUserDefaults];
[user setObject:_pluginInternalPrefs.currentReleaseVersionName forKey:@"currentReleaseVersionName"];
// init file structure for www files
_filesStructure = [[HCPFilesStructure alloc] initWithReleaseVersion:_pluginInternalPrefs.currentReleaseVersionName];
NSLog(@"====%s",__FUNCTION__);
}
www:就是專案的www檔案。
2、下載,ionic2專案建立時就自帶了AFNetworking,所以用它來下載,檔案都是壓縮包Zip的形式,程式碼如下:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
//存放檔案的路徑
NSString *fullPath = [NSString stringWithFormat:@"%@/%@.zip", documentsDirectory, projectName];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://192.168.100.234:8080/www/%@.zip",projectName]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDownloadTask *task =
[manager downloadTaskWithRequest:request
progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
return [NSURL fileURLWithPath:fullPath];
}
completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
}];
[task resume];
下載路徑URL是本地伺服器的IP+www+專案名稱.zip,專案壓縮包是提前放在本地伺服器上的。
3、解壓並刪除Zip // 解壓
NSString *zipPath =[NSString stringWithFormat:@"%@/%@.zip",documentsDirectory,projectName];
NSString *destinationPath = [NSString stringWithFormat:@"%@",documentsDirectory];
[SSZipArchive unzipFileAtPath:zipPath toDestination:destinationPath];
NSFileManager* fileManager=[NSFileManager defaultManager];
BOOL blHave=[[NSFileManager defaultManager] fileExistsAtPath:zipPath];
if (!blHave) {
NSLog(@"no have");
return ;
}else {
NSLog(@" have");
//移除Zip
BOOL blDele= [fileManager removeItemAtPath:zipPath error:nil];
if (blDele) {
NSLog(@"delete success");
}else {
NSLog(@"delete fail");
}
}
解壓用網上的SSZipArchive就可以了。
所以,總結全部,下載功能程式碼如下,
#pragma mark -檔案下載
-(void)downloadFileByAFNetworkingWithProject:(NSString*)projectName documentsDirectory:(NSString*)documentsDirectory{
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
//存放檔案的路徑
NSString *fullPath = [NSString stringWithFormat:@"%@/%@.zip", documentsDirectory, projectName];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://192.168.100.241:8080/www/%@.zip",projectName]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDownloadTask *task =
[manager downloadTaskWithRequest:request
progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
return [NSURL fileURLWithPath:fullPath];
}
completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
}];
[task resume];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 解壓
NSString *zipPath =[NSString stringWithFormat:@"%@/%@.zip",documentsDirectory,projectName];
NSString *destinationPath = [NSString stringWithFormat:@"%@",documentsDirectory];
[SSZipArchive unzipFileAtPath:zipPath toDestination:destinationPath];
NSFileManager* fileManager=[NSFileManager defaultManager];
BOOL blHave=[[NSFileManager defaultManager] fileExistsAtPath:zipPath];
if (!blHave) {
NSLog(@"no have");
return ;
}else {
NSLog(@" have");
//移除Zip
BOOL blDele= [fileManager removeItemAtPath:zipPath error:nil];
if (blDele) {
NSLog(@"delete success");
}else {
NSLog(@"delete fail");
}
}
});
}
projectName和documentsDirectory都是在外部呼叫時傳入的,可根據自己的需要調整是否需要傳入。
需要注意一點,本人在呼叫執行的時候,下載速度會慢於解壓,導致解壓時還沒有Zip檔案,所以解壓用dispatch_after做了一個2s的時間延遲,延遲時間可根據情況做設定。
三、更新
1、修改HCPContentManifest.m
官方說法
/**
* Model for content manifest.
* Content manifest is a configuration file, that holds the list of all web project files with they hashes.內容清單是一個配置檔案,包含所有web專案的列表檔案雜湊表。
* Used to determine which files has been removed from the project, which are added or updated.用於確定哪些檔案已經從專案中刪除,新增或更新。
*/
這個HCPContentManifest就是Web內容清單,找到- (HCPManifestDiff *)calculateDifference:(HCPContentManifest *)comparedManifest方法,修改下面這部分
// find new files
for (HCPManifestFile *newFile in comparedManifest.files) {
BOOL isFound = NO;
for (HCPManifestFile *oldFile in self.files) {
if ([newFile.name isEqualToString:oldFile.name]) {
isFound = YES;
break;
}
}
if (!isFound) {
[addedFiles addObject:newFile];
}
}
修改後,如下
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
NSString *newProjName = [ud objectForKey:@"page"];//"proj1","proj2".etc
NSLog(@"------%s=newProjName=%@",__FUNCTION__,newProjName);
// find new files
for (HCPManifestFile *newFile in comparedManifest.files) {
BOOL isFound = NO;
BOOL isNeed = NO;
for (HCPManifestFile *oldFile in self.files) {
if ([newFile.name isEqualToString:oldFile.name]) {
isFound = YES;
NSLog(@"++++----- newFile.name ======= %@", newFile.name);
if (newProjName != nil) {
if ([newFile.name hasPrefix: newProjName]) {
NSLog(@"+++++++++++ newFile.name必須的 ======= %@", newFile.name);
isNeed = YES;
}
}
break;
}
}
if (!isFound && isNeed) {
[addedFiles addObject:newFile];
}
}
在進入某個子專案時,傳值專案名到這,根據傳值,進入的子專案就是更新後的。
2、修改CDVViewController.m
因為是從iOS原生進入ionic,用瞭如下方法:
NSString *file=[NSString stringWithFormat:@"%@/index.html",_currentItems[indexPath.item]];
NSLog(@"--------file==%@",file);
[user setObject:file forKey:@"page"];
[user synchronize];
MainViewController *vc = [[MainViewController alloc] initWithFolderName:@"www" StartPage:file];
[self.navigationController pushViewController:vc animated:true];
MainViewController是繼承於CDVViewController,iOS原生進入ionic是需要通過cordova,所以修改如下
- (void)loadSettings
{
CDVConfigParser* delegate = [[CDVConfigParser alloc] init];
[self parseSettingsWithParser:delegate];
// Get the plugin dictionary, whitelist and settings from the delegate.
self.pluginsMap = delegate.pluginsDict;
self.startupPluginNames = delegate.startupPluginNames;
self.settings = delegate.settings;
// And the start folder/page.
if(self.wwwFolderName == nil){
self.wwwFolderName = @"www";
}
// if(delegate.startPage && self.startPage == nil){
//self.startPage = delegate.startPage;
// }
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
self.startPage = [ud objectForKey:@"page"];
NSLog(@"-------cdv-startPage==%@",self.startPage);
// Initialize the plugin objects dict.
self.pluginObjects = [[NSMutableDictionary alloc] initWithCapacity:20];
}
代理這部分註釋掉,是因為會預設執行代理的,即Staging檔案裡面的config.xml的<content src="index.html" />,所以把self.startPage改成靈活的,可根據自己的選擇進入想要進入的頁面。
3、修改HCPPlugin.m
把indexPageFromConfigXml方法裡面的“_indexPage = DEFAULT_STARTING_PAGE;”改成如下:
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
NSString *startUrl=[ud objectForKey:@"page"];
_indexPage = startUrl;//DEFAULT_STARTING_PAGE;
做這個操作是因為:在更新後,第一次進入頁面會進入預設的www/index.html,退出後,再進入,才是更新後的,為了解決這個問題而做的修改。
4、更新步驟
前提:帶有子專案的主專案在執行中。
子專案更新:
①、在子專案中需要的地方做修改;
②、ionic serve;
③、cordova-hcp build;
④、ionic build iOS;
⑤、將子專案platforms--iOS中的www複製,放在主專案外部的www檔案;
⑥、主專案cordova-hcp build;
⑦、將主專案外部的www檔案複製,放到伺服器 /usr/local/apache-tomcat-7.0.32/webapps,覆蓋原來的www檔案,如有其它需要下載的子專案,則放入新www中。
主專案更新:
①、在主專案中需要的地方做修改;
②、ionic serve;
③、cordova-hcp build;
⑦、將主專案外部的www檔案複製,放到伺服器 /usr/local/apache-tomcat-7.0.32/webapps,覆蓋原來的www檔案。
以上就是主要功能,還有許多細節需要自己完善,裡面很多操作是靈活,根據自己的需要用合適的方法就可以了,比如傳值方式。
這裡iOS和Android很多方法都是通用的。
(網不好,沒上傳圖片。如果有更好的建議和方法可以留言啊!!)