cocos2dx上做边下边玩小包热更
因为公司业务需求需要做边下边玩的小包下载,在这里记录一下思路
下载库我使用的是cocos2dx 4.x的CCDownloader来下载文件
大体思路就是hook住fileutils中的getFileData函数和isFileExist函数。
isFileExist:无论初始包里文件是否存在,只要文件是游戏的资源文件这里都要返回“文件存在”
getFileData:这里判断当文件在文件列表中但是游戏包体里不存在该文件时,需要暂停主线程并且去下载文件,文件下载完成时恢复主线程
当暂停主线程时,下载文件的回调需要在子线程中回调否则无法回调成功
除上面的下载文件以外,主线程中根据缺少的文件列表按照一定策略持续下载缺少的文件(优先下载列表等)。
下面是一些主要的代码:
1 //使用条件变量暂停主线程 2 //继承了CCFileUtils文件 3 unsigned char* QFileUtils::getFileData(const char* pszFileName, const char* pszMode, unsigned long * pSize) 4 { 5 auto download = QDownloadSmallPack::getInstance(); 6 auto index = QIndex::getInstance(); 7 if (download->isStartCheckRes()) 8 { 9 bool hasFile = download->checkFile(pszFileName); 10 if (!hasFile) 11 { 12 QIndex::IndexEntry* filePathInIndex = index->getFilePathByIndex(pszFileName); 13 if (filePathInIndex && !filePathInIndex->name.empty()) 14 { 15 std::unique_lock<std::mutex> lock{_m}; 16 download->downloadFile(filePathInIndex, _cond_var); 17 18 if (!download->isDownloadOK) 19 { 20 _cond_var.wait(lock, [download](){ return download->isDownloadOK; }); 21 } 22 23 } 24 } 25 } 26 27 return CCFileUtils::getFileData(pszFileName, pszMode, pSize); 28 }
- (id)init: (const cocos2d::network::DownloaderApple*)o hints:(const cocos2d::network::DownloaderHints&) hints { DLLOG("Construct DownloaderAppleImpl %p", self); // save outer task ref _outer = o; _hints = hints; // create task dictionary self.taskDict = [NSMutableDictionary dictionary]; // create download session NSURLSessionConfiguration *defaultConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; if (hints.callBackInMainThread) { //在主线程中回调 self.downloadSession = [NSURLSession sessionWithConfiguration:defaultConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]]; } else { //在子线程中回调 self.downloadSession = [NSURLSession sessionWithConfiguration:defaultConfig delegate:self delegateQueue:nil]; } // self.downloadSession.sessionDescription = kCurrentSession; return self; }
//其他两个回调做同样的修改就好 void onProgress(final int id, final long downloadBytes, final long downloadNow, final long downloadTotal) { DownloadTask task = (DownloadTask)_taskMap.get(id); if (null != task) { task.bytesReceived = downloadBytes; task.totalBytesReceived = downloadNow; task.totalBytesExpected = downloadTotal; } if (_callBackInMainThread){ Cocos2dxHelper.getActivity().runOnGLThread(new Runnable() { @Override public void run() { nativeOnProgress(_id, id, downloadBytes, downloadNow, downloadTotal); } }); }else { //在子线程中回调 new Runnable() { @Override public void run() { nativeOnProgress(_id, id, downloadBytes, downloadNow, downloadTotal); } }.run(); } }
//cv是getfiledata中使用的条件变量 _downloader->onFileTaskSuccess = [this, &cv](const cocos2d::network::DownloadTask& task) { //做一些游戏自己的检测逻辑,确认文件下载完成之后这里设置条件变量并且通知主线程恢复 isDownloadOK = true; cv.notify_all(); };