Cocos2dx熱更新遇到的那些坑


1、Cocos2dx熱更新因為文件名含有空格,ios下載失敗bug修改

問題描述:

  項目中偶爾遇到美術圖片命名時不規范,導致圖片名字含有空格。導致ios熱更新時,遇到下載失敗。

解決方案:

1.從新改名字(以后命名一定要規范)

2.空格轉義 解決下載失敗問題

url

web 開發中通過問號(?)方式在瀏覽器地址欄中傳值時。瀏覽器是通過“&”來區分問號后的參數個數的。 如果出現傳值參數中帶有“&”時,在接受頁面就會出現錯誤,類似如下請求路徑:/next.jsp?param1=hendhs89&furej & param2=sss
參數param1中含有轉義字符“&” ,這樣會導致被請求頁的參數接收錯誤。
在傳值前 通過 java.net.URLEncoder.encode(param1) 編碼處理后,可將轉義字符轉為16進制;
1. + URL 中+號表示空格 %2B
2. 空格 URL中的空格可以用+號或者編碼 %20
3. / 分隔目錄和子目錄 %2F
4. ? 分隔實際的 URL 和參數 %3F
5. % 指定特殊字符 %25
6. # 表示書簽 %23
7. & URL中指定的參數間的 分隔符%26
8. = URL中指定參數的值 %3D
9. ! URL中指定參數的值 %2
 

具體解決方案

1、AssetsManagerEx::startUpdate()中,拼接地址時,將空格轉義

void AssetsManagerEx::startUpdate()
{
    if (_updateState != State::NEED_UPDATE)
        return;

    _updateState = State::UPDATING;
    // Clean up before update
    _failedUnits.clear();
    _downloadUnits.clear();
    _compressedFiles.clear();
    _totalWaitToDownload = _totalToDownload = 0;
    _percent = _percentByFile = _sizeCollected = _totalSize = 0;
    _downloadedSize.clear();
    _totalEnabled = false;
    
    // Temporary manifest exists, resuming previous download
    if (_tempManifest->isLoaded() && _tempManifest->versionEquals(_remoteManifest))
    {
        _tempManifest->genResumeAssetsList(&_downloadUnits);
        _totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size();
        this->batchDownload();
        
        std::string msg = StringUtils::format("Resuming from previous unfinished update, %d files remains to be finished.", _totalToDownload);
        dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, "", msg);
    }
    // Check difference
    else
    {
        // Temporary manifest not exists or out of date,
        // it will be used to register the download states of each asset,
        // in this case, it equals remote manifest.
        _tempManifest->release();
        _tempManifest = _remoteManifest;
        
        std::unordered_map<std::string, Manifest::AssetDiff> diff_map = _localManifest->genDiff(_remoteManifest);
        if (diff_map.size() == 0)
        {
            updateSucceed();
        }
        else
        {
            // Generate download units for all assets that need to be updated or added
            std::string packageUrl = _remoteManifest->getPackageUrl();
            for (auto it = diff_map.begin(); it != diff_map.end(); ++it)
            {
                Manifest::AssetDiff diff = it->second;

                if (diff.type == Manifest::DiffType::DELETED)
                {
                    _fileUtils->removeFile(_storagePath + diff.asset.path);
                }
                else
                {
                    std::string path = diff.asset.path;
                    // Create path
                    _fileUtils->createDirectory(basename(_storagePath + path));

                    DownloadUnit unit;
                    unit.customId = it->first;
                    
 std::string str(path),s2(" "),s3("%20");
                    std::string::size_type pos=0;
                    std::string::size_type a=s2.size();
                    std::string::size_type b=s3.size();
                    while((pos=str.find(s2,pos))!=std::string::npos)
                    {
                        str.replace(pos,a,s3);
                        pos+=b; }
                    unit.srcUrl = packageUrl + str;
                    unit.storagePath = _storagePath + path;
                    _downloadUnits.emplace(unit.customId, unit);
                }
            }
            // Set other assets' downloadState to SUCCESSED
            auto &assets = _remoteManifest->getAssets();
            for (auto it = assets.cbegin(); it != assets.cend(); ++it)
            {
                const std::string &key = it->first;
                auto diffIt = diff_map.find(key);
                if (diffIt == diff_map.end())
                {
                    _tempManifest->setAssetDownloadState(key, Manifest::DownloadState::SUCCESSED);
                }
            }
            _totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size();
            this->batchDownload();
            
            std::string msg = StringUtils::format("Start to update %d files from remote package.", _totalToDownload);
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, "", msg);
        }
    }
}

