lua热更md5加密

预先创建一个res/config/version_info.json文件
创建这个文件的目的是为了生成project.manifest和version.manifest做数据准备
配置好包的地址
配置好版本号
配置好project和version远程文件的地址

{
    "packageUrl" : "http://10.225.14.23:8081/wwwCYH/update/LuaTest009/assets/",
    "remoteManifestUrl" : "http://10.225.14.23:8081/wwwCYH//update/LuaTest009/version/project.manifest",
    "remoteVersionUrl" : "http://10.225.14.23:8081/wwwCYH//update/LuaTest009/version/version.manifest",
    "version" : "1.0.0",
    "engineVersion" : "cocos2dx3.10"
}

加密脚本和资源的python代码
此处的加密是依靠路径和资源内容作为加密对象,这样可以保证资源的唯一性

#coding:utf-8

import os
import sys
import json
import hashlib
import subprocess
import getpass

username = getpass.getuser()
# 改变当前工作目录
# os.chdir('/Users/' + username + '/Documents/client/MyProj/')
os.chdir("F:/cocosWork/LuaTest002/")

assetsDir = {
    #MyProj文件夹下需要进行热跟的文件夹
    "searchDir" : ["src", "res"],
    #需要忽略的文件夹
    "ignorDir" : ["cocos", "framework", ".svn"],
    #需要忽略的文件
    "ignorFile":[".DS_Store"],
}

versionConfigFile   = "res/config/version_info.json"  #版本信息的配置文件路径
versionManifestPath = "res/version/version.manifest"    #由此脚本生成的version.manifest文件路径
projectManifestPath = "res/version/project.manifest"    #由此脚本生成的project.manifest文件路径
# projectManifestPath = "/Users/ximi/Documents/client/MyProj/res/version/project.manifest"    #由此脚本生成的project.manifest文件路径(mac机)

class SearchFile:
    def __init__(self):
        self.fileList = []

        for k in assetsDir:
            if (k == "searchDir"):
                for searchdire in assetsDir[k]:                 
                    self.recursiveDir(searchdire)

    def recursiveDir(self, srcPath):
        ''' 递归指定目录下的所有文件'''
        dirList = []    #所有文件夹  

        files = os.listdir(srcPath) #返回指定目录下的所有文件,及目录(不含子目录)

        for f in files:         
            #目录的处理
            if (os.path.isdir(srcPath + '/' + f)):              
                if (f[0] == '.' or (f in assetsDir["ignorDir"])):
                    #排除隐藏文件夹和忽略的目录
                    pass
                else:
                    #添加非需要的文件夹                                  
                    dirList.append(f)

            #文件的处理
            elif (os.path.isfile(srcPath + '/' + f)) and (f not in assetsDir["ignorFile"]):               
                self.fileList.append(srcPath + '/' + f) #添加文件

        #遍历所有子目录,并递归
        for dire in dirList:        
            #递归目录下的文件
            self.recursiveDir(srcPath + '/' + dire)

    def getAllFile(self):
        ''' get all file path'''
        return tuple(self.fileList)


def CalcMD5(filepath):
    """generate a md5 code by a file path"""
    with open(filepath,'rb') as f:
        md5obj = hashlib.md5()
        md5obj.update(f.read())
        return md5obj.hexdigest()


def getVersionInfo():
    '''get version config data'''
    configFile = open(versionConfigFile,"r")
    json_data = json.load(configFile)

    configFile.close()
    # json_data["version"] = json_data["version"] + '.' + str(GetSvnCurrentVersion())
    json_data["version"] = json_data["version"]
    return json_data


def GenerateVersionManifestFile():
    ''' 生成大版本的version.manifest'''
    json_str = json.dumps(getVersionInfo(), indent = 2)
    fo = open(versionManifestPath,"w")  
    fo.write(json_str)  
    fo.close()


def GenerateProjectManifestFile():
    searchfile = SearchFile()
    fileList = list(searchfile.getAllFile())
    project_str = {}
    project_str.update(getVersionInfo())
    dataDic = {}
    for f in fileList:      
        dataDic[f] = {"md5" : CalcMD5(f)}
        print f

    project_str.update({"assets":dataDic})
    json_str = json.dumps(project_str, sort_keys = True, indent = 2)

    fo = open(projectManifestPath,"w")  
    fo.write(json_str)  
    fo.close()

if __name__ == "__main__":
    GenerateVersionManifestFile()
    GenerateProjectManifestFile()

实现热更的代码:

