以前一直打算做这个功能,结果一直没做,最近抽了1天时间研究了下,怕以后又忘记,特意将一些注意事项写来下
版本为cocos2dx-3.9,
目前版本已经废除了以前的AssertManager,使用AssertManagerEx作为资源更新下载器了,功能涵盖了版本控制,版本检查,更新文件,解压,替换。对于刚开始看这个文件的人来说,是比较难搞清楚是怎么用的,经过测试,算是把这东西弄通了,这里需要注意的有以下几点:
1-对于要添加重写的代码,非常少,基本上就是添加一个监听,用来实现下载过程中的事件回调:
下载器对象初始化---
#define LOCAL_VERSION_PATH "config/project.manifest")
bool AssertDownload::init()
{
if (!Layer::init())
{
return false;
}
_loadLayer = Layer::create();
addChild(_loadLayer);
std::string storagePath = FileUtils::getInstance()->getWritablePath();
_am = AssetsManagerEx::create(LOCAL_VERSION_PATH, storagePath);
//参数1表示本地的project.manifest路径,_am在启动后会读取获取里面的版本号信息,
//参数2 表示本地写入路径,意思是当你下载更新后的文件会存入这个路径里
_am->retain();
return true;
}
/从表面上看,我们找不到任何设置更新服务器地址之类的东西
所以我们先大致上讲下怎么配置;
客户端需要在本地resrouce里配1个project.manifes文件 他的路径就是上面LOCAL_VERSION_PATH,即AssetsManagerEx::create的第1个参数
资源服务器需要配置提供3个:
1:各个备用下载的资源文件的路径文件夹 我们称这个叫packageUrl ,例如“http://192.168.0.114:9090/update/files/”
2:提供给客户端检查版本用的version.manifest文件地址 称为remoteVersionUrl 例如“http://192.168.0.114:9090/update/version/version.manifest”
3:提供给客户端检查版本和资源文件版本的project.manifes文件地址,称为remoteManifestUrl 例如“http://192.168.0.114:9090/update/version/project.manifest”
就是说基本上这些配置好了,就没什么代码需要写了,所以这里主要的工作是搞清楚这些配置的作用和用法。
下面我们来详细解释;
所以我们需要打开manifest文件去看内容和一些key
//打开manifest文件,我们发现
"packageUrl" : "http://192.168.0.114:9090/update/files/",
"remoteVersionUrl" : "http://192.168.0.114:9090/update/version/version.manifest",
"remoteManifestUrl" : "http://192.168.0.114:9090/update/version/project.manifest",
"version" : "1.0.0",
"engineVersion" : "Cocos2d-lua v3.3 Final",
"assets" : {
"res/Images/sp.png" : {
"md5" : "e6aed0272011da3039ccc1008040cbc1"
},
假如这个文件需要更新,他的地址就是 packageUrl + res/Images/sp.png;这样我们就可以拿到这个文件的完整地址,可以直接http获取了。
remoteVersionUrl 表示本地
下面这个函数是按钮回调,启动了下载器,并且添加了个监听器实现监听回调 (cocos2d::extension::AssetsManagerEx* _am)
void AssertDownload::startDownloadCallback(Ref* sender)
{
log("start call back");
if (!_am->getLocalManifest()->isLoaded())
{
CCLOG("Fail to update assets, step skipped.");
onLoadEnd();
}
else
{
_amListener = cocos2d::extension::EventListenerAssetsManagerEx::create(_am, std::bind(&AssertDownload::handleAssertsEvent,this, std::placeholders::_1));
Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_amListener, 1);
_am->update();
}
}
剩下的一个需要实现的就是handleAssertsEvent函数,里面就是个switch-case
void AssertDownload::handleAssertsEvent(EventAssetsManagerEx* event)
{
static int failCount = 0;
switch (event->getEventCode())
{
case EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST:
{
CCLOG("No local manifest file found, skip assets update.");
this->onLoadEnd();
}
break;
case EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION:
{
std::string assetId = event->getAssetId();
float percent = event->getPercent();
std::string str;
if (assetId == AssetsManagerEx::VERSION_ID)
{
str = StringUtils::format("Version file: %.2f", percent) + "%";
}
else if (assetId == AssetsManagerEx::MANIFEST_ID)
{
str = StringUtils::format("Manifest file: %.2f", percent) + "%";
}
else
{
str = StringUtils::format("%.2f", percent) + "%";
CCLOG("%.2f Percent", percent);
}
if (this->_progress != nullptr)
this->_progress->setString(str);
}
break;
case EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST:
case EventAssetsManagerEx::EventCode::ERROR_PARSE_MANIFEST:
{
CCLOG("Fail to download manifest file, update skipped.");
this->onLoadEnd();
}
break;
case EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE:
case EventAssetsManagerEx::EventCode::UPDATE_FINISHED:
{
CCLOG("Update finished. %s", event->getMessage().c_str());
this->onLoadEnd();
}
break;
case EventAssetsManagerEx::EventCode::UPDATE_FAILED:
{
CCLOG("Update failed. %s", event->getMessage().c_str());
failCount++;
if (failCount < 5)
{
_am->downloadFailedAssets();
}
else
{
CCLOG("Reach maximum fail count, exit update process");
failCount = 0;
this->onLoadEnd();
}
}
break;
case EventAssetsManagerEx::EventCode::ERROR_UPDATING:
{
CCLOG("Asset %s : %s", event->getAssetId().c_str(), event->getMessage().c_str());
}
break;
case EventAssetsManagerEx::EventCode::ERROR_DECOMPRESS:
{
CCLOG("%s", event->getMessage().c_str());
}
break;
case EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND:
{
log("new version found");
}
default:
break;
}
}
基本上这就是大部分代码了。
2 当然,纯看代码是很难搞懂他的实现和逻辑过程的,接下来,我们分析下这个内部的实现流程和逻辑。
通过调试跟踪,我们发现,AssetsManagerEx* am 对象创建create的时候,使用了2个参数,第1个参数