序言
前幾天一直在思考mac APP 的更新升級(jí)要怎么做谒府,網(wǎng)上查了一下 基本沒(méi)有什么文章可以參考击胜, 僅有的思路是 這篇文章?https://blog.csdn.net/lovechris00/article/details/80247987 使用的是三方sparkle洞翩,可以不用寫(xiě)一句代碼骡楼, 只用配置一下mainmenu即可措左。可是sparkle的彈窗滿足不了我們公司的設(shè)計(jì)需求(令人蛋疼)蛙酪,只好按照自己的思路來(lái)寫(xiě)一個(gè)齐苛。
準(zhǔn)備工作
在本地搭建一個(gè)服務(wù)器,提供展示下載服務(wù):
在本地創(chuàng)建一個(gè)文件夾updateServerFile桂塞, 文件夾中存放你的最新的安裝包.dmg文件凹蜂,然后打開(kāi)終端,在終端中輸入
$ cd /Users/administrator/Desktop/updateServerFile
?$ python -m SimpleHTTPServer 8902
這樣子一個(gè)本地服務(wù)就啟動(dòng)了藐俺,此時(shí)我們的本地服務(wù)器地址為:http://(yourhost):8902 或者h(yuǎn)ttp://127.0.0.1:8902
大致思路
先從服務(wù)端獲取更新的信息炊甲,如果需要需要更新 那么拿到更新的信息 和更新的地址:
1. 從服務(wù)端下載完整的dmg文件泥彤,把下載好的文件放在某個(gè)位置欲芹。
2. 自動(dòng)打開(kāi)dmg文件, 讓用戶將app文件拖入application 文件夾中吟吝,完成安裝菱父。
3. 遺留的dmg文件的處理。
1. 下載dmg文件
使用AFN進(jìn)行下載(暫時(shí)沒(méi)有斷點(diǎn)下載的需求)剑逃,將下載封裝成一個(gè)單獨(dú)的類浙宜,下載的操作為一個(gè)實(shí)例方法:
- (void)downloadDmgFileFromTargetUrl:(NSString *)targetUrl?? ? ? ? ? TodestinationFileNamePath:(NSString *)path ? ? ? ? ? ? ? ? ? ?
? ?? WithProgress:(void(^)(CGFloat progress))progressCallback? ? ?
? ? ?doneCallback:(void(^)(void))doneCallback?? ? ? ? ?
? ? ?errorCallback:(void(^)(NSString * errorDomine, NSInteger errorCode))errorCallback;
// targetUrl:為服務(wù)端的下載地址
//TodestinationFileNamePath: 下載為本地文件的路徑地址
//progressCallback :下載進(jìn)度的callback
//doneCall: 下載完成的callback
//errorCallback:出現(xiàn)錯(cuò)誤的callback
- (void)downloadDmgFileFromTargetUrl:(NSString *)targetUrl?? ? ? ? ? TodestinationFileNamePath:(NSString *)path? ? ? ? ? ? ? ? ? ? ? ? WithProgress:(void(^)(CGFloat progress))progressCallback? ? ? ? ? ? ? ? ? ? ? ? doneCallback:(void(^)(void))doneCallback?? ? ? ? ? ? ? ? ? ? ? errorCallback:(void(^)(NSString * errorDomine, NSInteger errorCode))errorCallback {
? ? AFURLSessionManager * manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];?
? NSURLRequest * request = [NSURLRequest requestWithURL: [NSURL URLWithString:targetUrl]];
? ? _downTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {? ? ?
? NSLog(@"下載進(jìn)度:%.0f%", downloadProgress.fractionCompleted * 100);? ? ? ? progressCallback(downloadProgress.fractionCompleted);
? ? } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {? ?
? ? return [NSURL fileURLWithPath:path];?
? } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {?
? ? ? if (!error) {? ? ?
? ? ? if (doneCallback) {? ? ? ? ?
? ? ? doneCallback();? ? ? ?
? ? }? ?
? ? } else {? ? ?
? ? ? if (errorCallback) {? ? ? ?
? ? ? ? errorCallback(error.domain, error.code);?
? ? ? ? ? }?
? ? ? }
? ? }];?? ?
? ? [_downTask resume];
} ??
文件下載好, 接下來(lái)要把這個(gè).dmg文件放在哪里呢蛹磺?
我最初的想法是放在Desktop文件夾中或者Downloads文件夾中粟瞬,但是如果這樣子放是不能夠打開(kāi)sandbox,要獲取到最高權(quán)限才可以萤捆,還有一點(diǎn)就是這樣子做有點(diǎn)流氓裙品,沒(méi)有經(jīng)過(guò)用戶的同意就把這個(gè)遺留的文件放在桌面俗批,如果是一個(gè)強(qiáng)迫癥的用戶的話,估計(jì)就受不了這樣子的一種行為市怎。
所以我的想法是岁忘,把這個(gè)安裝包文件放在document的cache文件夾中, 注意:如果要獲取正確的document文件夾, 一定要打開(kāi)沙盒權(quán)限, 否則找到的是系統(tǒng)的document.?
NSString * libraryDir = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)[0]; ?
?NSString * cachePath = [libraryDir stringByAppendingPathComponent:@"Caches"];?? ? NSString * lastDestinationFileName = [cachePath stringByAppendingPathComponent:@"XXXX.dmg"];
找好路徑,調(diào)用上面下載方法. 講dmg文件下載到Cache文件夾中. 但是此時(shí)只是下載好, 那么如何使用代碼來(lái)打開(kāi)這個(gè)文件呢?
想到的方法是使用NSTask來(lái)執(zhí)行Shell命令. 使用open命令來(lái)打開(kāi)已經(jīng)下載好的dmg文件. 參考網(wǎng)上的做法, 寫(xiě)了一個(gè)類, 單獨(dú)執(zhí)行某條shell命令
+ (NSString *)cmd:(NSString *)cmd {
? ? // 初始化并設(shè)置shell路徑
? ? NSTask *task = [[NSTask alloc] init];
? ? [task setLaunchPath: @"/bin/bash"]; ? ? // -c 用來(lái)執(zhí)行string-commands(命令字符串)区匠,也就說(shuō)不管后面的字符串里是什么都會(huì)被當(dāng)做shellcode來(lái)執(zhí)行 ?
? NSArray *arguments = [NSArray arrayWithObjects: @"-c", cmd, nil]; ?
? [task setArguments: arguments]; ?? ? ? ? // 新建輸出管道作為Task的輸出
? ? NSPipe *pipe = [NSPipe pipe]; ? ? [task setStandardOutput: pipe]; ?? ? ? ? // 開(kāi)始task ?
? NSFileHandle *file = [pipe fileHandleForReading]; ? ? [task launch]; ?? ? ? ? // 獲取運(yùn)行結(jié)果 ? ? NSData *data = [file readDataToEndOfFile]; ? ? return [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
}
下載好文件之后 執(zhí)行代碼?[XXXX cmd:[NSString stringWithFormat:@"cd %@; open xxx.dmg", cachePath]] 就可以自動(dòng)打開(kāi).
對(duì)于NSTask 剛剛接觸到, 還沒(méi)有時(shí)間去充分的理解里面的東西, 上面的方法是參考別的文章中 拿過(guò)來(lái)的, 若有不足之處, 望指出.