cocos2d-x使用AssetsManager類實現資源的在線更新


從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.     
  6.     isUpdateItemClicked = true;
  7. }
  8. AssetsManager* UpdateLayer::getAssetsManager()
  9. {
  10.     static AssetsManager *pAssetsManager = NULL;
  11.     
  12.     if (! pAssetsManager)
  13.     {
  14.         pAssetsManager = new AssetsManager("https://raw.github.com/minggo/AssetsManagerTest/master/package.zip", //資源更新包地址
  15.                                            "https://raw.github.com/minggo/AssetsManagerTest/master/version", //版本文件地址
  16.                                            pathToSave.c_str()); //本地存儲地址,見 createDownloadedDir()
  17.     }
  18.     
  19.     return pAssetsManager;
  20. }
復制代碼

獲得實例后,調用 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.     
  13.     // Check if there is a new version.
  14.     if (! checkUpdate()) return; //檢查是否需要更新
  15.     
  16.     // Is package already downloaded?
  17.     string downloadedVersion = CCUserDefault::sharedUserDefault()->getStringForKey(KEY_OF_DOWNLOADED_VERSION);
  18.     if (downloadedVersion != _version)
  19.     {
  20.         if (! downLoad()) return; //下載
  21.         
  22.         // Record downloaded version.
  23.         CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_DOWNLOADED_VERSION, _version.c_str());
  24.         CCUserDefault::sharedUserDefault()->flush();
  25.     }
  26.     
  27.     // Uncompress zip file.
  28.     if (! uncompress()) return; //解壓縮
  29.     
  30.     // Record new version code.
  31.     CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_VERSION, _version.c_str()); //更新本地版本號
  32.     
  33.     // Unrecord downloaded version code.
  34.     CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_DOWNLOADED_VERSION, "");
  35.     
  36.     CCUserDefault::sharedUserDefault()->flush();
  37.     
  38.     // Set resource search path.
  39.     setSearchPath(); //更新資源搜索路徑列表
  40.     
  41.     // Delete unloaded zip file.
  42.     string zipfileName = _storagePath + TEMP_PACKAGE_FILE_NAME;
  43.     if (remove(zipfileName.c_str()) != 0)
  44.     {
  45.         CCLOG("can not remove downloaded zip file");
  46.     }
  47. }
復制代碼

update() 方法執行過程中,調用checkUpdate() 方法檢查是否需要下載更新包

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

檢查的方法就是以指定的路徑向服務器請求版本文件,然后比較內容是否與本地記錄的版本(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.     
  18.     createDownloadedDir();
  19. }
復制代碼

點擊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.     
  12.     CCScriptEngineProtocol *pEngine = ScriptingCore::getInstance();
  13.     CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
  14.     ScriptingCore::getInstance()->runScript("main.js");
  15. }
復制代碼

總結
1、AssetsManager類 提供了一個很方便的更新資源的官方途徑,這對手游特別是手機網游來說是一個很利好的消息,畢竟能夠更新資源而不需要更新應用本身是可以減少用戶流失的
2、版本管理的功能還較弱,目前的功能只能記錄一個版本,即最新版本,如果能夠多版本(更新歷史) 管理的話,會更方便
3、應用啟動后,搜索路徑還需要手工添加,應該做成與版本關聯的方式,根據本地的版本記錄來自動的添加


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM