前言:
- 這篇沒有太多技術細節以及底層知識,僅僅是解決需求的操作步驟以及解決方案。
- 代碼會放在Github上,希望大家一起討論下存在的問題,以及更好的解決方案。
- 正文的代碼大部分是偽代碼,供學習以及討論用,因此沒有寫太多防御式編程的思想,如果用于工作中,需要自己做好防御式編程的措施。
為防止有著同樣需求的伙伴無法通過關鍵字搜索到本文,所以將標題起的如此冗長以及不符合正常標題的起名規范,希望大家諒解,這篇文目的不是為了分享知識,而是為了解決需求以及問題,這個下載器是我們做H5游戲實時匹配對戰時用到一個小組件,簡要的說下實現原理。
需求如下
- 從后端API接口下載游戲壓縮包,并保存在本地。
- 在本地沙盒目錄進行解壓縮
- 解壓成功后保存在本地指定目錄,進行文件管理
- 如果版本號變更,需要將本地游戲刪除,并保存最新版本的H5游戲到本地
- 在本地搭建代理服務器,通過iOS本地服務器以及端口號,運行H5游戲。
我的思路
盡量用最簡潔的方法來實現功能,盡量用最新的API來解決技術場景,為了供大家理解流程。簡化不需要的冗余代碼。
一、關于API下載
下載流程圖
中文版
建立游戲模塊Model
主要用到的字段有:H5下載鏈接,游戲唯一標識符,游戲版本號字段等。
/**
* 游戲字段 Model
*/
@interface WPGGamePageGames : NSObject
// 游戲id
@property (nonatomic, copy) NSString *gameId;
// H5游戲版本
@property (nonatomic, copy) NSString *h5Version;
// H5游戲包下載
@property (nonatomic, copy) NSString *h5Down;
// H5游戲包MD5
@property (nonatomic, copy) NSString *h5Md5;
@end
調用 NSURLSession API進行請求下載
對NSURLSession進行初始化加載:
- (NSURLSession *)session
{
if (!_session) {
_session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
delegate:self delegateQueue:[NSOperationQueue mainQueue]];
}
return _session;
}
建立一個下載請求,如果不需要斷點續傳,可以自動忽略 (void)pause 和 (void)resume 方法。
@property (nonatomic, strong) NSURLSessionDownloadTask *task;
@property (nonatomic, strong) NSData *resumeData;
// 開始創建下載請求并進行下載(_gameModel.h5Down 為H5游戲的下載鏈接)
- (void)start
{
NSURL *url = [NSURL URLWithString:_gameModel.h5Down];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"GET";
self.task = [self.session downloadTaskWithRequest:request];
[self.task resume];
}
// 暫停下載請求
- (void)pause
{
__weak __typeof(self) weakSelf = self;
[self.task cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
weakSelf.resumeData = resumeData;
weakSelf.task = nil;
}];
}
// 恢復下載請求進行斷點續傳
- (void)resume
{
self.task = [self.session downloadTaskWithResumeData:self.resumeData];
[self.task resume];
self.resumeData = nil;
}
4個重要下載回調代理如下:
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
// 展示下載進度
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
// 下載成功
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
if (error) {
// 下載失敗
}
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{
// 斷點續傳的代理
}
二、在本地沙盒目錄進行解壓縮
解壓縮需要用到第三方庫,SSZipArchive下載地址如下:https://github.com/ZipArchive/ZipArchive
注意 SSZipArchive 引入到工程時需要添加 libz.tbd 庫,否則編譯時通不過。使用SSZipArchive解壓文件的方法為:
BOOL ret1 = [SSZipArchive unzipFileAtPath:file toDestination:destination delegate:self];
if (!ret1) {
NSLog(@"解壓失敗");
return;
}
SSZipArchive解壓縮的代理方法如下
- (void)zipArchiveWillUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo
{
NSLog(@"將要解壓。");
}
- (void)zipArchiveDidUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo unzippedPath:(NSString *)unzippedPath
{
NSLog(@"解壓完成!");
}
關于SSZipArchive所有方法說明詳細API以及調用方法,已放在附錄欄中,不在正文說明。
三、文件管理
當游戲較多的時候,我們需要進行本地管理,我的管理目錄如下:
Library/Caches/Game/(文件夾名為:GameId)/H5游戲資源存放的地方
由于GameId為所有H5游戲的唯一標識符,所以我的做法是將所有H5游戲存放在Caches/Game/文件目錄下,文件路徑命名為GameId,這便不會出現游戲重名導致游戲覆蓋安裝的情況。
當版本更新的時候,之前存在沙盒目錄中的游戲需要刪除,并重新下載安裝,我通過本地數據庫去存取版本信息。當然首先要裝一個本地數據庫,我是通過FMDB第三方庫進行管理。
數據表字段如下:Id(自增Id),gameId(游戲唯一標識符),version(游戲版本號),exist(文件是否在本地存在)
版本管理業務邏輯:
1)若數據庫表中GameId存在,版本號在數據庫列表中不存在,則刪除本地GameId的文件夾進行下載
2)若數據庫表中GameId不存在,則直接進行下載H5游戲保存在本地
3)若數據庫表中GameId存在且版本號也存在,則直接讀取Library/Caches/Game/(文件夾名為:GameId)目錄,加載H5游戲資源。
4)當游戲下載成功后解壓到Library/Caches/Game/(文件夾名為:GameId)目錄下,將數據庫寫入最新的GameId,version字段寫入數據表中。表明本地存在Gameid=XX,version=X.X.X的H5游戲。
本地數據庫操作代碼如下:
#import "FMDB.h"
static WPGameDownloader *_instance;
@interface WPGameDownloader() <NSURLSessionDownloadDelegate, SSZipArchiveDelegate>
{
FMDatabase *_db;
}
+ (instancetype)shareManager
{
if (!_instance) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
}
return _instance;
}
- (id)init
{
if (self = [super init]) {
_queenArray = [NSMutableArray new];
_isDownloading = NO;
[self createTable];
}
return self;
}
// 創建表
- (void)createTable
{
//先打開數據庫,然后創建表,最后關閉數據庫
if (![self openDataBase]) {
return;
}
//tableExists 判斷表是否存在,當表不存在的時候再去創建 參數:表名
if (![_db tableExists:@"Game_Version_isExist"]) {
NSString *sql = @"CREATE TABLE IF NOT EXISTS Game_Version_IsExist ('ID' INTEGER PRIMARY KEY AUTOINCREMENT,'gameid' TEXT NOT NULL, 'version' TEXT NOT NULL,'exist' INTEGER NOT NULL)";
BOOL result = [_db executeUpdate:sql];
if (result) {
NSLog(@"create table success");
}
}
[_db close];
}
// 打印全部數據
- (void)printAllData
{
if (![self openDataBase]) {
return;
}
FMResultSet *set = [_db executeQuery:@"SELECT * FROM Game_Version_isExist"];
// next 單步查詢
while ([set next]) {組
NSLOG(@"===%d,%@,%@,%d", [set intForColumnIndex:0],[set stringForColumn:@"gameid"],[set stringForColumn:@"version"],[set intForColumn:@"exist"]);
}
[set close];
[_db close];
}
// 查詢全部數據
- (NSMutableArray *)selectAllData
{
if (![self openDataBase]) {
return nil;
}
FMResultSet *set = [_db executeQuery:@"SELECT * FROM Game_Version_isExist"];
NSMutableArray *array = [NSMutableArray array];
// next 單步查詢
while ([set next]) {
//把每一條數據(包含id,name,phone),存入一個對象,再把對象放入數組
WPGameDataBaseModel *game = [[WPGameDataBaseModel alloc] init];
game.auto_id = [set intForColumnIndex:0];
game.gameId = [set stringForColumn:@"gameid"];
game.version = [set stringForColumn:@"version"];
game.value = [set intForColumn:@"exist"];
//把查詢的每一條數據分別放入數組
[array addObject:game];
}
[set close];
[_db close];
return array;
}
- (BOOL)searchDataGameId:(NSString *)gameId versiton:(NSString *)version
{
[self printAllData];
if (![self openDataBase]) {
return NO;
}
NSString *sql = [NSString stringWithFormat:@"SELECT * FROM Game_Version_isExist WHERE gameid = %@ and version = '%@'", gameId,version];
FMResultSet *set = [_db executeQuery:sql];
BOOL returnValue = NO;
while ([set next]) {
returnValue = YES;
}
[set close];
[_db close];
return returnValue;
}
// 增加數據
- (void)inserIntoData:(WPGameDataBaseModel *)gameModel
{
if ([self openDataBase]) {
[_db executeUpdateWithFormat:@"DELETE FROM Game_Version_IsExist WHERE gameid = %@", gameModel.gameId];
[_db executeUpdateWithFormat:@"INSERT INTO Game_Version_IsExist (gameid, version, exist) VALUES (%@,%@,%d)",gameModel.gameId, gameModel.version,gameModel.value];
[_db close];
}
}
// 通過gameId進行修改
- (void)updateData:(WPGameDataBaseModel *)gameModel
{
//根據id找到具體的聯系人
if ([self openDataBase]) {
[_db executeUpdateWithFormat:@"UPDATE Game_Version_IsExist SET version = %@, exist = %d WHERE gameid = %@",gameModel.version,gameModel.value,gameModel.gameId];
[_db close];
}
}
// 刪除
- (void)deleteData:(NSString *)game_id
{
if ([self openDataBase]) {
//根據聯系人的id進行刪除
[_db executeUpdateWithFormat:@"DELETE FROM Game_Version_IsExist WHERE gameid = %@",game_id];
[_db close];
}
}
三、通過代理服務器運行H5游戲
JS游戲想要運行到iOS設備的WebView, 是需要自己搭建一套Web Server的。通過CocoaHTTPServer三方庫的這個可以滿足我們的需求,CocoaHTTPServer是個很強大的三方庫,不但可以通過加載H5游戲運行在本地,還能通過ip局域網和電腦傳輸文件,作用強大。
項目中, 我使用了 Cocoapods 來管理第三方庫.在 podfile 中直接添加下面的代碼:
pod 'CocoaHTTPServer', '~> 2.3'
然后 pod install 即可
主要的核心代碼如下:
@property (nonatomic, strong) HTTPServer *localHttpServer;
- (void)_configLocalHttpServer
{
NSString *webPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches/Game/snake/game/"];
_localHttpServer = [[HTTPServer alloc] init];
[_localHttpServer setType:@"_http.tcp"];
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSLog(@"%@", webPath);
if (![fileManager fileExistsAtPath:webPath]) {
NSLog(@"File path error!");
}
else {
NSString *webLocalPath = webPath;
[_localHttpServer setDocumentRoot:webLocalPath];
NSLog(@"webLocalPath:%@", webLocalPath);
[self _startWebServer];
}
}
- (void)_startWebServer
{
NSError *error;
if ([_localHttpServer start:&error]) {
NSLog(@"Started HTTP Server on port %hu", [_localHttpServer listeningPort]);
NSLog(@"Start Server Successfully.");
self.port = [NSString stringWithFormat:@"%d", [_localHttpServer listeningPort]];
_startServerSuccess = YES;
UIWebView *webView = [[UIWebView alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
[self.view addSubview:webView];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://127.0.0.1:%@/index.html", self.port]];
[webView loadRequest:[NSURLRequest requestWithURL:url]];
}
else {
NSLog(@"Error starting HTTP Server: %@", error);
_startServerSuccess = NO;
}
}
到這里流程就已經跑通了,然后說一下我下載器的實現。
我的實現
代理以及方法
.h文件所提供的方法如下:
- 通過 isExistGame:gameModel 方法來判斷本地是否存在這個H5游戲。
- 通過 downloadGameModel:gameModel 方法來下載游戲,下載多個游戲的時候,是通過串行隊列的方式進行下載。
- 下載進度在delegate中進行監聽,下載成功或者失敗也在delegate中進行監聽
@protocol WPGameDownloaderDelegate <NSObject>
// 下載成功回調(通過gameId判斷是否為本次下載任務)
- (void)downloadSuccess:(WPGameDownloader *)gamedownloader gameId:(NSString *)gameId;
// 下載失敗回調(通過gameId判斷是否為本次下載任務)
- (void)downloadFail:(WPGameDownloader *)gamedownloader gameId:(NSString *)gameId;
// 下載進度回調(通過gameId判斷是否為本次下載任務)
- (void)downloadProgress:(NSInteger)progress gamedownloader:(WPGameDownloader *)gamedownloader gameId:(NSString *)gameId;
@end
@interface WPGameDownloader : NSObject
@property (nonatomic, weak) id <WPGameDownloaderDelegate> delegate;
// 單例
+ (instancetype)shareManager;
// 下載游戲
- (void)downloadGameModel:(WPGGamePageGames *)gameModel;
// 游戲是否下載到本地
- (BOOL)isExistGame:(WPGGamePageGames *)gameModel;
@end
聲明變量并用單例進行實現
通過單例對H5游戲下載器進行更安全的控制,以防止并行下載會出現的問題,以及多線程同時讀寫數據庫出現的問題。
@interface WPGameDownloader() <NSURLSessionDownloadDelegate, SSZipArchiveDelegate>
{
FMDatabase *_db;
}
@property (nonatomic, strong) NSURLSession *session;
@property (nonatomic, strong) NSURLSessionDownloadTask *task;
@property (nonatomic, strong) NSMutableArray *queenArray;
@property (nonatomic, strong) WPGGamePageGames *gameModel;
@property (nonatomic, assign) BOOL isDownloading;
@end
@implementation WPGameDownloader
+ (instancetype)shareManager
{
if (!_instance) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
}
return _instance;
}
- (id)init
{
if (self = [super init]) {
_queenArray = [NSMutableArray new];
_isDownloading = NO;
[self createTable];
}
return self;
}
下載器已經將代碼放入github中,關于下載器的部分下載操作如下:
- (BOOL)isExistGame:(WPGGamePageGames *)gameModel
{
return [self searchDataGameId:gameModel.gameId versiton:gameModel.h5Version];
}
- (void)downloadGameModel:(WPGGamePageGames *)gameModel
{
[_queenArray addObject:gameModel];
[self startDownLoad];
}
- (void)startDownLoad
{
if (_queenArray.count<=0) {
return;
}
if (_isDownloading) {
return;
}
_isDownloading = YES;
_gameModel = [_queenArray cl_objectAtIndex:0];
[_queenArray cl_removeObjectAtIndex:0];
[self start];
}
- (void)removefile
{
NSFileManager *manager = [NSFileManager defaultManager];
NSString *docsDir = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"Library/Caches/Game/%@/", _gameModel.gameId]];
[manager removeItemAtPath:docsDir error:nil];
}
- (void)downloadFailed
{
_isDownloading = NO;
IDSLOG(@"FAILED : GAMEID: %@", _gameModel.gameId);
[self removefile];
[self.session finishTasksAndInvalidate];
_session = nil;
if ([self.delegate respondsToSelector:@selector(downloadFail:gameId:)]) {
[self.delegate downloadFail:self gameId:_gameModel.gameId];
}
[self startDownLoad];
}
- (void)downloadSuccess
{
IDSLOG(@"SUEECSS : GAMEID: %@", _gameModel.gameId);
WPGameDataBaseModel *model = [[WPGameDataBaseModel alloc] init];
model.gameId = _gameModel.gameId;
model.version = _gameModel.h5Version;
model.value = 1;
[self inserIntoData:model];
if ([self.delegate respondsToSelector:@selector(downloadSuccess:gameId:)]) {
[self.delegate downloadSuccess:self gameId:model.gameId];
}
_isDownloading = NO;
[self startDownLoad];
}
- (void)start
{
NSURL *url = [NSURL URLWithString:_gameModel.h5Down];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"GET";
self.task = [self.session downloadTaskWithRequest:request];
[self.task resume];
}
# pragma mark - delegate
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
if ([self.delegate respondsToSelector:@selector(downloadProgress:gamedownloader:gameId:)]) {
[self.delegate downloadProgress:(totalBytesWritten*100/totalBytesExpectedToWrite) gamedownloader:self gameId:_gameModel.gameId];
}
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location;
{
[self createGameFolder];
[self createGameFolderName:_gameModel.gameId];
NSString *docPath = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"Library/Caches/Game/%@/", _gameModel.gameId]];
NSString *file = [docPath stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
NSError *error = nil;
NSFileManager *manager = [NSFileManager defaultManager];
BOOL result = [manager fileExistsAtPath:location.path];
NSLog(@"移動之前 這個文件已經存在:%@",result?@"是的":@"不存在");
if ([manager fileExistsAtPath:location.path]) {
NSLog(@"移動之前文件大小為: %.1fM", [[manager attributesOfItemAtPath:location.path error:nil] fileSize]/1000000.0);
}
if (![[manager attributesOfItemAtPath:location.path error:nil] fileSize]) {
NSLog(@"文件為空返回");
return;
}
// 判斷文件是否存在
BOOL ret = [manager moveItemAtPath:location.path toPath:file error:&error];
if (!ret) {
NSLog(@"MOVE FILE IS WRONG");
}
if (error) {
NSLog(@"move failed:%@", [error localizedDescription]);
}
BOOL resultdd = [manager fileExistsAtPath:file];
NSLog(@"移動之后 這個文件已經存在:%@",resultdd?@"是的":@"不存在");
NSLog(@"儲存路徑 移動之后:%@, \n移動之前:%@",file,location.path);
NSString *destination = [NSString stringWithFormat:@"%@/", docPath];
BOOL ret1 = [SSZipArchive unzipFileAtPath:file toDestination:destination delegate:self];
if (!ret1) {
NSLog(@"解壓失敗");
[self downloadFailed];
return;
}
[manager removeItemAtPath:file error:nil];
// 遍歷文件
NSDirectoryEnumerator *dirEnum = [manager enumeratorAtPath:docPath];
NSString *fileName;
while (fileName = [dirEnum nextObject]) {
NSLog(@"FileFull>>> : %@" , [docPath stringByAppendingPathComponent:fileName]) ;
}
[self downloadSuccess];
}
- (long long)fileSizeAtPath:(NSString *)filePath {
NSFileManager *manager = [NSFileManager defaultManager];
if ([manager fileExistsAtPath:filePath]) {
return [[manager attributesOfItemAtPath:filePath error:nil] fileSize];
}
return 0;
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
if (error) {
[self downloadFailed];
}
}
寫在最后
上面的例子本人親自實踐過的, 給大家提供了一個實現思路, 算是拋磚引玉.
如果想做好這個模式, 還需要很多工作要做, 這里列出來給大家分享一下.
1.游戲資源包管理和下載.
2.游戲中需要和 Native 的交互邏輯.
3.數據加密.
4.移動端游戲本身的加載優化.
代碼示例我放在了 GitHub上。
下載器代碼如下:https://github.com/Yulei-Duan/WPGameDownloader
游戲代理服務器代碼如下:https://github.com/Yulei-Duan/testProjestAboutGameRun
有問題,請在下面評論, 非常感謝能來看我的Demo分享!
附錄
SSZipArchive所有方法說明
@interface SSZipArchive : NSObject
// Unzip 解壓
/**
* @param path 源文件
* @param destination 目的文件
* @param uniqueId 標記,用于區別多個解壓操作
*
* @return 返回 YES 表示成功,返回 NO 表示解壓失敗。
*/
+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination uniqueId:(NSString *)uniqueId;
/**
* @param path 源文件
* @param destination 目的文件
* @param overwrite YES 會覆蓋 destination 路徑下的同名文件,NO 則不會。
* @param password 需要輸入密碼的才能解壓的壓縮包
* @param error 返回解壓時遇到的錯誤信息
* @param uniqueId 標記,用于區別多個解壓操作
*
* @return 返回 YES 表示成功,返回 NO 表示解壓失敗。
*/
+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error uniqueId:(NSString *)uniqueId;
/**
* @param path 源文件
* @param destination 目的文件
* @param delegate 設置代理
* @param uniqueId 標記,用于區別多個解壓操作
*
* @return 返回 YES 表示成功,返回 NO 表示解壓失敗。
*/
+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(id<SSZipArchiveDelegate>)delegate uniqueId:(NSString *)uniqueId;
/**
* @param path 源文件
* @param destination 目的文件
* @param overwrite YES 會覆蓋 destination 路徑下的同名文件,NO 則不會。
* @param password 需要輸入密碼的才能解壓的壓縮包
* @param error 返回解壓時遇到的錯誤信息
* @param delegate 設置代理
* @param uniqueId 標記,用于區別多個解壓操作
*
* @return 返回 YES 表示成功,返回 NO 表示解壓失敗。
*/
+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error delegate:(id<SSZipArchiveDelegate>)delegate uniqueId:(NSString *)uniqueId;
// Zip 壓縮
/**
* @param path 目的路徑(格式:~/xxx.zip 結尾的路徑)
* @param filenames 要壓縮的文件路徑
*
* @return 返回 YES 表示成功,返回 NO 表示壓縮失敗。
*/
+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)filenames;
/**
* @param path 目的路徑(格式:~/xxx.zip 結尾的路徑)
* @param filenames 要壓縮的文件目錄路徑
*
* @return 返回 YES 表示成功,返回 NO 表示壓縮失敗。
*/
+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath;
/**
* 初始化壓縮對象
*
* @param path 目的路徑(格式:~/xxx.zip 結尾的路徑)
*
* @return 初始化后的對像
*/
- (id)initWithPath:(NSString *)path;
/**
* 打開壓縮對象
* @return 返回 YES 表示成功,返回 NO 表示失敗。
*/
- (BOOL)open;
/**
* 添加要壓縮的文件的路徑
*
* @param path 文件路徑
*
* @return 返回 YES 表示成功,返回 NO 表示失敗。
*/
- (BOOL)writeFile:(NSString *)path;
/**
* 向此路徑的文件里寫入數據
*
* @param data 要寫入的數據
* @param filename 文件路徑
*
* @return 返回 YES 表示成功,返回 NO 表示失敗。
*/
- (BOOL)writeData:(NSData *)data filename:(NSString *)filename;
/**
* 關閉壓縮對象
* @return 返回 YES 表示成功,返回 NO 表示失敗。
*/
- (BOOL)close;
@end
@protocol SSZipArchiveDelegate <NSObject>
@optional
//將要解壓
- (void)zipArchiveWillUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo;
//解壓完成
- (void)zipArchiveDidUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo unzippedPath:(NSString *)unzippedPat uniqueId:(NSString *)uniqueId;
//將要解壓
- (void)zipArchiveWillUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;
//解壓完成
- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;
@end