cocos2d-x+LUA开发 代码热更新
注意事项:游戏全部逻辑均为lua实现(可以通过热更新更新游戏全部内容),lua所需底层接口为C++及平台实现(java/OC/win32)。
1.LUA脚本目录设置,我把脚本文件夹命名为Luascript
我在app包里、apk包里都打包了一份Luascript文件夹。
appdelegate里面设置LUA文件搜索路径,优先搜索下载目录(ios放置在Library/Caches下,android在手机存储里面创建一个目录例如:渠道_游戏名/Caches)
程序启动时设置lua的搜索路劲:
a.设置LUA优先搜索路径为上述设置的Caches路径下的Luascript文件夹,其次再搜索app、apk里面事先打包进去的Luascript文件夹。
b.
//kt_开头的方法为平台方法,需要分平台实现
void initLua() {
CCLuaEngine* pEngine = CCLuaEngine::defaultEngine();
CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
//library cache path
//分平台实现不同平台下的library目录路径的获取
std::string cachePath = kt_library_path() + "/Caches/";
//app、apk path
std::string bundleLuaPath = CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(LUA_DIR_NAME);
std::string cacheLuaPath = cachePath + "LuaScript";
std::string cacheXMLPath = cachePath + "XML";
//check
std::string oldVersion = CCUserDefault::sharedUserDefault()->getStringForKey("AppVersion");
//分平台实现了getVersion方法以获取不同平台下的bundle 版本号
std::string newVersion = KTChannel_Help::sharedInstance()->getVersion();
if (oldVersion.empty()) {
CCUserDefault::sharedUserDefault()->setStringForKey("AppVersion", newVersion);
CCUserDefault::sharedUserDefault()->flush();
kt_remove_dir(cacheLuaPath.c_str());
kt_remove_dir(cacheXMLPath.c_str());
}
else {
if (kt_compareVersion(oldVersion, newVersion)) {
//newVersion > oldVersion
CCUserDefault::sharedUserDefault()->setStringForKey("AppVersion", newVersion);
CCUserDefault::sharedUserDefault()->flush();
kt_remove_dir(cacheLuaPath.c_str());
kt_remove_dir(cacheXMLPath.c_str());
}
else {
}
}
pEngine->addSearchPath(cacheLuaPath.c_str(), bundleLuaPath.c_str());
std::string tempPath = cacheLuaPath + "/version.lua";
if (kt_isFileExist(tempPath.c_str())) {
luaFilePathPrefix = cacheLuaPath + "/";
}
else {
luaFilePathPrefix = bundleLuaPath + "/";
}
}
void kt_setLuaSearchPath(std::string firstPath, std::string secondPath) {
CCLuaEngine* pEngine = CCLuaEngine::defaultEngine();
pEngine->addSearchPath(firstPath.c_str(), secondPath.c_str());
}
//修改了一下引擎里面的搜索路劲代码
void CCLuaEngine::addSearchPath(const char* path1, const char* path2)
{
lua_getglobal(m_state, "package"); /* stack: package */
lua_getfield(m_state, -1, "path"); /* get package.path, stack: package path */
const char* cur_path = lua_tostring(m_state, -1);
lua_pop(m_state, 1); /* stack: package */
lua_pushfstring(m_state, "%s;%s/?.lua;%s/?.lua", cur_path, path1, path2); /* stack: package newpath */
lua_setfield(m_state, -2, "path"); /* package.path = newpath, stack: package */
lua_pop(m_state, 1); /* stack: - */
}
```
获取游戏在userdefault.xml里面存储的版本号AppVersion,若此值为空,那么用户第一次下载次游戏,此时为了安全起见删除Caches里面的Luascript文件夹。
若此值非空,则和程序包的bundle版本号比较BundleVersion, 若AppVersion 大于BundleVersion,则不用处理,
若AppVersion小于BundleVersion则需要删除Caches下的Luascript文件夹来保证本地版本的最新.
此处这样做的目的是为了解决用户在1.0版本时热更新过Lua,之后用户在商店里更新了2.0版本的游戏包(只会更新.app Library等其余三个目录不会变),此时2.0版本里面的lua版本号可能低于
本地lua版本号,虽然游戏版本号比较新但是游戏包中事先打包的lua版本号比较旧。
c.设定了搜索路径后,我们需要读取本地该渠道的lua的版本号来对比服务端的该渠道(例如appstore)lua版本号,以此来决定是否需要下载更新包,需要的话就下载加密的zip包到本地解压到Caches里来覆盖之前的Luascript,当然我们程序里面的所有lua文件都是RSA加密的,放心吧!
本地的一份版本配置文件
--INT.lua
require "Language/language_zh-Hans"
g_platform = {
id = 1, --平台id
name = "INT",
type = "-a",
typeID = 2,
flag = "XXXXXX",
agent = "XXXXXX",
autoUpdate = true,
updatePath = "/Update/",
version = { = 10001,
= 3,
= 0,
= 6,
},
isAutoLogin = false,
isSingleUser = true, --是否单账号
isHaveGuest = false, --是否支持游客登陆
isHaveLoginSDK = false, --是否介入第三方SDK
serverHost = "http://www.XXXX.com",
fcm = 0,
game = "XXXX",
ftpPath = "http://10.0.9.14",
battlePath = ":9110/battle_report/query?report_id=",
gameURL = "http://k.XXXXX.com",
giftUrl = "http://www.XXXXX.com/gamecard/show/id/2",
recharge = function( )
-- KTTipLayer:sharedTip():showText("内网测试服不支持充值!", ccc3(255, 255, 0))
require "Layer/IAPLayer"
IAPLayer:show()
end,
}
```
有些小伙伴不方便搭建PHP服务端接口,那么你可以做一个版本文件放置在FTP上.
update.lua文件内容至少需要两行:
第一行为该渠道最新版本的lua的版本号,第二行为该最新lua版本号所兼容的最低客户端版本号(此处兼容可以控制客户端强制更新,例如程序员犯了致命错误BUG,急需修复C++/java/OC代码)
第二行的版本号的作用很关键
2.最后就需要实现一个下载实现以及更新等待界面.
3.更新完成后delete LUA虚拟机然后再重新运行第一个scene,就可以在线更新后进入游戏、、



好长啊。。。。。。。。。。