从2.1.2版本开始,2dx在libExtensions下添加了一个AssetsManager类用于资源的在线更新和简单的版本管理,同时添加了AssetsManagerTest项目示范了AssetsManager类的用法。

运行AssetsManagerTest,可以看到菜单界面

点击enter,看到下面的画面

重新运行程序,点击update,可以看到后台的log

然后再点击enter,发现画面已经发生改变

重新运行程序,画面一直都是新的。
重新运行程序,点击reset,再点击enter,发现画面回到了旧画面

代码分析
程序创建了一个UpdateLayer,上面有三个menuitem,这个不用多说
当点击update时,程序调用getAssetsManager() 获取AssetsManager 的实例,在getAssetsManager() 中应用了单例的模式,如果没有创建pAssetsManager 则new一个,第一个参数是更新包地址,第二个参数是版本文件地址,第三个参数是本地存储路径

  1. void UpdateLayer::update(cocos2d::CCObject *pSender)
  2. {
  3. // update resources
  4. getAssetsManager()->update();
  5. isUpdateItemClicked = true;
  6. }
  7. AssetsManager* UpdateLayer::getAssetsManager()
  8. {
  9. static AssetsManager *pAssetsManager = NULL;
  10. if (! pAssetsManager)
  11. {
  12. pAssetsManager = new AssetsManager("https://raw.github.com/minggo/AssetsManagerTest/master/package.zip", //资源更新包地址
  13. "https://raw.github.com/minggo/AssetsManagerTest/master/version", //版本文件地址
  14. pathToSave.c_str()); //本地存储地址,见 createDownloadedDir()
  15. }
  16. return pAssetsManager;
  17. }

复制代码

获得实例后,调用 update() 方法

  1. void AssetsManager::update()
  2. {
  3. // 1. Urls of package and version should be valid;
  4. // 2. Package should be a zip file.
  5. if (_versionFileUrl.size() == 0 ||
  6. _packageUrl.size() == 0 ||
  7. std::string::npos == _packageUrl.find(".zip"))
  8. {
  9. CCLOG("no version file url, or no package url, or the package is not a zip file");
  10. return;
  11. }
  12. // Check if there is a new version.
  13. if (! checkUpdate()) return; //检查是否需要更新
  14. // Is package already downloaded?
  15. string downloadedVersion = CCUserDefault::sharedUserDefault()->getStringForKey(KEY_OF_DOWNLOADED_VERSION);
  16. if (downloadedVersion != _version)
  17. {
  18. if (! downLoad()) return; //下载
  19. // Record downloaded version.
  20. CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_DOWNLOADED_VERSION, _version.c_str());
  21. CCUserDefault::sharedUserDefault()->flush();
  22. }
  23. // Uncompress zip file.
  24. if (! uncompress()) return; //解压缩
  25. // Record new version code.
  26. CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_VERSION, _version.c_str()); //更新本地版本号
  27. // Unrecord downloaded version code.
  28. CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_DOWNLOADED_VERSION, "");
  29. CCUserDefault::sharedUserDefault()->flush();
  30. // Set resource search path.
  31. setSearchPath(); //更新资源搜索路径列表
  32. // Delete unloaded zip file.
  33. string zipfileName = _storagePath + TEMP_PACKAGE_FILE_NAME;
  34. if (remove(zipfileName.c_str()) != 0)
  35. {
  36. CCLOG("can not remove downloaded zip file");
  37. }
  38. }

复制代码

update() 方法执行过程中,调用checkUpdate() 方法检查是否需要下载更新包

  1. bool AssetsManager::checkUpdate()
  2. {
  3. if (_versionFileUrl.size() == 0) return false;
  4. _curl = curl_easy_init();
  5. if (! _curl)
  6. {
  7. CCLOG("can not init curl");
  8. return false;
  9. }
  10. // Clear _version before assign new value.
  11. _version.clear();
  12. CURLcode res;
  13. curl_easy_setopt(_curl, CURLOPT_URL, _versionFileUrl.c_str());
  14. curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYPEER, 0L);
  15. curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, getVersionCode);
  16. curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &_version);
  17. res = curl_easy_perform(_curl);
  18. if (res != 0)
  19. {
  20. CCLOG("can not get version file content, error code is %d", res);
  21. curl_easy_cleanup(_curl);
  22. return false;
  23. }
  24. string recordedVersion = CCUserDefault::sharedUserDefault()->getStringForKey(KEY_OF_VERSION);
  25. if (recordedVersion == _version) //判断版本是否与本地版本相同,如果相同则更新搜索路径列表,并返回不需要更新
  26. {
  27. CCLOG("there is not new version");
  28. // Set resource search path.
  29. setSearchPath(); //更新列表
  30. return false;
  31. }
  32. CCLOG("there is a new version: %s", _version.c_str());
  33. return true;
  34. }

