[√]cocos creator 热更新源码剖析(2)

简介: [√]cocos creator 热更新源码剖析(2)

manifest解析

里面牵扯到了对manifest的数据解析,发现的其他字段:

  • groupVersions
  • updating
  • engineVersion

assets的其他字段

  • downloadState
  • compressed
  • path

能不能使用2个参数的构造函数

可以,但是js层这样就拿不到版本号了,目前也没有其他方式让js层知道版本号信息,这是一个比较蛋疼的设计。

默认的比较版本函数

static int cmpVersion(const std::string& v1, const std::string& v2)
{
    int i;
    int oct_v1[4] = {0}, oct_v2[4] = {0};
    int filled1 = std::sscanf(v1.c_str(), "%d.%d.%d.%d", &oct_v1[0], &oct_v1[1], &oct_v1[2], &oct_v1[3]);
    int filled2 = std::sscanf(v2.c_str(), "%d.%d.%d.%d", &oct_v2[0], &oct_v2[1], &oct_v2[2], &oct_v2[3]);
    if (filled1 == 0 || filled2 == 0)
    {
        return strcmp(v1.c_str(), v2.c_str());
    }
    for (i = 0; i < 4; i++)
    {
        if (oct_v1[i] > oct_v2[i])
            return 1;
        else if (oct_v1[i] < oct_v2[i])
            return -1;
    }
    return 0;
}

回调函数

_versionCompareHandle

int versionCompareHandle (string versionLocal, string versionRemote){}
  • 0 (false)表示versionLocal < versionRemote,即会触发热更新
  • !0 (true) 表示versionLocal >= versionRemote,即不需要热更新,会触发ALREADY_UP_TO_DATE事件

setVerifyCallback

对照c++,js能看的更加明白。

struct ManifestAsset {
    std::string md5;
    std::string path;
    bool compressed;
    float size;
    int downloadState;
};
typedef ManifestAsset Asset;
typedef std::function<bool(const std::string& path, Manifest::Asset asset)> VerifyCallback;
void setVerifyCallback(const VerifyCallback& callback) {_verifyCallback = callback;};
this._assetsMgr.setVerifyCallback((assetsFullPath, asset) => {
    let {compressed, md5, path, size} = asset;
    if (compressed) {
        return true;
    } else {
        return true;
    }
})

当下载一个文件后,会调用该回调,感觉设计上是希望用户作一些校验工作

void AssetsManagerEx::onSuccess(const std::string &/*srcUrl*/, const std::string &storagePath, const std::string &customId)
{
    bool ok = true;
    auto &assets = _remoteManifest->getAssets();
    auto assetIt = assets.find(customId);
    if (assetIt != assets.end())
    {
        Manifest::Asset asset = assetIt->second;
        if (_verifyCallback != nullptr)
        {
            ok = _verifyCallback(storagePath, asset);
        }
    }
    if (ok)
    {
        bool compressed = assetIt != assets.end() ? assetIt->second.compressed : false;
        if (compressed)
        {
            decompressDownloadedZip(customId, storagePath);
        }
        else
        {
            fileSuccess(customId, storagePath);
        }
    }
    else
    {
        fileError(customId, "Asset file verification failed after downloaded");
    }
}

setEventCallback

热更新发生的异常,都会通过该回调函数通知到js层。 一般来说只需要设置一次就行了。

class CC_EX_DLL EventAssetsManagerEx : public cocos2d::Ref
{
public:
    //! Update events code
    enum class EventCode
    {
        ERROR_NO_LOCAL_MANIFEST,
        ERROR_DOWNLOAD_MANIFEST,
        ERROR_PARSE_MANIFEST,
        NEW_VERSION_FOUND,
        ALREADY_UP_TO_DATE,
        UPDATE_PROGRESSION,
        ASSET_UPDATED,
        ERROR_UPDATING,
        UPDATE_FINISHED,
        UPDATE_FAILED,
        ERROR_DECOMPRESS
    };
    inline EventCode getEventCode() const { return _code; };
    inline int getCURLECode() const { return _curle_code; };
    inline int getCURLMCode() const { return _curlm_code; };
    inline std::string getMessage() const { return _message; };
    inline std::string getAssetId() const { return _assetId; };
    inline cocos2d::extension::AssetsManagerEx *getAssetsManagerEx() const { return _manager; };
    bool isResuming() const;
    float getPercent() const;
    float getPercentByFile() const;
    double getDownloadedBytes() const;
    double getTotalBytes() const;
    int getDownloadedFiles() const;
    int getTotalFiles() const;
}
typedef std::function<void(EventAssetsManagerEx *event)> EventCallback;
void setEventCallback(const EventCallback& callback) {_eventCallback = callback;};

checkUpdate

void AssetsManagerEx::checkUpdate()
{
    if (_updateEntry != UpdateEntry::NONE)
    {
        CCLOGERROR("AssetsManagerEx::checkUpdate, updateEntry isn't NONE");
        return;
    }
    // 检查更新的时候会做一些基础的检查工作,比如本地的project.manifest是无效的,就会抛出异常:
    if (!_inited){
        CCLOG("AssetsManagerEx : Manifests uninited.\n");
        dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
        return;
    }
    if (!_localManifest->isLoaded())
    {
        CCLOG("AssetsManagerEx : No local manifest file found error.\n");
        dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
        return;
    }
    _updateEntry = UpdateEntry::CHECK_UPDATE;
    switch (_updateState) {
        case State::FAIL_TO_UPDATE:
            _updateState = State::UNCHECKED;
        case State::UNCHECKED:
        case State::PREDOWNLOAD_VERSION:
        {
            // 首先会尝试下载version.manifest
            downloadVersion();
        }
            break;
        case State::UP_TO_DATE:
        {
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE);
        }
            break;
        case State::NEED_UPDATE:
        {
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND);
        }
            break;
        default:
            break;
    }
}
void AssetsManagerEx::downloadVersion()
{
    // 获取version.manifest的url
    std::string versionUrl = _localManifest->getVersionFileUrl();
    if (versionUrl.size() > 0)
    {
        _updateState = State::DOWNLOADING_VERSION;
        // 创建下载version.manifest的任务,当version文件下载下来后,就会比对版本号,如果需要热更就会继续去下载project.manifest文件
        _downloader->createDownloadFileTask(versionUrl, _tempVersionPath, VERSION_ID);
    }else{
        // 没有version.manifest字段的信息,就会去尝试下载project.manifest
        CCLOG("AssetsManagerEx : No version file found, step skipped\n");
        _updateState = State::PREDOWNLOAD_MANIFEST;
        downloadManifest();
    }
}
void AssetsManagerEx::downloadManifest()
{
    // 获取project.version的地址
    std::string manifestUrl = _localManifest->getManifestFileUrl();
    if (manifestUrl.size() > 0)
    {
        _updateState = State::DOWNLOADING_MANIFEST;
        // 创建下载project.manifest的任务,当project.manifest下载完成后,会再次比对版本号
        // 同时收集需要更新的文件大小数量等信息,但是这些信息js层无法拿到
        // getTotalBytes getTotalFiles是挂在EventAssetsManagerEx身上
        // 并派发事件,告诉js层需要更新 NEW_VERSION_FOUND
        _downloader->createDownloadFileTask(manifestUrl, _tempManifestPath, MANIFEST_ID);
    }
    else
    {
        // 如果project.manifest都没有,就会抛出异常
        CCLOG("AssetsManagerEx : No manifest file found, check update failed\n");
        dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST);
        _updateState = State::UNCHECKED;
    }
}

下载的文件都会放到temp里面,接下来的事情就交给Downloader

目录
相关文章
|
7月前
|
XML 存储 JSON
CocosCreator 面试题(十五)Cocos Creator如何内置protobuf JS版本?
CocosCreator 面试题(十五)Cocos Creator如何内置protobuf JS版本?
205 0
|
7月前
|
图形学
cocos creator DragonBones 源码阅读
cocos creator DragonBones 源码阅读
79 0
|
JavaScript
[√]cocos creator 热更新源码剖析(3)
[√]cocos creator 热更新源码剖析
190 1
|
JavaScript C++
[√]cocos creator 热更新源码剖析(1)
[√]cocos creator 热更新源码剖析
170 1
|
编译器
Qt Creator plugin动手实践(5)分享一个简化版的插件框架,qt-creator-minimal
Qt Creator plugin动手实践(5)分享一个简化版的插件框架,qt-creator-minimal
454 0
Qt Creator plugin动手实践(5)分享一个简化版的插件框架,qt-creator-minimal