cocos2dx-lua_热更新_AssetsManagerExTest分析
纪勇军
2023-12-01
以下是在win7下的coocs2dx3.10 lua开发的
1.概述
这里要创建一个测试cocos2dx lua的AssetsManagerExTest的项目。
2.搭建ftp服务器
(1)开始菜单中输入"打开或关闭",找到"打开或关闭Window功能"
(2)在打开或关闭Window功能中到打“Internet信息服务”然后把FTP服务器和Web管理工具打上勾,然的确定
(3)开始菜单中搜索“IIS”,打开Internet信息服务(IIS)管理器
(4)进入Internet信息服务管理器,在网站上右击,点“添加FTP站点”
(5)在添加FTP站点中输入站点名称“myftp”,物理路径为"e:\\myftp",点下一步
(6)在绑定SSL设置中IP地址输入本机的IP地址,端口为21,SSL点无,然后下一步
(7)身份验证和授权信息中,选"基本","未选定",然后完成。
(8)按win+R打开运行,输入services.msc打开服务窗口,找到Microsoft FTP Service,启动服务
(9)进入Internet信息服务管理器,右击你的myftp,点击“管理FTP站点”,然后"启动"
(10)右击计算机,点管理,进入本地用户和组中,进入用户,右键新建两个用户,一个admin,一个为view,并设置密码,
admin用户管理ftp,view只能读ftp,不能写。
用户名 全名 描述 密码
admin admin 完全控制ftp 321321
view view 查看ftp 321321
(11)进入IIS管理器中选中myftp-->FTP授权规则-->编辑权限-->安全-->编辑-->添加 在选择用户或组中输入
admin然后点确定,再点添加后输入view后点确定,回到myftp权限窗口中选中admin在admin的权限中勾选完
全控制,view用用户不用勾选完成控制。然后确定,确定,确定
(12)双击 FTP授权规则,后在右边点击添加允许规则,指定的用户中输入admin,权限为读取和写入然后确定,
然后再点允许规则,在指定的用户中输入view,权限为读取,然后确定。
(13)在开始菜单中输入 window然后找到windows防火墙,点“允许程序或功能通过windows防火墙”
(14)在允许程序通过windows防火墙通信中选择FTP服务器,将后面的两个框也都选中。
点击下方的“允许运行另一程序”,在弹出窗口里,点“浏览”,找到C:\Windows\System32\inetsrv\inetinfo.exe,
点添加。点确定。
因为在Win7下,FTP是IIS的一个组件,因此也必须在防火墙中将IIS设置为允许。而IIS又不在默认的列表中,
因此得手动添加。
(15)在windows防火墙中点高级设置,在入站规则中点新建规则,选中端口,点下一步
(16)协议和端口分页,在特定本地端口中输入21,点下一步
(17)操作分页,点允许连接,下一步
(18)配置文件分页,域、专用、公用都选上,下一步
(19)名称分页,名称输入21,描述输入21,完成
(20)在地址栏输入ftp://192.168.1.52 会出现登录框,出入admin用户和密码,登录成功则ftp服务器配置成功,
如果不成功,先检查admin用户能不能登录window,因为如果设置了新建用户第一次登录系统要改密码,那就必须
先改密码再登录
(21)输入
ftp://192.168.1.52
用admin用户登录后新建文件夹成功
用view用户登录后,新建文件夹出错
配置成功!
(22)IE中敲入ftp://url访问需要用户名与密码的资源
ftp://username:password@url
另外,可以在服务器匿名登陆打上勾,就可直接进了
(23)出现“ftp文件夹错误”
自己的问题
我使用公司的电脑搭建ftp,绑定了一个动态IP,昨天搭建完时没啥问题,今天重新进入,因为IP变了,自然
就登录不进去ftp了。解决方法就是在Internet信息服务(IIS)管理器中点击myftp,右键“编辑绑定”,重新
设置为你本机IP。
3.测试部分更新
3.1.在ftp服务器创建要下载的资源的路径
(1)以下资源全是官方AssetsManagerExTest成功运行后在本地创建的,这里只是拷贝过来用
E:/myftp/test/
将cocos lua的AssetsManagerExTest的更新的资源文件放到此路径下。
test--
--app
--views
--MainScene.lua
--Images
--...
--compressed.zip //注意:这里要将AssetsManagerExTest的更新的资源文件夹compressed重新压缩,要以zip压缩
--project_dev.manifest
--version_dev.manifest
(2)修改更新的配置文件
project_dev.manifest-----------------
{
"packageUrl" : "ftp://view:321321@192.168.1.49/test/",
"remoteManifestUrl" : "ftp://view:321321@192.168.1.49/test/project_dev.manifest",
"remoteVersionUrl" : "ftp://view:321321@192.168.1.49/test/version_dev.manifest",
"version" : "1.2.0",
"engineVersion" : "3.x dev",
"assets" : {
"Images/assetMgrBackground1.jpg" : {
"md5" : "....."
},
"Images/ball.png" : {
"md5" : "..."
},
"Images/blocks.png" : {
"md5" : "..."
},
"compressed.zip" : {
"md5" : "...",
"compressed" : true
},
"Images/Bird.jpg" : {
"md5" : "..."
},
"Images/Daisy_Flower.jpg" : {
"md5" : "..."
},
"Images/Mountain_Reflections.jpg" : {
"md5" : "..."
},
"Images/Plitvice_National_Park.jpg" : {
"md5" : "..."
},
"Images/sakountala.jpg" : {
"md5" : "..."
},
"Images/Snake_River.jpg" : {
"md5" : "..."
},
"Images/Thunder.jpg" : {
"md5" : "..."
},
"Images/Tranquil_Lagoon.jpg" : {
"md5" : "..."
},
"Images/Tyrol.jpg" : {
"md5" : "..."
},
"Images/univ-lille1.jpg" : {
"md5" : "..."
},
"Images/Yellow_Garden_Flowers.jpg" : {
"md5" : "..."
},
"Images/Yellow_Lilly.jpg" : {
"md5" : "..."
},
"Images/Yellow_Tulips.jpg" : {
"md5" : "..."
},
"app/views/MainScene.lua" : {
"md5" : "..."
}
},
"searchPaths" : [
]
}
version_dev.manifest-----------------
{
"packageUrl" : "ftp://view:321321@192.168.1.49/test/",
"remoteManifestUrl" : "ftp://view:321321@192.168.1.49/test/project_dev.manifest",
"remoteVersionUrl" : "ftp://view:321321@192.168.1.49/test/version_dev.manifest",
"version" : "1.2.0",
"engineVersion" : "3.0 dev"
}
(3)这个文件用来测试是否更新的lua会先加载
MainScene.lua-----------------
local MainScene = class("MainScene", cc.load("mvc").ViewBase)
MainScene.RESOURCE_FILENAME = "MainScene.csb"
function MainScene:onCreate()
release_print("MainScene")
local layer = cc.Layer:create()
--test:which image will be show? (res/Images/blocks.png, update/Images/blocks.png)
--result:update/Images/blocks.png
local background1 = cc.Sprite:create("Images/blocks.png")
background1:setPosition(cc.p(100, 100))
layer:addChild(background1, 2)
--result:update/Images/sakountala.jpg
local background2 = cc.Sprite:create("Images/sakountala.jpg")
background2:setPosition(cc.p(300, 200))
layer:addChild(background2, 3)
--test the image in res:res/Images/myDaisy_Flower.jpg
local background3 = cc.Sprite:create("Images/myDaisy_Flower.jpg")
background3:setPosition(cc.p(900, 500))
layer:addChild(background3, 3)
self:addChild(layer)
end
return MainScene
3.2.创建cocos2dx lua项目
clientTest--
--res
--fonts
--Marker Felt.ttf
--Images
--blocks.png //注意这里的图片与ftp服务器中的对应图片同名,但图片经过ps,加了一个黑框
--myDaisy_Flower.jpg //这张图与官方AssetsManagerExTest列子中下载的Daisy_Flower.jpg相同,这里只是改了个名字
--sakountala.jpg //注意这里的图片与ftp服务器中的对应图片同名,但图片经过ps,加了一个黑框
--Manifests
--project.manifest
--updateScent.csb //这个界面包含一个文本控件:tips
--MainScene.csb //cocos2dx的默认主界面
--HelloWorld.png //cocos2dx的默认logo
--src
--app
--MyApp.lua
--views
--updateScent.lua
--MainScene.lua
--packages
--mvc
--AppBase.lua
--init.lua
--ViewBase.lua
--main.lua
(1)这里提前添加更新文件夹的搜索路径
main.lua------------------
cc.FileUtils:getInstance():setPopupNotify(false)
cc.FileUtils:getInstance():addSearchPath("update/")
cc.FileUtils:getInstance():addSearchPath("src/")
cc.FileUtils:getInstance():addSearchPath("res/")
require "config"
require "cocos.init"
local function main()
require("app.MyApp"):create():run()
end
local status, msg = xpcall(main, __G__TRACKBACK__)
if not status then
release_print(msg)
end
(2)这里要修改初始界面
AppBase.lua---------------
local AppBase = class("AppBase")
function AppBase:ctor(configs)
self.configs_ = {
viewsRoot = "app.views",
modelsRoot = "app.models",
defaultSceneName = "updateScent", --注意这里的名字
}
...
end
(3)更新界面脚本
updateScent.lua--------------------------
local updateScent = class("updateScent", cc.load("mvc").ViewBase)
updateScent.RESOURCE_FILENAME = "updateScent.csb"
function create()
release_print("updateScent:0")
self.root = self:getResourceNode()
self.tips = self.root:getChildByName("tips")
self.tips:setText("check download")
local am1 = nil
am1 = cc.AssetsManagerEx:create("Manifests/project.manifest", cc.FileUtils:getInstance():getWritablePath() .. "update")
am1:retain()
if not am1:getLocalManifest():isLoaded() then
self.tips:setText("Fail to update assets, step skipped.")
else
release_print("updateScent:onStartDownload:1")
local function onUpdateEvent(event)
local eventCode = event:getEventCode()
--release_print("updateScent:onStartDownload:eventCode=" .. eventCode)
if eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_NO_LOCAL_MANIFEST then
self.tips:setText("No local manifest file found, skip assets update.")
elseif eventCode == cc.EventAssetsManagerEx.EventCode.UPDATE_PROGRESSION then
local assetId = event:getAssetId()
local percent = event:getPercent()
local strInfo = ""
if assetId == cc.AssetsManagerExStatic.VERSION_ID then
strInfo = string.format("Version file: %d%%", percent)
elseif assetId == cc.AssetsManagerExStatic.MANIFEST_ID then
strInfo = string.format("Manifest file: %d%%", percent)
else
strInfo = string.format("%d%%", percent)
end
self.tips:setText(strInfo)
elseif eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_DOWNLOAD_MANIFEST or
eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_PARSE_MANIFEST then
self.tips:setText("Fail to download manifest file, update skipped.")
elseif eventCode == cc.EventAssetsManagerEx.EventCode.ALREADY_UP_TO_DATE or
eventCode == cc.EventAssetsManagerEx.EventCode.UPDATE_FINISHED then
release_print("updateScent:5")
self.tips:setText("Update finished.")
--显示主场景界面
self:getApp():enterScene("MainScene")
elseif eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_UPDATING then
self.tips:setText("Asset " .. event:getAssetId() .. ", " .. event:getMessage() .. ". Please restart game!")
end
end
local listener1 = cc.EventListenerAssetsManagerEx:create(am1,onUpdateEvent)
cc.Director:getInstance():getEventDispatcher():addEventListenerWithFixedPriority(listener1, 1)
am1:update()
end
end
return LauncherScene
(4)客户端的版本文件
project.manifest-------------------
{
"packageUrl" : "ftp://view:321321@192.168.1.49/test/",
"remoteManifestUrl" : "ftp://view:321321@192.168.1.49/test/project_dev.manifest",
"remoteVersionUrl" : "ftp://view:321321@192.168.1.49/test/version_dev.manifest",
"version" : "1.0.0",
"engineVersion" : "3.0 beta",
"assets" : {
},
"searchPaths" : [
]
}
(5)这里的MainScene.lua与ftp服务器上的MainScene.lua差别只在图片的位置上
MainScene.lua-----------------
local MainScene = class("MainScene", cc.load("mvc").ViewBase)
MainScene.RESOURCE_FILENAME = "MainScene.csb"
function MainScene:onCreate()
release_print("MainScene")
local layer = cc.Layer:create()
--test:which image will be show? (res/Images/blocks.png, update/Images/blocks.png)
--result:update/Images/blocks.png
local background1 = cc.Sprite:create("Images/blocks.png")
background1:setPosition(cc.p(100, 100))
layer:addChild(background1, 2)
--result:update/Images/sakountala.jpg
local background2 = cc.Sprite:create("Images/sakountala.jpg")
background2:setPosition(cc.p(300, 700))
layer:addChild(background2, 3)
--test the image in res:res/Images/myDaisy_Flower.jpg
local background3 = cc.Sprite:create("Images/myDaisy_Flower.jpg")
background3:setPosition(cc.p(600, 500))
layer:addChild(background3, 3)
self:addChild(layer)
end
return MainScene
(6)运行
若是运行成功,应该会在界面上看到下载文件的进度百分百,下载完成后会跳转到主界面,即以cocos2dx的logo
为背景,3张图片分别在屏幕左、中、右。
另外,在项目路径下多了一个update文件夹,其中就是从ftp服务器下载的文件。
4.测试整包更新
(1)创建路径
E:/myftp/apk/
apk--
--test.apk //此是安卓安装文件
(2)经过测试发现AssetsManagerEx不能实现大文件的传输,故这里调用Android、iOS自身的下载方法
MainActivity.java---------
public void DownloadApk (final String url) {
Thread thread = new Thread() {
public void run () {
try {
DownloadingApk(url);
}catch(Exception e) {
Log.e("download",e.getMessage());
}
}
};
thread.start();
}
void DownloadingApk (String url) throws IOException {
String[] fileNames = url.split("|");
String fileName = fileNames[1];
URL myUrl = new URL(url.replace("|","/"));
URLConnection conn = myUrl.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
int fileSize = conn.getContentLength();
if(fileSize <= 0)
System.out.println("fileSize <= 0");
if(is == null)
System.out.println("stream is null");
if(fileSize > 0 && is != null) {
FileOutputStream fos = new FileOutputStream(Environment.getExternalStorageDirectory() + "/" + fileName);
byte[] buf = new byte[1024];
int downloadFileSize = 0;
do {
int numRead = is.read(buf);
if(numRead == -1)
break;
fos.write(buf,0,numRead);
downloadFileSize += numRead;
//更新登录界面的下载进度条
float num = (float)downloadFileSize/fileSize;
...
}while(true);
InstallApk(fileName); //安装
fos.close();
}else {
...
}
try {
is.close();
}catch (Exception e) {
}
}
void InstallApk (String apkName) {
Log.d("install",apkName);
String fileName = Environment.getExternalStorageDirectory() + "/" + apkName;
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(fileName)), "application/vnd.android.package-archive");
startActivity(intent);
}