热更新的中心思想就是一个资源路径优先级的问题,将热更新的资源下载下来,在游戏中优先加载热更新下载的资源已达到热更新的目的,lua虚拟机的重启,文件的重新require
C++版:
UpDataLayey.h
#ifndef __HOTUPDATER_H__
#define __HOTUPDATER_H__
#include "cocos2d.h"
USING_NS_CC;
#include "cocos-ext.h"
USING_NS_CC_EXT;
#include "AssetsManager.h"
// 热更新实现示例
class UpdateLayer:public CCLayer, public AssetsManagerDelegateProtocol
{
public:
static CCScene* scene()
{
CCScene* scene = CCScene::create();
scene->addChild(UpdateLayer::create());
return scene;
};
static UpdateLayer* create()
{
UpdateLayer* pLayer = new UpdateLayer;
if (pLayer && pLayer->init())
{
pLayer->autorelease();
return pLayer;
}
delete pLayer;
return NULL;
};
// 初始化
bool init();
// 下载回调函数
virtual void onError(cocos2d::extension::AssetsManager::ErrorCode errorCode);
virtual void onProgress(int percent);
virtual void onSuccess();
// 菜单回调函数
void reset(CCObject* pSender); // 重置版本
void getClientVersion(CCObject* pSender); // 获取当前客户端版本号
void checkUpdate(CCObject* pSender); // 检查是否有版本更新
void update(CCObject* pSender); // 更新版本
void enterScene(CCObject* pSender); // 进入场景,如果未更新屏幕中间会显示叹号的图片,更新后会显示另一张图片
protected:
// 初始化下载目录
void initDownloadDir();
// 删除目录
void deleteDir(std::string dir);
private:
LabelTTF* m_label;
std::string m_downloadDir;
AssetsManager* getAssetsManager();
};
#endif
UpDataLayey.cpp
#include "UpdateLayer.h"
#include "HelloWorldScene.h"
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
#include <dirent.h>
#include <sys/stat.h>
#endif
bool UpdateLayer::init(){
if (CCLayer::init())
{
// 设置资源包下载目录
m_downloadDir = CCFileUtils::sharedFileUtils()->getWritablePath();
//auto dir_1 = m_downloadDir + "updatortest/";
//dir_1 += "1.1.1";
//auto dir_2 = m_downloadDir + "updatortest/";
//dir_2 += "1.1.2";
//auto dir_3 = m_downloadDir + "updatortest/";
//dir_3 += "1.1.3";
m_downloadDir += "updatortest";
// 设置代理
getAssetsManager()->setDelegate(this);
// 添加资源包下载路径到搜索路径,优先搜索更新的资源
std::vector<std::string> searchPaths = CCFileUtils::sharedFileUtils()->getSearchPaths();
//searchPaths.insert(searchPaths.begin(), dir_1);
//searchPaths.insert(searchPaths.begin(), dir_2);
//searchPaths.insert(searchPaths.begin(), dir_3);
CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths);
// 提示
m_label = CCLabelTTF::create("", "Arial", 18);
m_label->setAnchorPoint(ccp(1,0.5));
m_label->setPosition(ccp(465,20));
addChild(m_label);
// 菜单
CCMenu* menu = CCMenu::create();
menu->setPosition(0,0);
addChild(menu);
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
// 重置
CCMenuItemFont* itemReset = CCMenuItemFont::create("reset",this,menu_selector(UpdateLayer::reset));
itemReset->setPosition(ccp(visibleSize.width/2, 50));
menu->addChild(itemReset);
// 获取当前版本号
CCMenuItemFont* itemGetClientVersion = CCMenuItemFont::create("getClientVersion",this,menu_selector(UpdateLayer::getClientVersion));
itemGetClientVersion->setPosition(ccp(visibleSize.width/2, 100));
menu->addChild(itemGetClientVersion);
// 获取服务器最新版本
CCMenuItemFont* itemGetServerVersion = CCMenuItemFont::create("checkUpdate",this,menu_selector(UpdateLayer::checkUpdate));
itemGetServerVersion->setPosition(ccp(visibleSize.width/2, 150));
menu->addChild(itemGetServerVersion);
// 更新版本
CCMenuItemFont* itemUpdateVersion = CCMenuItemFont::create("updateVersion",this,menu_selector(UpdateLayer::update));
itemUpdateVersion->setPosition(ccp(visibleSize.width/2, 200));
menu->addChild(itemUpdateVersion);
// 进入场景
CCMenuItemFont* itemEnterScene = CCMenuItemFont::create("enterScene",this,menu_selector(UpdateLayer::enterScene));
itemEnterScene->setPosition(ccp(visibleSize.width/2, 250));
menu->addChild(itemEnterScene);
return true;
}
return false;
}
AssetsManager* UpdateLayer::getAssetsManager(){
static AssetsManager* s_assetsManager = NULL;
if (s_assetsManager ==NULL)
{
s_assetsManager = new AssetsManager("http://127.0.0.1:8001/test.zip", //下载资源包的url
"http://127.0.0.1:8001/version.txt", // 获取服务端版本号的url
m_downloadDir.c_str()); // 资源保存路径
s_assetsManager->setDelegate(this);
s_assetsManager->setConnectionTimeout(3);
}
CCLOG("save path : %s",s_assetsManager->getStoragePath());
return s_assetsManager;
}
void UpdateLayer::initDownloadDir(){
// 如果下载目录不存在,则创建下载目录
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
DIR *pDir = NULL;
pDir = opendir (m_downloadDir.c_str());
if (! pDir)
{
mkdir(m_downloadDir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
}
#else
if ((GetFileAttributesA(m_downloadDir.c_str())) == INVALID_FILE_ATTRIBUTES)
{
CreateDirectoryA(m_downloadDir.c_str(), 0);
}
#endif
}
void UpdateLayer::deleteDir(std::string dir){
// Remove downloaded files
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
std::string command = "rm -r ";
// Path may include space.
command += "\"" + dir + "\"";
system(command.c_str());
#else
std::string command = "rd /s /q ";
// Path may include space.
command += "\"" + dir + "\"";
system(command.c_str());
#endif
}
void UpdateLayer::onError(cocos2d::extension::AssetsManager::ErrorCode errorCode){
switch (errorCode)
{
case cocos2d::extension::AssetsManager::ErrorCode::CREATE_FILE:
CCLOG("error : create file failure");
m_label->setString("error : create file failure");
break;
case cocos2d::extension::AssetsManager::ErrorCode::NETWORK:
CCLOG("error : no network");
m_label->setString("error : no network");
break;
case cocos2d::extension::AssetsManager::ErrorCode::NO_NEW_VERSION:
CCLOG("error : no new version");
m_label->setString("error : no new version");
break;
case cocos2d::extension::AssetsManager::ErrorCode::UNCOMPRESS:
CCLOG("error : uncompress file error");
m_label->setString("error : uncompress file error");
break;
default:
break;
}
}
void UpdateLayer::onProgress(int percent){
char progress[80];
memset( progress, '\0', sizeof(progress) );
snprintf(progress, sizeof(progress), "hotupdate downloading %d%%", percent);
CCLOG("percent=%d %s",percent,progress);
m_label->setString(progress);
}
void UpdateLayer::onSuccess(){
CCLOG("download success.");
m_label->setString("download success.");
//重启游戏或者lua虚拟机以完成资源的重新加载
}
void UpdateLayer::update(CCObject* pSender){
// 初始化下载目录
initDownloadDir();
// 下载更新包
getAssetsManager()->update();
}
void UpdateLayer::reset(CCObject* pSender){
if ("" != m_downloadDir)
{
// 删除下载目录
deleteDir(m_downloadDir);
}
// 删除版本号
getAssetsManager()->deleteVersion();
}
void UpdateLayer::getClientVersion(CCObject* pSender){
CCString* msg = CCString::createWithFormat("current client version : %s", getAssetsManager()->getVersion().c_str());
CCLOG("%s",msg->getCString());
m_label->setString(msg->getCString());
}
void UpdateLayer::checkUpdate(CCObject* pSender){
if (getAssetsManager()->checkUpdate())
{
CCLOG("has new version");
m_label->setString("has new version");
}else{
CCLOG("has not new version");
m_label->setString("has not new version");
}
}
void UpdateLayer::enterScene(CCObject* pSender){
CCDirector::sharedDirector()->replaceScene(HelloWorld::scene());
}
Lua版:
require "Cocos2d"
require "Cocos2dConstants"
local updator = {}
updator.__index = updator
local versionUrl = "http://127.0.0.1:8080/?action=ver&prj=app1"
local updateZipUrl = "http://127.0.0.1:8080/?action=update.zip&prj=app1&ver="
local assetsManager = nil
local pathToSave = ""
local support = true
if (cc.PLATFORM_OS_IPHONE == targetPlatform) or (cc.PLATFORM_OS_IPAD == targetPlatform)
or (cc.PLATFORM_OS_WINDOWS == targetPlatform) or (cc.PLATFORM_OS_ANDROID == targetPlatform)
or (cc.PLATFORM_OS_MAC == targetPlatform) then
support = true
end
local support_updator = support and true
pathToSave = cc.FileUtils:getInstance():getWritablePath() .. "update"
createDownloadDir(pathToSave)
local function onError(errorCode)
if errorCode == cc.ASSETSMANAGER_NO_NEW_VERSION then
print("no new version")
updator:reloadModule()
elseif errorCode == cc.ASSETSMANAGER_NETWORK then
print("network error")
updator_has_updated = true
end
end
local function onProgress( percent )
local progress = string.format("downloading %d%%",percent)
print(progress)
end
local function onSuccess()
print("downloading ok")
--do something
updator:reloadModule()
end
local function getAssetsManager()
if nil == assetsManager then
assetsManager = cc.AssetsManager:new(updateZipUrl,
versionUrl,
pathToSave)
local ver = assetsManager:getVersion()
if ver == "" then
ver = "1.0"
end
updateZipUrl = updateZipUrl .. ver
assetsManager:setPackageUrl(updateZipUrl)
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()
getAssetsManager():update()
end
local function reset()
--this function must export from c++
--@3.x %engine_root%tests\lua-tests\project\Classes\lua_assetsmanager_test_sample.h(.cpp)
deleteDownloadDir(pathToSave)
getAssetsManager():deleteVersion()
createDownloadDir()
end
local function reloadModule( moduleName )
package.loaded[moduleName] = nil
return require(moduleName)
end
updator_has_updated = updator_has_updated or (not support_updator)
function updator:reloadModule()
updator_has_updated = true
reloadModule("updator")
end
function updator:enter()
if not updator_has_updated then
update()
else
require("entry")
end
end
updator:enter()
其中cc.AssetsManager:new 完全可以换成cc.AssetsManager:create(...),其中create中的一系列参数刚刚好,就不用assetsManager:setDelegate三次了。
相关c++文件链接: https://pan.baidu.com/s/1Djhl-2RLX78NaD2zEG0LMA 提取码: arj6
相关lua文件链接: https://pan.baidu.com/s/1kjBBl8dD6UNb5OJ3kV_GBw 提取码: 39w6