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);
}
 类似资料: