cocos2d-x使用AssetsManager类实现资源的在线更新
2014-07-03 11:22
393 查看
从2.1.2版本开始,2dx在libExtensions下添加了一个AssetsManager类用于资源的在线更新和简单的版本管理,同时添加了AssetsManagerTest项目示范了AssetsManager类的用法。
运行AssetsManagerTest,可以看到菜单界面
点击enter,看到下面的画面
重新运行程序,点击update,可以看到后台的log
然后再点击enter,发现画面已经发生改变
重新运行程序,画面一直都是新的。
重新运行程序,点击reset,再点击enter,发现画面回到了旧画面
代码分析
程序创建了一个UpdateLayer,上面有三个menuitem,这个不用多说
当点击update时,程序调用getAssetsManager() 获取AssetsManager 的实例,在getAssetsManager() 中应用了单例的模式,如果没有创建pAssetsManager 则new一个,第一个参数是更新包地址,第二个参数是版本文件地址,第三个参数是本地存储路径
void UpdateLayer::update(cocos2d::CCObject *pSender)
{
// update resources
getAssetsManager()->update();
isUpdateItemClicked = true;
}
AssetsManager* UpdateLayer::getAssetsManager()
{
static AssetsManager *pAssetsManager = NULL;
if (! pAssetsManager)
{
pAssetsManager = new AssetsManager("https://raw.github.com/minggo/AssetsManagerTest/master/package.zip", //资源更新包地址
"https://raw.github.com/minggo/AssetsManagerTest/master/version", //版本文件地址
pathToSave.c_str()); //本地存储地址,见 createDownloadedDir()
}
return pAssetsManager;
}
复制代码
获得实例后,调用 update() 方法
void AssetsManager::update()
{
// 1. Urls of package and version should be valid;
// 2. Package should be a zip file.
if (_versionFileUrl.size() == 0 ||
_packageUrl.size() == 0 ||
std::string::npos == _packageUrl.find(".zip"))
{
CCLOG("no version file url, or no package url, or the package is not a zip file");
return;
}
// Check if there is a new version.
if (! checkUpdate()) return; //检查是否需要更新
// Is package already downloaded?
string downloadedVersion = CCUserDefault::sharedUserDefault()->getStringForKey(KEY_OF_DOWNLOADED_VERSION);
if (downloadedVersion != _version)
{
if (! downLoad()) return; //下载
// Record downloaded version.
CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_DOWNLOADED_VERSION, _version.c_str());
CCUserDefault::sharedUserDefault()->flush();
}
// Uncompress zip file.
if (! uncompress()) return; //解压缩
// Record new version code.
CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_VERSION, _version.c_str()); //更新本地版本号
// Unrecord downloaded version code.
CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_DOWNLOADED_VERSION, "");
CCUserDefault::sharedUserDefault()->flush();
// Set resource search path.
setSearchPath(); //更新资源搜索路径列表
// Delete unloaded zip file.
string zipfileName = _storagePath + TEMP_PACKAGE_FILE_NAME;
if (remove(zipfileName.c_str()) != 0)
{
CCLOG("can not remove downloaded zip file");
}
}
复制代码
update() 方法执行过程中,调用checkUpdate() 方法检查是否需要下载更新包
bool AssetsManager::checkUpdate()
{
if (_versionFileUrl.size() == 0) return false;
_curl = curl_easy_init();
if (! _curl)
{
CCLOG("can not init curl");
return false;
}
// Clear _version before assign new value.
_version.clear();
CURLcode res;
curl_easy_setopt(_curl, CURLOPT_URL, _versionFileUrl.c_str());
curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, getVersionCode);
curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &_version);
res = curl_easy_perform(_curl);
if (res != 0)
{
CCLOG("can not get version file content, error code is %d", res);
curl_easy_cleanup(_curl);
return false;
}
string recordedVersion = CCUserDefault::sharedUserDefault()->getStringForKey(KEY_OF_VERSION);
if (recordedVersion == _version) //判断版本是否与本地版本相同,如果相同则更新搜索路径列表,并返回不需要更新
{
CCLOG("there is not new version");
// Set resource search path.
setSearchPath(); //更新列表
return false;
}
CCLOG("there is a new version: %s", _version.c_str());
return true;
}
复制代码
检查的方法就是以指定的路径向服务器请求版本文件,然后比较内容是否与本地记录的版本(CCUserDefault::sharedUserDefault()->getStringForKey(KEY_OF_VERSION);)一致,一致则结束,不一致则返回需要更新,然后调用downLoad() 来下载,下载的过程中会回调 progressFunc 来反馈进度,下载的过程应该是同步的阻塞模式(我没仔细跟进去分析,从代码的写法上猜测的),也就是下载过程中不能做其他操作。下载完成后,调用 uncompress() 解压缩到指定的路径。然后更新本地版本号为新版本号,并写文件(CCUserDefault::sharedUserDefault()->flush();)。最后调用setSearchPath() 将存储路径添加到搜索路径列表中去。
void AssetsManager::setSearchPath()
{
vector<string> searchPaths = CCFileUtils::sharedFileUtils()->getSearchPaths(); //获得当前列表
vector<string>::iterator iter = searchPaths.begin(); //获取列表的头
searchPaths.insert(iter, _storagePath); //添加,添加后,新添加的路径在前
CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths); //回写
}
复制代码
2.1.2版本引擎对CCFileUtils 进行了重构,所谓的资源搜索路径列表就是指一个存有多个路径的序列,在搜索某个文件时,按照列表的顺序遍历(使用迭代器),依次测试文件是否存在,直到发现文件。如果列表以某种顺序组织,比如按版本号的降序排列,即先搜索新版本,后搜索旧版本,从而可以实现新版本资源替换旧版本资源的功能。
点击reset,删除已下载的文件
void UpdateLayer::reset(cocos2d::CCObject *pSender)
{
// Remove downloaded files
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
string command = "rm -r ";
// Path may include space.
command += "\"" + pathToSave + "\"";
system(command.c_str());
#else
string command = "rd /s /q ";
// Path may include space.
command += "\"" + pathToSave + "\"";
system(command.c_str());
#endif
// Delete recorded version codes.
getAssetsManager()->deleteVersion();
createDownloadedDir();
}
复制代码
点击enter,需要注意有一个判断是否点击过的update的判断,如果没有点击过则需要将新的路径手工添加到搜索列表中去,如果点击过则路径已经自动添加过了
void UpdateLayer::enter(cocos2d::CCObject *pSender)
{
// Should set search resource path before running script if "update" is not clicked.
// Because AssetsManager will set
if (! isUpdateItemClicked) //判断是否需要手工添加搜索路径
{
vector<string> searchPaths = CCFileUtils::sharedFileUtils()->getSearchPaths();
searchPaths.insert(searchPaths.begin(), pathToSave);
CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths);
}
CCScriptEngineProtocol *pEngine = ScriptingCore::getInstance();
CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
ScriptingCore::getInstance()->runScript("main.js");
}
复制代码
总结
1、AssetsManager类 提供了一个很方便的更新资源的官方途径,这对手游特别是手机网游来说是一个很利好的消息,毕竟能够更新资源而不需要更新应用本身是可以减少用户流失的
2、版本管理的功能还较弱,目前的功能只能记录一个版本,即最新版本,如果能够多版本(更新历史) 管理的话,会更方便
3、应用启动后,搜索路径还需要手工添加,应该做成与版本关联的方式,根据本地的版本记录来自动的添加
运行AssetsManagerTest,可以看到菜单界面
点击enter,看到下面的画面
重新运行程序,点击update,可以看到后台的log
然后再点击enter,发现画面已经发生改变
重新运行程序,画面一直都是新的。
重新运行程序,点击reset,再点击enter,发现画面回到了旧画面
代码分析
程序创建了一个UpdateLayer,上面有三个menuitem,这个不用多说
当点击update时,程序调用getAssetsManager() 获取AssetsManager 的实例,在getAssetsManager() 中应用了单例的模式,如果没有创建pAssetsManager 则new一个,第一个参数是更新包地址,第二个参数是版本文件地址,第三个参数是本地存储路径
void UpdateLayer::update(cocos2d::CCObject *pSender)
{
// update resources
getAssetsManager()->update();
isUpdateItemClicked = true;
}
AssetsManager* UpdateLayer::getAssetsManager()
{
static AssetsManager *pAssetsManager = NULL;
if (! pAssetsManager)
{
pAssetsManager = new AssetsManager("https://raw.github.com/minggo/AssetsManagerTest/master/package.zip", //资源更新包地址
"https://raw.github.com/minggo/AssetsManagerTest/master/version", //版本文件地址
pathToSave.c_str()); //本地存储地址,见 createDownloadedDir()
}
return pAssetsManager;
}
复制代码
获得实例后,调用 update() 方法
void AssetsManager::update()
{
// 1. Urls of package and version should be valid;
// 2. Package should be a zip file.
if (_versionFileUrl.size() == 0 ||
_packageUrl.size() == 0 ||
std::string::npos == _packageUrl.find(".zip"))
{
CCLOG("no version file url, or no package url, or the package is not a zip file");
return;
}
// Check if there is a new version.
if (! checkUpdate()) return; //检查是否需要更新
// Is package already downloaded?
string downloadedVersion = CCUserDefault::sharedUserDefault()->getStringForKey(KEY_OF_DOWNLOADED_VERSION);
if (downloadedVersion != _version)
{
if (! downLoad()) return; //下载
// Record downloaded version.
CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_DOWNLOADED_VERSION, _version.c_str());
CCUserDefault::sharedUserDefault()->flush();
}
// Uncompress zip file.
if (! uncompress()) return; //解压缩
// Record new version code.
CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_VERSION, _version.c_str()); //更新本地版本号
// Unrecord downloaded version code.
CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_DOWNLOADED_VERSION, "");
CCUserDefault::sharedUserDefault()->flush();
// Set resource search path.
setSearchPath(); //更新资源搜索路径列表
// Delete unloaded zip file.
string zipfileName = _storagePath + TEMP_PACKAGE_FILE_NAME;
if (remove(zipfileName.c_str()) != 0)
{
CCLOG("can not remove downloaded zip file");
}
}
复制代码
update() 方法执行过程中,调用checkUpdate() 方法检查是否需要下载更新包
bool AssetsManager::checkUpdate()
{
if (_versionFileUrl.size() == 0) return false;
_curl = curl_easy_init();
if (! _curl)
{
CCLOG("can not init curl");
return false;
}
// Clear _version before assign new value.
_version.clear();
CURLcode res;
curl_easy_setopt(_curl, CURLOPT_URL, _versionFileUrl.c_str());
curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, getVersionCode);
curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &_version);
res = curl_easy_perform(_curl);
if (res != 0)
{
CCLOG("can not get version file content, error code is %d", res);
curl_easy_cleanup(_curl);
return false;
}
string recordedVersion = CCUserDefault::sharedUserDefault()->getStringForKey(KEY_OF_VERSION);
if (recordedVersion == _version) //判断版本是否与本地版本相同,如果相同则更新搜索路径列表,并返回不需要更新
{
CCLOG("there is not new version");
// Set resource search path.
setSearchPath(); //更新列表
return false;
}
CCLOG("there is a new version: %s", _version.c_str());
return true;
}
复制代码
检查的方法就是以指定的路径向服务器请求版本文件,然后比较内容是否与本地记录的版本(CCUserDefault::sharedUserDefault()->getStringForKey(KEY_OF_VERSION);)一致,一致则结束,不一致则返回需要更新,然后调用downLoad() 来下载,下载的过程中会回调 progressFunc 来反馈进度,下载的过程应该是同步的阻塞模式(我没仔细跟进去分析,从代码的写法上猜测的),也就是下载过程中不能做其他操作。下载完成后,调用 uncompress() 解压缩到指定的路径。然后更新本地版本号为新版本号,并写文件(CCUserDefault::sharedUserDefault()->flush();)。最后调用setSearchPath() 将存储路径添加到搜索路径列表中去。
void AssetsManager::setSearchPath()
{
vector<string> searchPaths = CCFileUtils::sharedFileUtils()->getSearchPaths(); //获得当前列表
vector<string>::iterator iter = searchPaths.begin(); //获取列表的头
searchPaths.insert(iter, _storagePath); //添加,添加后,新添加的路径在前
CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths); //回写
}
复制代码
2.1.2版本引擎对CCFileUtils 进行了重构,所谓的资源搜索路径列表就是指一个存有多个路径的序列,在搜索某个文件时,按照列表的顺序遍历(使用迭代器),依次测试文件是否存在,直到发现文件。如果列表以某种顺序组织,比如按版本号的降序排列,即先搜索新版本,后搜索旧版本,从而可以实现新版本资源替换旧版本资源的功能。
点击reset,删除已下载的文件
void UpdateLayer::reset(cocos2d::CCObject *pSender)
{
// Remove downloaded files
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
string command = "rm -r ";
// Path may include space.
command += "\"" + pathToSave + "\"";
system(command.c_str());
#else
string command = "rd /s /q ";
// Path may include space.
command += "\"" + pathToSave + "\"";
system(command.c_str());
#endif
// Delete recorded version codes.
getAssetsManager()->deleteVersion();
createDownloadedDir();
}
复制代码
点击enter,需要注意有一个判断是否点击过的update的判断,如果没有点击过则需要将新的路径手工添加到搜索列表中去,如果点击过则路径已经自动添加过了
void UpdateLayer::enter(cocos2d::CCObject *pSender)
{
// Should set search resource path before running script if "update" is not clicked.
// Because AssetsManager will set
if (! isUpdateItemClicked) //判断是否需要手工添加搜索路径
{
vector<string> searchPaths = CCFileUtils::sharedFileUtils()->getSearchPaths();
searchPaths.insert(searchPaths.begin(), pathToSave);
CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths);
}
CCScriptEngineProtocol *pEngine = ScriptingCore::getInstance();
CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
ScriptingCore::getInstance()->runScript("main.js");
}
复制代码
总结
1、AssetsManager类 提供了一个很方便的更新资源的官方途径,这对手游特别是手机网游来说是一个很利好的消息,毕竟能够更新资源而不需要更新应用本身是可以减少用户流失的
2、版本管理的功能还较弱,目前的功能只能记录一个版本,即最新版本,如果能够多版本(更新历史) 管理的话,会更方便
3、应用启动后,搜索路径还需要手工添加,应该做成与版本关联的方式,根据本地的版本记录来自动的添加
相关文章推荐
- cocos2d-x使用AssetsManager类实现资源的在线更新
- cocos2d-x使用AssetsManager类实现资源的在线更新
- Hybrid模式-利用AssetsManager实现在线更新脚本文件lua、js、图片等资源(免去平台审核周期)
- 【COCOS2DX-LUA 脚本开发之十二】利用AssetsManager实现在线更新资源文件
- 【COCOS2DX-LUA 脚本开发之十二】Hybrid模式-利用AssetsManager实现在线更新脚本文件lua、js、图片等资源(免去平台审核周期)
- 【Cocos2d-x】实现资源热更新
- 【Cocos2d-x】实现资源热更新
- C# LiveUpdate.exe实现文件在线更新(原理说明,使用指南一)
- 【COCOS2DX-LUA 脚本开发之十二】Hybrid模式-利用AssetsManager实现在线更新脚本文件lua、js、图片等资源(免去平台审核周期)
- Cocos2d-x 3.2 自动更新 -- 使用AssetsManager更新游戏资源包
- Cocos2d-x 3.2 自动更新 -- 使用AssetsManager更新游戏资源包
- 函数项目【COCOS2DX-LUA 脚本开发之十二】Hybrid模式-利用AssetsManager实现在线更新脚本文件lua、js、图片等资源(免去平台审核周期)函数项目
- 【COCOS2DX-LUA 脚本开发之十二】Hybrid模式-利用AssetsManager实现在线更新脚本文件lua、js、图片等资源(免去平台审核周期)
- cocos2dx 3.1.1 在线热更新 自动更新(使用AssetsManager更新游戏资源包)
- (转)使用RCP组件实现程序在线升级更新
- 【COCOS2DX-LUA 脚本开发之十二】Hybrid模式-利用AssetsManager实现在线更新脚本文件lua、js、图片等资源(免去平台审核周期)
- 使用心跳机制实现CS架构下多客户端的在线状态实时更新以及掉线自动重连
- C# LiveUpdate.exe实现文件在线更新升级(原理说明,使用指南一)
- 【Cocos2d-x】实现资源热更新
- 【COCOS2DX-LUA 脚本开发之十二】Hybrid模式-利用AssetsManager实现在线更新脚本文件lua、js、图片等资源(免去平台审核周期)