复制代码

检查的方法就是以指定的路径向服务器请求版本文件,然后比较内容是否与本地记录的版本(CCUserDefault::sharedUserDefault()->getStringForKey(KEY_OF_VERSION);)一致,一致则结束,不一致则返回需要更新,然后调用downLoad() 来下载,下载的过程中会回调 progressFunc 来反馈进度,下载的过程应该是同步的阻塞模式(我没仔细跟进去分析,从代码的写法上猜测的),也就是下载过程中不能做其他操作。下载完成后,调用 uncompress() 解压缩到指定的路径。然后更新本地版本号为新版本号,并写文件(CCUserDefault::sharedUserDefault()->flush();)。最后调用setSearchPath() 将存储路径添加到搜索路径列表中去。

  1. void AssetsManager::setSearchPath()
  2. {
  3. vector<string> searchPaths = CCFileUtils::sharedFileUtils()->getSearchPaths(); //获得当前列表
  4. vector<string>::iterator iter = searchPaths.begin(); //获取列表的头
  5. searchPaths.insert(iter, _storagePath); //添加,添加后,新添加的路径在前
  6. CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths); //回写
  7. }

复制代码

2.1.2版本引擎对CCFileUtils 进行了重构,所谓的资源搜索路径列表就是指一个存有多个路径的序列,在搜索某个文件时,按照列表的顺序遍历(使用迭代器),依次测试文件是否存在,直到发现文件。如果列表以某种顺序组织,比如按版本号的降序排列,即先搜索新版本,后搜索旧版本,从而可以实现新版本资源替换旧版本资源的功能。

点击reset,删除已下载的文件

  1. void UpdateLayer::reset(cocos2d::CCObject *pSender)
  2. {
  3. // Remove downloaded files
  4. #if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
  5. string command = "rm -r ";
  6. // Path may include space.
  7. command += "\"" + pathToSave + "\"";
  8. system(command.c_str());
  9. #else
  10. string command = "rd /s /q ";
  11. // Path may include space.
  12. command += "\"" + pathToSave + "\"";
  13. system(command.c_str());
  14. #endif
  15. // Delete recorded version codes.
  16. getAssetsManager()->deleteVersion();
  17. createDownloadedDir();
  18. }

复制代码

点击enter,需要注意有一个判断是否点击过的update的判断,如果没有点击过则需要将新的路径手工添加到搜索列表中去,如果点击过则路径已经自动添加过了

  1. void UpdateLayer::enter(cocos2d::CCObject *pSender)
  2. {
  3. // Should set search resource path before running script if "update" is not clicked.
  4. // Because AssetsManager will set
  5. if (! isUpdateItemClicked) //判断是否需要手工添加搜索路径
  6. {
  7. vector<string> searchPaths = CCFileUtils::sharedFileUtils()->getSearchPaths();
  8. searchPaths.insert(searchPaths.begin(), pathToSave);
  9. CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths);
  10. }
  11. CCScriptEngineProtocol *pEngine = ScriptingCore::getInstance();
  12. CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
  13. ScriptingCore::getInstance()->runScript("main.js");
  14. }

复制代码

总结
1、AssetsManager类 提供了一个很方便的更新资源的官方途径,这对手游特别是手机网游来说是一个很利好的消息,毕竟能够更新资源而不需要更新应用本身是可以减少用户流失的
2、版本管理的功能还较弱,目前的功能只能记录一个版本,即最新版本,如果能够多版本(更新历史) 管理的话,会更方便
3、应用启动后,搜索路径还需要手工添加,应该做成与版本关联的方式,根据本地的版本记录来自动的添加

