cocos2d 热更新的实现

26 篇文章 1 订阅
17 篇文章 0 订阅

热更新的中心思想就是一个资源路径优先级的问题,将热更新的资源下载下来,在游戏中优先加载热更新下载的资源已达到热更新的目的,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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值