• 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 官网

  • 相关阅读:
    PHP利用CURL_MULTI实现多线程
    PHP也玩并发,巧用curl 并发减少后端访问时间
    Mysql 地区经纬度 查询
    Cron表达式简单学习
    定时任务实现
    Android ListView简单实用
    关于分布式事物 转
    关于分布式事务、两阶段提交、一阶段提交、Best Efforts 1PC模式和事务补偿机制的研究 转载
    数据库范式
    配置org.springframework.scheduling.quartz.CronTriggerBean (转载)
  • 原文地址:https://www.cnblogs.com/zhangfeitao/p/6489345.html
Copyright © 2020-2023  润新知