2012年8月29日 星期三

iOS - 下載 Zip File 並解壓縮

今天要來介紹一個方法,讓 iOS App 可以解開 Zip File,這樣一來 Server 端要給 iOS App 的文件就可以打包成比較小的 size ,而且可以減少 Server 傳資料到 iOS App 的時間。首先要準備好一個 Zip 檔和 Server 端的程式,可以參考這篇文章,把 mime type 改成 application/zip 就可以了。如下的設定

fs.stat(filename, function(error, stat) {
      if (error) { throw error; }
          res.writeHead(200, {
            'Content-Type' : 'application/zip',
            'Content-Length' : stat.size
          });
 });
Node.js 檔和 iOS 專案筆者放在 GitHub/iOS_unzip

接下來就是 iOS 的部分了,筆者採用的 Zip/Unzip 套件為 ZipArchive 提供的第三方套件。下載後會看到如下的資料夾內容。


接下來開啟 Single View Application。如下,命名為 UnzipDemo
把 ZipArchive 的檔案全加到 UnzipDemo 裡。如下
在 ZipArchive 的文件有提到,要在存案加入 libz.dylib。如下

加入之後會看到如下圖,才是正確的
加入之後,我們立馬 Compile 執行看看,卻看到如下的 Error
 

原來是 ZipArchive 這個專案有用到 dealloc 等 ARC 開啟時不允許的關鍵字,因為引入的檔案不多,直接把某幾個 file 設定會不支援 ARC 就好了,如下設定。

現在 Compile 就可以成功執行了。
接者來看到功能面,新增一個 UIButton 和連結一個  IBAction 如下圖
在 ViewController.m 新增如下程式碼,先來把 Server 的 developer.zip 下載到 Mac 某個資料夾。在這邊的例子,是用 GET 連結 http://127.0.0.1:8800/data?fileName=developer.zip 然後存到 /Users/chronoer/developer/developer.zip ,先做這樣的測試。

#define SERVER @"http://127.0.0.1:8800/data"
@interface ViewController (){
    NSString * fileName;
   
}
@property (strong) NSMutableData * tmpData;
@end

@implementation ViewController
@synthesize tmpData;
- (IBAction)downZip:(id)sender {
   fileName = @"developer.zip";     NSURL * fileURL = [NSURL URLWithString:[SERVER stringByAppendingFormat:@"?fileName=%@", fileName]];         NSURLRequest * urlRequest = [NSURLRequest requestWithURL:fileURL];     [NSURLConnection connectionWithRequest:urlRequest delegate:self]; } -(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{     [self.tmpData appendData:data]; } -(void) connectionDidFinishLoading:(NSURLConnection *)connection{ NSString * filePath = [[self fakeDoc] stringByAppendingFormat:@"/%@"fileName]; [[NSFileManager defaultManager] createFileAtPath:filePath contents:self.tmpData attributes:nil]; } -(NSString *) fakeDoc{ return @"/Users/chronoer/developer"; }
首先有一個 ivar fileName 用來設定要抓取的 zip 檔名,還有一個 tmpData,要去收集從 Server 來的 binary 的片段。在 downZip: 這個 IBAction 我們看到用 NSURLConnection 去連結 http://127.0.0.1:8800/data?fileName=developer.zip 然後指定 delegate 為 self,所以接下來至少要實作
 
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    [self.tmpData appendData:data];
}
 
-(void) connectionDidFinishLoading:(NSURLConnection *)connection{
    NSString * filePath = [[self fakeDoc] stringByAppendingFormat:@"/%@", fileName];
    [[NSFileManager defaultManager] createFileAtPath:filePath contents:self.tmpData attributes:nil]; 
}
這兩個 delegate method。其中

[self.tmpData appendData:data];
就是把每個 zip file 小片斷收集到 tmpData而整個檔案都收集完整就會呼叫 connectionDidFinishLoading: ,如下我們就把 self.tmpData 的完整資料存在 /Users/chronoer/developer/developer.zip。

  NSString * filePath = [[self fakeDoc] stringByAppendingFormat:@"/%@", fileName];
[[NSFileManager defaultManager] createFileAtPath:filePath contents:self.tmpData attributes:nil];
developer.zip 要預先放在 server 的資料夾,然後 /Users/chronoer/developer 這個目錄也要存在。
最後就是 unzip 的部分了,在 ViewController.m import 如下

#import "ZipArchive.h" 
 然後新增一個 method 為 unzipFile

-(void) unzipFile:(NSString * ) zipFilePath{
    ZipArchive *zipArchive = [[ZipArchive alloc] init];
    [zipArchive UnzipOpenFile:zipFilePath ];
    [zipArchive UnzipFileTo:[self fakeDoc] overWrite:YES];
    [zipArchive UnzipCloseFile]; }
非常單純的 4 個步驟,先 alloc ZipArchive 的物件,然後指定要開啟的 zip 檔,用

[zipArchive UnzipOpenFile:zipFilePath ];
再來就是把這個 zip 檔解壓縮到指定的目錄底下,並設定為 overWrite

[zipArchive UnzipFileTo:[self fakeDoc] overWrite:YES];
結束就是關掉和這個 zip 相關連結,

[zipArchive UnzipCloseFile];
好啦,今天教學到這,咱們下次見。

沒有留言:

張貼留言