3.1 使用AssetsManagerEx
AssetsManagerEx的使用非常简单,需要用到两个类,AssetsManagerEx和EventListenerAssetsManagerEx, AssetsManagerEx用来执行增量更新,EventListenerAssetsManagerEx用来监听增量更新中触发的各种事件,如各种更新失败的原因、进度更新以及更新成功等事件。使用的示例代码如下。
//传入Manifest路径和缓存路径,创建AssetsManagerEx对象 auto AssetsManager = AssetsManagerEx::create(manifestPath, storagePath); AssetsManager->retain(); //传入AssetsManagerEx对象和回调函数,EventListenerAssetsManagerEx可以捕获 AssetsManagerEx触发的各种事件 auto listener = EventListenerAssetsManagerEx::create(AssetsManager, callback); //监听事件需要先将EventListenerAssetsManagerEx添加到EventDispatcher Director::getInstance()->getEventDispatcher()->addEventListenerWithFixe dPriority(listener , 1); //最后执行AssetsManagerEx的update()方法自动更新 AssetsManager->update();
上面的代码简单描述了使用AssetsManagerEx的步骤,接下来详细介绍一下AssetsManagerEx的使用。首先是AssetsManagerEx,增量更新的核心功能都由AssetsManagerEx实现,需要传入Manifest文件的路径和相对于WritablePath可写路径的缓存路径来初始化AssetsManagerEx。Manifest文件是用于检查版本更新的文件,在后面会详细介绍,缓存路径指的是增量更新文件下载后存储的路径,由于权限等问题,从服务器下载的资源并不能替换程序安装目录下的原始资源,所以我们会下载到一个可写的缓存目录下,在加载资源的时候优先加载缓存目录中的资源,如找不到则再去加载安装目录中的资源。AssetsManagerEx的常用接口如下。
//检查是否有更新 void checkUpdate(); //自动检查是否有更新,有则自动更新 void update(); //下载更新失败的部分资源 void downloadFailedAssets(); //获取本地Manifest对象 const Manifest* getLocalManifest() const;
update()方法和checkUpdate()方法的区别是,update()方法会检查更新并自动执行更新,而checkUpdate()方法则只是检查是否有更新,如果希望实现一些非强制性的更新,或者在更新之前弹出一个对话框,由玩家来决定是否更新等,就可以使用checkUpdate()方法。
checkUpdate()方法的返回值是void,那么我们如何知道是否需要更新呢?通过消息!我们需要创建一个EventListenerAssetsManagerEx对象来监听AssetsManagerEx触发的消息,当检查到新版本时,AssetsManagerEx会触发NEW_VERSION_FOUND消息,而不需要更新时,则会触发ALREADY_UP_TO_DATE消息,AssetsManagerEx会触发的所有消息如下。
enum class EventCode { ERROR_NO_LOCAL_MANIFEST, //本地Manifest错误 ERROR_DOWNLOAD_MANIFEST, //下载Manifest失败 ERROR_PARSE_MANIFEST, //解析Manifest失败 NEW_VERSION_FOUND, //检查到新版本 ALREADY_UP_TO_DATE, //已经是最新版本 UPDATE_PROGRESSION, //更新进度刷新消息 ASSET_UPDATED, //有资源下载成功 ERROR_UPDATING, //有文件下载失败 UPDATE_FINISHED, //更新完成 UPDATE_FAILED, //更新失败 ERROR_DECOMPRESS //解压文件失败 };
可调用EventListenerAssetsManagerEx的create()方法传入AssetsManagerEx对象和回调函数,创建对象,然后将EventListenerAssetsManagerEx对象添加到EventDispatcher中,当消息触发时会调用回调函数,将事件对象传入到回调函数中。示例教程中的TutorialUpdateAssets示例演示了如何使用AssetsManagerEx进行热更新,示例代码如下。
std::string storage = FileUtils::getInstance()->getWritablePath() + "test1/"; auto assetMgrEx = AssetsManagerEx::create("project.manifest", storage); assetMgrEx->retain(); auto amListener = cocos2d::extension::EventListenerAssetsManagerEx:: create(assetMgrEx, [this](EventAssetsManagerEx* event){ switch (event->getEventCode()) { case EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST: { //本地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("asset %s download %s Percent", assetId.c_str(), str.c_str()); } break; case EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST: case EventAssetsManagerEx::EventCode::ERROR_PARSE_MANIFEST: { //下载或解析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()); event->getAssetsManagerEx()->downloadFailedAssets(); 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; default: break; ); //自动检查是否有更新,有则自动更新 void update(); //下载更新失败的部分资源 void downloadFailedAssets(); //获取本地Manifest对象 const Manifest* getLocalManifest() const; } }); //将EventListenerAssetsManagerEx添加到EventDispatcher中 Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority (amListener, 1); assetMgrEx->update();
在回调函数中可以获取EventAssetsManagerEx对象,从该对象中获取消息ID、CURL错误码、错误消息、资源ID、AssetsManagerEx、总的下载进度以及当前文件的下载进度等信息。
需要注意的是创建AssetsManagerEx时传入的Manifest文件和下载路径,我们传入的project.manifest文件是安装包中的一个Manifest文件,它记录了本地的资源列表以及服务器的Manifest文件地址,后面会详细介绍Manifest文件。下载路径需要是一个可写的路径,所以需要获取WritablePath作为前缀,注意不要和其他路径混合在一起,这个路径只用来存放增量更新更新下来的文件,不要将游戏的存档等信息放到这个路径下。
示例不论更新成功还是失败,最终都会调用onLoadEnd()方法,在onLoadEnd()方法中创建一个Sprite,如果更新失败会根据本地的图片创建Sprite,如果更新成功则会根据更新下来的图片创建Sprite。
void TutorialUpdateAssets::onLoadEnd() { auto backgroundSprite = Sprite::create("Images/background1.jpg"); addChild(backgroundSprite, 1); backgroundSprite->setPosition(Director::getInstance()->getWinSize()*0.5f); }