cocos2d热更新代码分析
发布时间:2020-12-14 17:03:20 所属栏目:百科 来源:网络整理
导读:cocos2d热更新代码分析 #include "AssetsManagerEx.h" #include "CCEventListenerAssetsManagerEx.h" #include "deprecated/CCString.h" #include "base/CCDirector.h" #include curl/curl.h #include curl/easy.h #include stdio.h #ifdef MINIZIP_FROM_SYS
cocos2d热更新代码分析#include "AssetsManagerEx.h"
#include "CCEventListenerAssetsManagerEx.h"
#include "deprecated/CCString.h"
#include "base/CCDirector.h"
#include <curl/curl.h>
#include <curl/easy.h>
#include <stdio.h>
#ifdef MINIZIP_FROM_SYSTEM
#include <minizip/unzip.h>
#else // from our embedded sources
#include "unzip.h"
#endif
using namespace cocos2d;
using namespace std;
NS_CC_EXT_BEGIN
#define VERSION_FILENAME "version.manifest"
#define TEMP_MANIFEST_FILENAME "project.manifest.temp"
#define MANIFEST_FILENAME "project.manifest"
#define BUFFER_SIZE 8192
#define MAX_FILENAME 512
#define DEFAULT_CONNECTION_TIMEOUT 8
const std::string AssetsManagerEx::VERSION_ID = "@version";
const std::string AssetsManagerEx::MANIFEST_ID = "@manifest";
const std::string AssetsManagerEx::BATCH_UPDATE_ID = "@batch_update";
// Implementation of AssetsManagerEx
//read AssetsManagerEx 顺序
/** initManifests loadLocalManifest checkUpdate downloadVersion 下载服务器版本文件 onSuccess--VERSION_ID ( 解析服务器版本配置文件,如果服务器版本和本地版本不一样,给出通知需要更新:_updateState = State::NEED_UPDATE; 否则通知不需要更新 _updateState = State::UP_TO_DATE; ) --如果需要更新,客户端需要主动调update方法 update 由于_remoteManifest没有解析详细配置文件,所以需要去下载详细配置文件 downloadManifest (下载到_tempManifestPath) parseManifest _remoteMaifest解析服务器详细配置文件 startUpdate */
/** params: manifestUrl:apk中的配置文件 storagePath:热更新下载到的文件目录 content: _cacheVersionPath:本地缓存的版本配置文件 _cacheManifestPath:本地下载的详细配置文件(详细是指包括了需要下载的文件,而不仅仅是版本配置文件) _tempManifestPath:下载热更新包时的临时配置文件 */
AssetsManagerEx::AssetsManagerEx(const std::string& manifestUrl,const std::string& storagePath)
: _updateState(State::UNCHECKED),_assets(nullptr),_storagePath(""),_cacheVersionPath(""),_cacheManifestPath(""),_tempManifestPath(""),_manifestUrl(manifestUrl),_localManifest(nullptr),_tempManifest(nullptr),_remoteManifest(nullptr),_waitToUpdate(false),_percent(0),_percentByFile(0),_totalToDownload(0),_totalWaitToDownload(0),_inited(false)
{
// Init variables
_eventDispatcher = Director::getInstance()->getEventDispatcher();
std::string pointer = StringUtils::format("%p",this);
_eventName = EventListenerAssetsManagerEx::LISTENER_ID + pointer;
_fileUtils = FileUtils::getInstance();
_updateState = State::UNCHECKED;
_downloader = std::make_shared<Downloader>();
_downloader->setConnectionTimeout(DEFAULT_CONNECTION_TIMEOUT);
_downloader->_onError = std::bind(&AssetsManagerEx::onError,this,std::placeholders::_1);
_downloader->_onProgress = std::bind(&AssetsManagerEx::onProgress,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4);
_downloader->_onSuccess = std::bind(&AssetsManagerEx::onSuccess,std::placeholders::_3);
setStoragePath(storagePath);
_cacheVersionPath = _storagePath + VERSION_FILENAME;
_cacheManifestPath = _storagePath + MANIFEST_FILENAME;
_tempManifestPath = _storagePath + TEMP_MANIFEST_FILENAME;
initManifests(manifestUrl);
}
AssetsManagerEx::~AssetsManagerEx()
{
_downloader->_onError = nullptr;
_downloader->_onSuccess = nullptr;
_downloader->_onProgress = nullptr;
CC_SAFE_RELEASE(_localManifest);
// _tempManifest could share a ptr with _remoteManifest or _localManifest
if (_tempManifest != _localManifest && _tempManifest != _remoteManifest)
CC_SAFE_RELEASE(_tempManifest);
CC_SAFE_RELEASE(_remoteManifest);
}
AssetsManagerEx* AssetsManagerEx::create(const std::string& manifestUrl,const std::string& storagePath)
{
AssetsManagerEx* ret = new (std::nothrow) AssetsManagerEx(manifestUrl,storagePath);
if (ret)
{
ret->autorelease();
}
else
{
CC_SAFE_DELETE(ret);
}
return ret;
}
void AssetsManagerEx::initManifests(const std::string& manifestUrl)
{
_inited = true;
// Init and load local manifest
_localManifest = new (std::nothrow) Manifest();
if (_localManifest)
{
loadLocalManifest(manifestUrl);
// Init and load temporary manifest
_tempManifest = new (std::nothrow) Manifest();
if (_tempManifest)
{
_tempManifest->parse(_tempManifestPath); //获取临时下载热更新的配置文件
if (!_tempManifest->isLoaded())
_fileUtils->removeFile(_tempManifestPath);
}
else
{
_inited = false;
}
// Init remote manifest for future usage
_remoteManifest = new (std::nothrow) Manifest();
if (!_remoteManifest)
{
_inited = false;
}
}
else
{
_inited = false;
}
if (!_inited)
{
CC_SAFE_DELETE(_localManifest);
CC_SAFE_DELETE(_tempManifest);
CC_SAFE_DELETE(_remoteManifest);
}
}
void AssetsManagerEx::prepareLocalManifest()
{
// An alias to assets
_assets = &(_localManifest->getAssets());
// Add search paths
_localManifest->prependSearchPaths();
}
void AssetsManagerEx::loadLocalManifest(const std::string& manifestUrl)
{
Manifest *cachedManifest = nullptr;
// Find the cached manifest file
if (_fileUtils->isFileExist(_cacheManifestPath))
{
cachedManifest = new (std::nothrow) Manifest();
if (cachedManifest) {
cachedManifest->parse(_cacheManifestPath);
if (!cachedManifest->isLoaded())
{
_fileUtils->removeFile(_cacheManifestPath);
CC_SAFE_RELEASE(cachedManifest);
cachedManifest = nullptr;
}
}
}
//首先获取apk中的配置文件
// Load local manifest in app package
_localManifest->parse(_manifestUrl);
if (_localManifest->isLoaded())
{
// Compare with cached manifest to determine which one to use
if (cachedManifest) {
if (strcmp(_localManifest->getVersion().c_str(),cachedManifest->getVersion().c_str()) > 0) //如果apk中的版本比本地缓存的版本还大,说明需要更新apk包
{
//如果需要更新apk包,移除 配置文件放置的目录
// Recreate storage,to empty the content
_fileUtils->removeDirectory(_storagePath);
_fileUtils->createDirectory(_storagePath);
CC_SAFE_RELEASE(cachedManifest);
}
else
{
CC_SAFE_RELEASE(_localManifest);
_localManifest = cachedManifest; //本地有配置文件就用本地的,否则就用apk中自带的配置文件
}
}
prepareLocalManifest();
}
// Fail to load local manifest
if (!_localManifest->isLoaded())
{
CCLOG("AssetsManagerEx : No local manifest file found error.n");
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
}
}
std::string AssetsManagerEx::basename(const std::string& path) const
{
size_t found = path.find_last_of("/");
if (std::string::npos != found)
{
return path.substr(0,found);
}
else
{
return path;
}
}
std::string AssetsManagerEx::get(const std::string& key) const
{
auto it = _assets->find(key);
if (it != _assets->cend()) {
return _storagePath + it->second.path;
}
else return "";
}
const Manifest* AssetsManagerEx::getLocalManifest() const
{
return _localManifest;
}
const Manifest* AssetsManagerEx::getRemoteManifest() const
{
return _remoteManifest;
}
const std::string& AssetsManagerEx::getStoragePath() const
{
return _storagePath;
}
void AssetsManagerEx::setStoragePath(const std::string& storagePath)
{
_storagePath = storagePath;
adjustPath(_storagePath);
_fileUtils->createDirectory(_storagePath);
}
void AssetsManagerEx::adjustPath(std::string &path)
{
if (path.size() > 0 && path[path.size() - 1] != '/')
{
path.append("/");
}
}
bool AssetsManagerEx::decompress(const std::string &zip)
{
// Find root path for zip file
size_t pos = zip.find_last_of("/");
if (pos == std::string::npos)
{
CCLOG("AssetsManagerEx : no root path specified for zip file %sn",zip.c_str());
return false;
}
const std::string rootPath = zip.substr(0,pos+1);
// Open the zip file
unzFile zipfile = unzOpen(zip.c_str());
if (! zipfile)
{
CCLOG("AssetsManagerEx : can not open downloaded zip file %sn",zip.c_str());
return false;
}
// Get info about the zip file
unz_global_info global_info;
if (unzGetGlobalInfo(zipfile,&global_info) != UNZ_OK)
{
CCLOG("AssetsManagerEx : can not read file global info of %sn",zip.c_str());
unzClose(zipfile);
return false;
}
// Buffer to hold data read from the zip file
char readBuffer[BUFFER_SIZE];
// Loop to extract all files.
uLong i;
for (i = 0; i < global_info.number_entry; ++i)
{
// Get info about current file.
unz_file_info fileInfo;
char fileName[MAX_FILENAME];
if (unzGetCurrentFileInfo(zipfile,&fileInfo,fileName,MAX_FILENAME,NULL,0,0) != UNZ_OK)
{
CCLOG("AssetsManagerEx : can not read compressed file infon");
unzClose(zipfile);
return false;
}
const std::string fullPath = rootPath + fileName;
// Check if this entry is a directory or a file.
const size_t filenameLength = strlen(fileName);
if (fileName[filenameLength-1] == '/')
{
//There are not directory entry in some case.
//So we need to create directory when decompressing file entry
if ( !_fileUtils->createDirectory(basename(fullPath)) )
{
// Failed to create directory
CCLOG("AssetsManagerEx : can not create directory %sn",fullPath.c_str());
unzClose(zipfile);
return false;
}
}
else
{
// Entry is a file,so extract it.
// Open current file.
if (unzOpenCurrentFile(zipfile) != UNZ_OK)
{
CCLOG("AssetsManagerEx : can not extract file %sn",fileName);
unzClose(zipfile);
return false;
}
// Create a file to store current file.
FILE *out = fopen(fullPath.c_str(),"wb");
if (!out)
{
CCLOG("AssetsManagerEx : can not create decompress destination file %sn",fullPath.c_str());
unzCloseCurrentFile(zipfile);
unzClose(zipfile);
return false;
}
// Write current file content to destinate file.
int error = UNZ_OK;
do
{
error = unzReadCurrentFile(zipfile,readBuffer,BUFFER_SIZE);
if (error < 0)
{
CCLOG("AssetsManagerEx : can not read zip file %s,error code is %dn",error);
fclose(out);
unzCloseCurrentFile(zipfile);
unzClose(zipfile);
return false;
}
if (error > 0)
{
fwrite(readBuffer,error,1,out);
}
} while(error > 0);
fclose(out);
}
unzCloseCurrentFile(zipfile);
// Goto next entry listed in the zip file.
if ((i+1) < global_info.number_entry)
{
if (unzGoToNextFile(zipfile) != UNZ_OK)
{
CCLOG("AssetsManagerEx : can not read next file for decompressingn");
unzClose(zipfile);
return false;
}
}
}
unzClose(zipfile);
return true;
}
void AssetsManagerEx::decompressDownloadedZip()
{
// Decompress all compressed files
for (auto it = _compressedFiles.begin(); it != _compressedFiles.end(); ++it) {
std::string zipfile = *it;
if (!decompress(zipfile))
{
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DECOMPRESS,"","Unable to decompress file " + zipfile);
}
_fileUtils->removeFile(zipfile);
}
_compressedFiles.clear();
}
void AssetsManagerEx::dispatchUpdateEvent(EventAssetsManagerEx::EventCode code,const std::string &assetId/* = ""*/,const std::string &message/* = ""*/,int curle_code/* = CURLE_OK*/,int curlm_code/* = CURLM_OK*/)
{
EventAssetsManagerEx event(_eventName,code,_percent,_percentByFile,assetId,message,curle_code,curlm_code);
_eventDispatcher->dispatchEvent(&event);
}
AssetsManagerEx::State AssetsManagerEx::getState() const
{
return _updateState;
}
void AssetsManagerEx::downloadVersion()
{
if (_updateState > State::PREDOWNLOAD_VERSION)
return;
std::string versionUrl = _localManifest->getVersionFileUrl();
if (versionUrl.size() > 0)
{
_updateState = State::DOWNLOADING_VERSION;
// Download version file asynchronously
_downloader->downloadAsync(versionUrl,_cacheVersionPath,VERSION_ID);
}
// No version file found
else
{
CCLOG("AssetsManagerEx : No version file found,step skippedn");
_updateState = State::PREDOWNLOAD_MANIFEST;
downloadManifest();
}
}
void AssetsManagerEx::parseVersion()
{
if (_updateState != State::VERSION_LOADED)
return;
_remoteManifest->parseVersion(_cacheVersionPath); //解析下载到本地的服务器版本文件
if (!_remoteManifest->isVersionLoaded())
{
CCLOG("AssetsManagerEx : Fail to parse version file,step skippedn");
_updateState = State::PREDOWNLOAD_MANIFEST;
downloadManifest();
}
else
{
if (_localManifest->versionEquals(_remoteManifest))
{
_updateState = State::UP_TO_DATE;
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE);
}
else
{
_updateState = State::NEED_UPDATE;
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND);
// Wait to update so continue the process
if (_waitToUpdate)
{
_updateState = State::PREDOWNLOAD_MANIFEST;
downloadManifest();
}
}
}
}
void AssetsManagerEx::downloadManifest()
{
if (_updateState != State::PREDOWNLOAD_MANIFEST)
return;
std::string manifestUrl = _localManifest->getManifestFileUrl();
if (manifestUrl.size() > 0)
{
_updateState = State::DOWNLOADING_MANIFEST;
// Download version file asynchronously
_downloader->downloadAsync(manifestUrl,_tempManifestPath,MANIFEST_ID);
}
// No manifest file found
else
{
CCLOG("AssetsManagerEx : No manifest file found,check update failedn");
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST);
_updateState = State::UNCHECKED;
}
}
void AssetsManagerEx::parseManifest()
{
if (_updateState != State::MANIFEST_LOADED)
return;
_remoteManifest->parse(_tempManifestPath);
if (!_remoteManifest->isLoaded())
{
CCLOG("AssetsManagerEx : Error parsing manifest filen");
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_PARSE_MANIFEST);
_updateState = State::UNCHECKED;
}
else
{
if (_localManifest->versionEquals(_remoteManifest))
{
_updateState = State::UP_TO_DATE;
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE);
}
else
{
_updateState = State::NEED_UPDATE;
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND);
if (_waitToUpdate)
{
startUpdate();
}
}
}
}
void AssetsManagerEx::startUpdate()
{
if (_updateState != State::NEED_UPDATE)
return;
_updateState = State::UPDATING;
// Clean up before update
_failedUnits.clear();
_downloadUnits.clear();
_compressedFiles.clear();
_totalWaitToDownload = _totalToDownload = 0;
_percent = _percentByFile = _sizeCollected = _totalSize = 0;
_downloadedSize.clear();
_totalEnabled = false;
// Temporary manifest exists,resuming previous download
if (_tempManifest->isLoaded() && _tempManifest->versionEquals(_remoteManifest)) //下载中退出,下次回去重新开始下载
{
_tempManifest->genResumeAssetsList(&_downloadUnits);
_totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size();
_downloader->batchDownloadAsync(_downloadUnits,BATCH_UPDATE_ID);
std::string msg = StringUtils::format("Resuming from previous unfinished update,%d files remains to be finished.",_totalToDownload);
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION,msg);
}
// Check difference
else
{
// Temporary manifest not exists or out of date,
// it will be used to register the download states of each asset,
// in this case,it equals remote manifest.
_tempManifest->release();
_tempManifest = _remoteManifest; //说明是本次下载完的配置文件,tempManifest还未解析,但是remoteManifest已经解析了
std::unordered_map<std::string,Manifest::AssetDiff> diff_map = _localManifest->genDiff(_remoteManifest); //拿到需要更新的所有资源
if (diff_map.size() == 0)
{
updateSucceed();
}
else
{
// Generate download units for all assets that need to be updated or added
std::string packageUrl = _remoteManifest->getPackageUrl(); //去下载需要更新的资源
for (auto it = diff_map.begin(); it != diff_map.end(); ++it)
{
Manifest::AssetDiff diff = it->second;
if (diff.type == Manifest::DiffType::DELETED)
{
_fileUtils->removeFile(_storagePath + diff.asset.path);
}
else
{
std::string path = diff.asset.path;
// Create path
_fileUtils->createDirectory(basename(_storagePath + path));
Downloader::DownloadUnit unit;
unit.customId = it->first;
unit.srcUrl = packageUrl + path;
unit.storagePath = _storagePath + path;
unit.resumeDownload = false;
_downloadUnits.emplace(unit.customId,unit);
}
}
// Set other assets' downloadState to SUCCESSED
auto assets = _remoteManifest->getAssets(); //这里的资源已经在以前的版本中更新过了。
for (auto it = assets.cbegin(); it != assets.cend(); ++it)
{
const std::string &key = it->first;
auto diffIt = diff_map.find(key);
if (diffIt == diff_map.end())
{
_tempManifest->setAssetDownloadState(key,Manifest::DownloadState::SUCCESSED);
}
}
_totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size();
_downloader->batchDownloadAsync(_downloadUnits,BATCH_UPDATE_ID);
std::string msg = StringUtils::format("Start to update %d files from remote package.",_totalToDownload);
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION,msg);
}
}
_waitToUpdate = false;
}
void AssetsManagerEx::updateSucceed()
{
// Every thing is correctly downloaded,do the following
// 1. rename temporary manifest to valid manifest
_fileUtils->renameFile(_storagePath,TEMP_MANIFEST_FILENAME,MANIFEST_FILENAME); //将临时配置文件改成本地详细配置文件(详细是指:包括了详细文件信息)
// 2. swap the localManifest
if (_localManifest != nullptr)
_localManifest->release();
_localManifest = _remoteManifest;
_remoteManifest = nullptr;
// 3. make local manifest take effect
prepareLocalManifest();
// 4. decompress all compressed files
decompressDownloadedZip();
// 5. Set update state
_updateState = State::UP_TO_DATE;
// 6. Notify finished event
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_FINISHED); //给出通知结束热更新
}
void AssetsManagerEx::checkUpdate()
{
if (!_inited){
CCLOG("AssetsManagerEx : Manifests uninited.n");
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
return;
}
if (!_localManifest->isLoaded())
{
CCLOG("AssetsManagerEx : No local manifest file found error.n");
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
return;
}
switch (_updateState) {
case State::UNCHECKED:
case State::PREDOWNLOAD_VERSION:
{
downloadVersion();
}
break;
case State::UP_TO_DATE:
{
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE);
}
break;
case State::FAIL_TO_UPDATE:
case State::NEED_UPDATE:
{
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND);
}
break;
default:
break;
}
}
void AssetsManagerEx::update()
{
if (!_inited){
CCLOG("AssetsManagerEx : Manifests uninited.n");
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
return;
}
if (!_localManifest->isLoaded())
{
CCLOG("AssetsManagerEx : No local manifest file found error.n");
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
return;
}
_waitToUpdate = true;
switch (_updateState) {
case State::UNCHECKED:
{
_updateState = State::PREDOWNLOAD_VERSION;
}
case State::PREDOWNLOAD_VERSION:
{
downloadVersion();
}
break;
case State::VERSION_LOADED:
{
parseVersion();
}
break;
case State::PREDOWNLOAD_MANIFEST:
{
downloadManifest();
}
break;
case State::MANIFEST_LOADED:
{
parseManifest();
}
break;
case State::FAIL_TO_UPDATE:
case State::NEED_UPDATE:
{
// Manifest not loaded yet
if (!_remoteManifest->isLoaded())
{
_waitToUpdate = true;
_updateState = State::PREDOWNLOAD_MANIFEST;
downloadManifest();
}
else
{
startUpdate();
}
}
break;
case State::UP_TO_DATE:
case State::UPDATING:
_waitToUpdate = false;
break;
default:
break;
}
}
void AssetsManagerEx::updateAssets(const Downloader::DownloadUnits& assets)
{
if (!_inited){
CCLOG("AssetsManagerEx : Manifests uninited.n");
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
return;
}
if (_updateState != State::UPDATING && _localManifest->isLoaded() && _remoteManifest->isLoaded())
{
int size = (int)(assets.size());
if (size > 0)
{
_updateState = State::UPDATING;
_downloadUnits.clear();
_downloadUnits = assets;
_downloader->batchDownloadAsync(_downloadUnits,BATCH_UPDATE_ID);
}
else if (size == 0 && _totalWaitToDownload == 0)
{
updateSucceed();
}
}
}
const Downloader::DownloadUnits& AssetsManagerEx::getFailedAssets() const
{
return _failedUnits;
}
void AssetsManagerEx::downloadFailedAssets()
{
CCLOG("AssetsManagerEx : Start update %lu failed assets.n",_failedUnits.size());
updateAssets(_failedUnits);
}
void AssetsManagerEx::onError(const Downloader::Error &error)
{
// Skip version error occured
if (error.customId == VERSION_ID)
{
CCLOG("AssetsManagerEx : Fail to download version file,step skippedn");
_updateState = State::PREDOWNLOAD_MANIFEST;
downloadManifest();
}
else if (error.customId == MANIFEST_ID)
{
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST,error.customId,error.message,error.curle_code,error.curlm_code);
}
else
{
auto unitIt = _downloadUnits.find(error.customId);
// Found unit and add it to failed units
if (unitIt != _downloadUnits.end())
{
Downloader::DownloadUnit unit = unitIt->second;
_failedUnits.emplace(unit.customId,unit);
}
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_UPDATING,error.curlm_code);
}
}
void AssetsManagerEx::onProgress(double total,double downloaded,const std::string &url,const std::string &customId)
{
if (customId == VERSION_ID || customId == MANIFEST_ID)
{
_percent = 100 * downloaded / total;
// Notify progression event
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION,customId);
return;
}
else
{
// Calcul total downloaded
bool found = false;
double totalDownloaded = 0;
for (auto it = _downloadedSize.begin(); it != _downloadedSize.end(); ++it)
{
if (it->first == customId)
{
it->second = downloaded;
found = true;
}
totalDownloaded += it->second;
}
// Collect information if not registed
if (!found)
{
// Set download state to DOWNLOADING,this will run only once in the download process
_tempManifest->setAssetDownloadState(customId,Manifest::DownloadState::DOWNLOADING);
// Register the download size information
_downloadedSize.emplace(customId,downloaded);
_totalSize += total;
_sizeCollected++;
// All collected,enable total size
if (_sizeCollected == _totalToDownload)
{
_totalEnabled = true; //当需要下载的每个文件都有下载(不管有没有下载完全 才通知显示大小的进度)
}
}
if (_totalEnabled && _updateState == State::UPDATING)
{
float currentPercent = 100 * totalDownloaded / _totalSize;
// Notify at integer level change
if ((int)currentPercent != (int)_percent) {
_percent = currentPercent;
// Notify progression event
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION,customId);
}
}
}
}
void AssetsManagerEx::onSuccess(const std::string &srcUrl,const std::string &storagePath,const std::string &customId)
{
if (customId == VERSION_ID)
{
_updateState = State::VERSION_LOADED;
parseVersion();
}
else if (customId == MANIFEST_ID)
{
_updateState = State::MANIFEST_LOADED;
parseManifest();
}
else if (customId == BATCH_UPDATE_ID)
{
// Finished with error check
if (_failedUnits.size() > 0 || _totalWaitToDownload > 0) //还有未下载成功的
{
// Save current download manifest information for resuming
_tempManifest->saveToFile(_tempManifestPath);//保存到临时文件中去,下次再去下载
decompressDownloadedZip();
_updateState = State::FAIL_TO_UPDATE;
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_FAILED); //通知未更新成功
}
else
{
updateSucceed();
}
}
else
{
auto assets = _remoteManifest->getAssets();
auto assetIt = assets.find(customId);
if (assetIt != assets.end())
{
// Set download state to SUCCESSED
_tempManifest->setAssetDownloadState(customId,Manifest::DownloadState::SUCCESSED);
// Add file to need decompress list
if (assetIt->second.compressed) {
_compressedFiles.push_back(storagePath);
}
}
auto unitIt = _downloadUnits.find(customId);
if (unitIt != _downloadUnits.end())
{
// Reduce count only when unit found in _downloadUnits
_totalWaitToDownload--;
_percentByFile = 100 * (float)(_totalToDownload - _totalWaitToDownload) / _totalToDownload;
// Notify progression event
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION,"");
}
// Notify asset updated event
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ASSET_UPDATED,customId);
unitIt = _failedUnits.find(customId);
// Found unit and delete it
if (unitIt != _failedUnits.end())
{
// Remove from failed units list
_failedUnits.erase(unitIt);
}
}
}
void AssetsManagerEx::destroyDownloadedVersion()
{
_fileUtils->removeFile(_cacheVersionPath);
_fileUtils->removeFile(_cacheManifestPath);
}
NS_CC_EXT_END
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |