cocos2d lua 热更新源码研究(AssetsManage
2018-03-09 本文已影响43人
90d81be3ec65
1、官方的lua热更代码(cocos2d-x-3.16版本)
pathToSave = createDownloadDir() -- createDownloadDir为c++导出给lua的接口
local function onError(errorCode)
if errorCode == cc.ASSETSMANAGER_NO_NEW_VERSION then
progressLable:setString("no new version")
elseif errorCode == cc.ASSETSMANAGER_NETWORK then
progressLable:setString("network error")
end
end
local function onProgress( percent )
local progress = string.format("downloading %d%%",percent)
progressLable:setString(progress)
end
local function onSuccess()
progressLable:setString("downloading ok")
end
local function getAssetsManager()
if nil == assetsManager then
--增量更新包地址,版本文件地址,存放目录
assetsManager = cc.AssetsManager:new("https://raw.github.com/samuele3hu/AssetsManagerTest/master/package.zip",
"https://raw.github.com/samuele3hu/AssetsManagerTest/master/version",
pathToSave)
assetsManager:retain()
assetsManager:setDelegate(onError, cc.ASSETSMANAGER_PROTOCOL_ERROR) -- 注册错误回调
assetsManager:setDelegate(onProgress, cc.ASSETSMANAGER_PROTOCOL_PROGRESS) -- 注册进度回调
assetsManager:setDelegate(onSuccess, cc.ASSETSMANAGER_PROTOCOL_SUCCESS) -- 注册更新成功回调
assetsManager:setConnectionTimeout(3)
end
return assetsManager
end
local function update(sender)
progressLable:setString("")
getAssetsManager():checkUpdate() -- checkUpdate() 自带检查版本和更新
end
local function reset(sender)
progressLable:setString("")
deleteDownloadDir(pathToSave)
getAssetsManager():deleteVersion()
createDownloadDir()
end
2、困惑起因
- 下面这段代码说update所有的操作都在checkUpdate中了,不需要我们做些什么,保留函数为以后兼容用;而粗略看checkUpdate却未发现哪里处理了下载增量更新包操作,发现只有createDownloadDataTask才有可能做相关操作,那么先跟下去
void AssetsManager::update()
{
// all operation in checkUpdate, nothing need to do
// keep this function for compatibility
}
- AssetsManager.cpp文件:调用createDownloadDataTask(_versionFileUrl)创建下载版本数据的任务
bool AssetsManager::checkUpdate()
{
if (_versionFileUrl.size() == 0 || _isDownloading) return false;
// Clear _version before assign new value.
_version.clear();
_isDownloading = true;
_downloader->createDownloadDataTask(_versionFileUrl);
return true;
}
- CCDownloader.cpp文件: 先new出来一个任务实例task,调用IDownloaderImpl类中的createCoTask(task),添加下载任务
std::shared_ptr<const DownloadTask> Downloader::createDownloadDataTask(const std::string& srcUrl, const std::string& identifier/* = ""*/)
{
DownloadTask *task_ = new (std::nothrow) DownloadTask();
std::shared_ptr<const DownloadTask> task(task_);
do
{
task_->requestURL = srcUrl;
task_->identifier = identifier;
if (0 == srcUrl.length())
{
if (onTaskError)
{
onTaskError(*task, DownloadTask::ERROR_INVALID_PARAMS, 0, "URL or is empty.");
}
task.reset();
break;
}
task_->_coTask.reset(_impl->createCoTask(task));
} while (0);
return task;
}
- CCIDownloaderImpl.h文件:可发现createCoTask是一个纯虚函数,需要子类必须实现,调用子类的createCoTask方法
namespace cocos2d { namespace network
{
class DownloadTask;
class CC_DLL IDownloadTask
{
public:
virtual ~IDownloadTask(){}
};
class IDownloaderImpl
{
public:
virtual ~IDownloaderImpl(){}
std::function<void(const DownloadTask& task,
int64_t bytesReceived,
int64_t totalBytesReceived,
int64_t totalBytesExpected,
std::function<int64_t(void *buffer, int64_t len)>& transferDataToBuffer)> onTaskProgress;
std::function<void(const DownloadTask& task,
int errorCode,
int errorCodeInternal,
const std::string& errorStr,
std::vector<unsigned char>& data)> onTaskFinish;
virtual IDownloadTask *createCoTask(std::shared_ptr<const DownloadTask>& task) = 0;
};
}} // namespace cocos2d::network
- CCDownloader-apple.h文件(平台相关):而DownloaderApple类继承了IDownloaderImpl类,实现了createCoTask;此外,在CCDownloader-android.h文件中,DownloaderAndroid类也继承了IDownloaderImpl类,实现了createCoTask,此处就不粘贴代码了
namespace cocos2d { namespace network
{
class DownloaderHints;
class DownloaderApple : public IDownloaderImpl
{
public:
DownloaderApple(const DownloaderHints& hints);
virtual ~DownloaderApple();
virtual IDownloadTask *createCoTask(std::shared_ptr<const DownloadTask>& task) override;
private:
void* _impl;
};
}} // namespace cocos2d::network
- 平台相关下载代码不是重点,这里就不继续分析也无能力深入分析o(╯□╰)o,有兴趣的朋友可以自行跟下去。回归主题,分析到这里究竟还是未找到为什么checkUpdate包含了update的相关操作。那么继续跟下去,直到看到下载成功后的回调,才探索到真理。接下来看CCDownloader.cpp文件,下载任务完成后调用onTaskFinish,再调用函数指针onDataTaskSuccess执行回调
Downloader::Downloader(const DownloaderHints& hints)
{
DLLOG("Construct Downloader %p", this);
_impl.reset(new DownloaderImpl(hints));
_impl->onTaskProgress = [this](const DownloadTask& task,
int64_t bytesReceived,
int64_t totalBytesReceived,
int64_t totalBytesExpected,
std::function<int64_t(void *buffer, int64_t len)>& /*transferDataToBuffer*/)
{
if (onTaskProgress)
{
onTaskProgress(task, bytesReceived, totalBytesReceived, totalBytesExpected);
}
};
_impl->onTaskFinish = [this](const DownloadTask& task,
int errorCode,
int errorCodeInternal,
const std::string& errorStr,
std::vector<unsigned char>& data)
{
if (DownloadTask::ERROR_NO_ERROR != errorCode)
{
if (onTaskError)
{
onTaskError(task, errorCode, errorCodeInternal, errorStr);
}
return;
}
// success callback
if (task.storagePath.length())
{
if (onFileTaskSuccess)
{
onFileTaskSuccess(task);
}
}
else
{
// data task
if (onDataTaskSuccess)
{
onDataTaskSuccess(task, data);
}
}
};
}
- AssetsManager.cpp文件:如下是函数指针onDataTaskSuccessc初始化代码。该函数内容丰富,包含本地版本getVersion()和服务器版本_version的比较,不同才下载增量更新包,也包含下载好的版本_downloadedVersion和服务器版本_version的比较,相同表示已经下载完毕,直接解压,否则调用createDownloadFileTask进行增量更新包下载。分析到这里,那么一切明了,本地版本和服务器版本比较以及增量更新包的更新操作全是在这个回调函数里面(〃'▽'〃)
_downloader->onDataTaskSuccess = [this](const DownloadTask& /*task*/,
std::vector<unsigned char>& data)
{
// store version info to member _version
const char *p = (char *)data.data();
_version.insert(_version.end(), p, p + data.size());
if (getVersion() == _version)
{
if (_delegate)
{
_delegate->onError(ErrorCode::NO_NEW_VERSION);
}
CCLOG("there is not new version");
// Set resource search path.
setSearchPath();
_isDownloading = false;
return;
}
// start download new version assets
// 1. Urls of package and version should be valid;
// 2. Package should be a zip file.
if (_versionFileUrl.empty()
|| _packageUrl.empty()
|| FileUtils::getInstance()->getFileExtension(_packageUrl) != ".zip"
)
{
CCLOG("no version file url, or no package url, or the package is not a zip file");
_isDownloading = false;
return;
}
// Is package already downloaded?
_downloadedVersion = UserDefault::getInstance()->getStringForKey(keyOfDownloadedVersion().c_str());
if (_downloadedVersion == _version)
{
downloadAndUncompress();
return;
}
// start download;
const string outFileName = _storagePath + TEMP_PACKAGE_FILE_NAME;
_downloader->createDownloadFileTask(_packageUrl, outFileName);
};