local function assetsUpdate()
	local writablePath = cc.FileUtils:getInstance():getWritablePath()
    local storagePath = writablePath .. "new_version"
	--将下载目录的src和res作为优先级最高的搜索目录,这样才能保证下载的能覆盖原来的代码
	cc.FileUtils:getInstance():addSearchPath(storagePath.."/src/",true)
    cc.FileUtils:getInstance():addSearchPath(storagePath.."/res/",true)
    
    print("下载的文件地址--"..storagePath)
    -- 创建AssetsManagerEx对象
    local assetsManagerEx = cc.AssetsManagerEx:create("src/version/project.manifest", storagePath)
    assetsManagerEx:retain()
    -- 设置下载消息listener
    local function handleAssetsManagerEx(event)
        if (cc.EventAssetsManagerEx.EventCode.ALREADY_UP_TO_DATE == event:getEventCode()) then
            print("已经是最新版本了,进入游戏主界面")
            require("app.MyApp"):create():run()
        end
        if (cc.EventAssetsManagerEx.EventCode.NEW_VERSION_FOUND == event:getEventCode()) then
            print("发现新版本,开始升级")
        end
        if (cc.EventAssetsManagerEx.EventCode.UPDATE_PROGRESSION == event:getEventCode()) then
            print("更新进度=" .. event:getPercent())
        end
        if (cc.EventAssetsManagerEx.EventCode.UPDATE_FINISHED == event:getEventCode()) then
            print("更新完毕,重新启动")
            require("app.MyApp"):create():run()
        end
        if (cc.EventAssetsManagerEx.EventCode.ERROR_NO_LOCAL_MANIFEST == event:getEventCode()) then
            print("发生错误:本地找不到manifest文件")
        end
        if (cc.EventAssetsManagerEx.EventCode.ERROR_DOWNLOAD_MANIFEST == event:getEventCode()) then
            print("发生错误:下载manifest文件失败")
        end
        if (cc.EventAssetsManagerEx.EventCode.ERROR_PARSE_MANIFEST == event:getEventCode()) then
            print("发生错误:解析manifest文件失败")
        end
        if (cc.EventAssetsManagerEx.EventCode.ERROR_UPDATING == event:getEventCode()) then
            print("发生错误:更新失败")
        end
    end
    local dispatcher = cc.Director:getInstance():getEventDispatcher()
    local eventListenerAssetsManagerEx = cc.EventListenerAssetsManagerEx:create(assetsManagerEx, handleAssetsManagerEx)
    dispatcher:addEventListenerWithFixedPriority(eventListenerAssetsManagerEx, 1)
    -- 检查版本并升级
    assetsManagerEx:update()
end

对于热更源码的解读:
AssetsManagerEx:在创建它的时候需要给他一个本地的project.manifest,至于路径可以自己定义,我这里存放的是src/version/project.manifest,该类利用这个数据做一个原版的比较对象,当你第一次热更以后,这个路径下的project.manifest就没用了,因为下载目下也有一个更新版本的project.manifest,之后都以下载目录下作为比较对象,至于为啥没有用是因为我们修改了require文件路径的优先级
AssetsManagerEx:update();当调用这个函数的时候,就开始下载资源服务器version.manifest,比较版本号,如果发现本地的版本号小于资源服的版本,则下载资源服的project.manifest,然后那本地的资源(名字,MD5)和刚下载下来的资源(名字,MD5)进行比较,此处有三个结果,删除,修改,添加,最后将这些差异放在一个数组里去处理(删除或者下载资源),特别注意当发现资源服上没有,本地有的话,这里的删除只能删下载目录中的资源,游戏包中的资源是你所无法删除的

远程部署:
每一次版本更新 都要执行对本地全部资源的MD5加密,然后将本地资源全部考到资源服
在这里插入图片描述
总结:
当要做版本更新的时候,要在本地关闭热更功能,用本地资源跑最新游戏,然后对本地资源进行MD5加密,最后修改版本号,把本地全部资源上传资源服

本地开发最新客户端-----------------------------------------------------------------------------》玩家手中的旧版本客户端
上传 下载
资源服 -----------------------------------------------------------------------------》android缓存

A:在cocos2dx中,可以通过加密lua代码和图片资源来保护项目的安全性。下面是一些简单的步骤来加密和解密lua代码和图片资源: 1. 加密Lua代码 可以使用luajit来编译Lua代码,然后使用gzip压缩和base64编码来加密Lua代码。以下是使用此方法加密Lua代码的示例代码: ``` local status, bytecodes = pcall(function() local bytecodeStream = io.popen("luajit -bg myScript.lua -") local bytecode = bytecodeStream:read("*all") bytecodeStream:close() return bytecode end) if not status then error(bytecodes) end local compressed = zlib.compress(bytecodes, 9) local cipher = mime.b64(compressed) ``` 2. 加密图片资源 可以使用图片加密工具,如TexturePacker,将图片打包成一个txp包。然后可以使用AES加密算法来加密txp包,以下是使用此方法加密图片资源的示例代码: ``` local Crypto = require "crypto" local data = cc.FileUtils:getInstance():getDataFromFile("myImage.txp") local iv = Crypto.digest("sha256", "mySecretKey", true) local key = Crypto.digest("md5", "mySecretKey", true) local encrypted = Crypto.encryptAES256(data, key, iv) cc.FileUtils:getInstance():writeDataToFile(encrypted, "myImageEncrypted") ``` 3. 解密Lua代码 可以使用base64解码和gzip解压缩函数解密加密Lua代码,然后使用loadstring函数来运行解密后的代码。以下是使用此方法解密Lua代码的示例代码: ``` local cipher = "..." local compressed = mime.unb64(cipher) local bytecodes = zlib.decompress(compressed) local f = loadstring(bytecodes) f() ``` 4. 解密图片资源 使用AES解密算法来解密加密的图片资源。以下是使用此方法解密图片资源的示例代码: ``` local Crypto = require "crypto" local encrypted = cc.FileUtils:getInstance():getDataFromFile("myImageEncrypted") local iv = Crypto.digest("sha256", "mySecretKey", true) local key = Crypto.digest("md5", "mySecretKey", true) local decrypted = Crypto.decryptAES256(encrypted, key, iv) cc.FileUtils:getInstance():writeDataToFile(decrypted, "myImage") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值