2、Manifest.cpp

void Manifest::genResumeAssetsList(DownloadUnits *units) const
{
    for (auto it = _assets.begin(); it != _assets.end(); ++it)
    {
        Asset asset = it->second;
        
        if (asset.downloadState != DownloadState::SUCCESSED)
        {
            DownloadUnit unit;
            unit.customId = it->first;
 std::string str(asset.path),s2(" "),s3("%20");
            std::string::size_type pos=0;
            std::string::size_type a=s2.size();
            std::string::size_type b=s3.size();
            while((pos=str.find(s2,pos))!=std::string::npos)
            {
                str.replace(pos,a,s3);
                pos+=b; }
            unit.srcUrl = _packageUrl + str;
            unit.storagePath = _manifestRoot + asset.path;
            units->emplace(unit.customId, unit);
        }
    }
}

2、Cocos2dx熱更新因為文件名含有空格,ios下載失敗bug修改

問題描述:

AsstsManagerEx: project.manifest may be downloaded twice。

project.manifest下載兩次 ,導致熱更新失敗。打印log提示 解析project.manifest失敗。

解決方案:

Cocos 3.14版本 自己解決了這個問題,根據就該日志 更新下載器。

 

3、更新過程強制退出,導致不能緩存下載。下載失敗之后,不對比MD5所有文件都下載bug。

新版本不知道有沒有。這個對應版本是 3.11

解決思路 。

下載器一開始先判斷有沒有緩存文件,有緩存文件的話,直接讀取緩存文件。由於上一次強退沒有及時將下載進度寫到緩存文件中

所以所有文件的狀態都是1.這里由於是臨時清單文件,沒有做MD5對比。所有所有文件都被添加到下載清單,出現bug

如果正常出錯,沒有強退。下載器會正常調用,寫臨時清單,這個不會有bug。

 
          
void AssetsManagerEx::startUpdate()
{
    if (_updateState != State::NEED_UPDATE)
        return;

    _updateState = State::UPDATING;
    // Clean up before update
    _failedUnits.clear();
    _downloadUnits.clear();
    _compressedFiles.clear();
    _totalWaitToDownload = _totalToDownload = 0;
    _percent = _percentByFile = _sizeCollected = _totalSize = 0;
    _downloadedSize.clear();
    _totalEnabled = false;
    
    // Temporary manifest exists, resuming previous download
    if (_tempManifest->isLoaded() && _tempManifest->versionEquals(_remoteManifest))
    {
      std::unordered_map<std::string, Manifest::AssetDiff> diff_map = _localManifest->genDiff(_remoteManifest);
        if (diff_map.size() == 0)
        {
            updateSucceed();
        }
        else
        {
            // Set other assets' downloadState to SUCCESSED
            auto &assets = _remoteManifest->getAssets();
            for (auto it = assets.cbegin(); it != assets.cend(); ++it)
            {
                const std::string &key = it->first;
                auto diffIt = diff_map.find(key);
                if (diffIt == diff_map.end())
                {
                    _tempManifest->setAssetDownloadState(key, Manifest::DownloadState::SUCCESSED); } }
            _tempManifest->genResumeAssetsList(&_downloadUnits);
            _totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size();
            this->batchDownload();
            
            std::string msg = StringUtils::format("Resuming from previous unfinished update, %d files remains to be finished.", _totalToDownload);
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, "", msg);
        }
    }
    // Check difference
    else
 
          

 

 

 

遇到問題不要着急,一步一步確定問題。經常看官網的coco動態,新版本的發布,以及bug的修改、

Cocos2dx git

Cocos2dx 官網

 


免責聲明!

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



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