cocos2d-x使用AssetsManager类实现资源的在线更新的更多相关文章

  1. cocos2d 播放GIF动画类

    cocos2d 播放GIF动画类 以前项目中曾经用到过,后来因为GIF图像的质量较差,被弃用了,把公司名字去掉分享下,根据网上资料改编的cocos2d-iphone版的. // // CCSprite ...

  2. 访问动态链接库中的C++类和资源

    面我们来介绍如何访问动态链接库中的C++类和资源.其具体操作步骤如下:(1)创建一个基于对话框的工程,工程名称为“AccessDll”.设计对话框资源如图1所示. 图1  对话框资源设计窗口(2)定义 ...

  3. Javaweb学习笔记——(九)——————Servlet的进入,及ServletConfig、GenericServlet、HttpServlet、ServletContext、获取类路径资源

    Servlet1.什么是Servlet? *Servlet是Javaweb三大组件之一(Servlet,Filter,Listener) *Servlet是用来处理客户端请求的动态资源 *Servle ...

  4. 【Unity】使用Resources类管理资源

    最近参考了各位大神的资源,初步学习了Unity的资源管理模式,包括在编辑器管理(使用AssetDatabase)和在运行时管理(使用Resources和AssetBundle).在此简单总结运行时用R ...

  5. 创建在类路径资源[applicationcontext]中定义名为“工厂”的bean时出错。:在设置bean属性“dataSource”时,无法解析对bean“dataSource”的引用;嵌套异常是org.springframe .beans.factory。BeanCreationException:创建名为“数据源”的bean时出错,该名称是在类路径资源[applicationcontext

    控制台报错: 创建在类路径资源[applicationcontext]中定义名为“工厂”的bean时出错.:在设置bean属性“dataSource”时,无法解析对bean“dataSource”的引 ...

  6. org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException 前言中不允许有内容 来自类路径资源的XML文档中的第1行是无效的

    今天复习一下Spring和Hibernate的整合,遇到了一个问题,报错信息如下: org.springframework.beans.factory.xml.XmlBeanDefinitionSto ...

  7. 在javaweb中通过servlet类和普通类读取资源文件

    javaweb有两种方式读取资源文件 在Servlet中读取,可以使用servletContext,servletContext可以拿到web所有的资源文件,然后随便读,但是这种方法不常用,尽量少在S ...

  8. Docker 的两类存储资源 - 每天5分钟玩转 Docker 容器技术(38)

    我们从本章开始讨论 Docker 存储. Docker 为容器提供了两种存放数据的资源: 由 storage driver 管理的镜像层和容器层. Data Volume. 我们会详细讨论它们的原理和 ...

  9. 038、Docker 的两类存储资源(2019-02-27 周三)

    参考https://www.cnblogs.com/CloudMan6/p/7127843.html   Docker为容器提供了两种存放数据的资源:       1.由storage driver  ...

随机推荐

  1. tomcat配置环境变量

    先把jdk配置好,这里不在赘述. 一.配置Tomcat环境变量 1,新建变量名:CATALINA_BASE,变量值:C:\tomcat2,新建变量名:CATALINA_HOME,变 量值:C:\tom ...

  2. 李洪强iOS经典面试题133--UNIX常用命令

    可能碰到的iOS笔试面试题(3)--UNIX常用命令 做开发说用不到命令行,那肯定是不可能的.所以记住几个常用的命令还是很有用. cd 改变工作目录 pwd 输出当前工作目录的绝对路径在UNIX中要执 ...

  3. $_POST 变量以及$GLOBALS['HTTP_RAW_POST_DATA']

    $_POST 变量是一个数组,内容是由 HTTP POST 方法发送的变量名称和值. $_POST 变量用于收集来自 method="post" 的表单中的值.从带有 POST 方 ...

  4. 理解Oracle TM和TX锁

    在Oracle中有很多锁,通过v$lock_type视图可以查看Oracle中所有类型的锁,在本篇文章中我们熟悉一下TM和TX锁的类型 SQL> select * from v$lock_typ ...

  5. java web重定向与转发

    首先定义一下这两个词: 重定向是将用户从当前页面或servlet定向到另外一个jsp页面或者servlet 转发是将用户对当前jsp页面或者servlet对象的请求转发给另外一个jsp页面或者serv ...

  6. php for循环嵌套

    <?php     //2.打印一个50*50的 'o' 的正方形方整, 使用for的嵌套     // oooooo     // oooooo     // oooooo //for循环嵌套 ...

  7. WS调用的时候报错

    报错内容javax.xml.ws.WebServiceException: Method recognizeIdentityCardByFilePath is exposed as WebMethod ...

  8. HTML中id、name、class 区别

    参考:http://www.cnblogs.com/polk6/archive////.html http://blog.csdn.net/ithomer/article/details/ HTML ...

  9. BizTalk开发系列(三十八)微软BizTalk Server定价和许可[解读]

    做BizTalk的项目一段时间了,但是对BizTalk的价格和许可还不是很了解.给客户设计解决方案时大部分产品都是直接按照企业版的功能来设计,很 少考虑到价格和许可方面的因素,以为这个不是我们的事情或 ...

  10. 关于static 的研究 与递归调用的输出

    static的作用 :1.保存上次执行的结果 2.static int m; 这里默认m的初始值为0,即默认 值是0 #include "stdio.h" int fun(int ...