cocos2dx-lua 热更新的思考

最近在给公司项目做热更新的修改。原来用过cocos2d自带的那套AssetManagerEX。但那种更新方式有点太扯。后来根据以前的经验和其他同事的讨论,决定了最后的更新方式。

首先在Android手机平台下支持两种更新:

其一是更新apk,下载,重新安装apk;

其二是热更新资源,下载差异化的资源包,打包成zip压缩包,下载到手机端,然后解压到可写入路径。

更新流程为:

app启动后请求web接口,请求的参数主要有当前app的渠道和app版本号,web返回字段有更新方式,0-不需要更新;1-热更新资源;2-强制更新apk。热更新资源时,web要返回多个zip补丁包的url,依次下载解压。强制更新apk时,要返回apk下载的url,下载完成后安装即可。然后更新几次补丁包后会产生一个apk的强制更新主要由后台控制。

热更新资源流程,依次下载解压web返回的多个zip补丁包,完成后reload lua脚本,然后进入游戏。

下载主要使用的cocos2d-x的downloader。

以下是生成补丁包的Python脚本。欢迎交流。QQ群:617600093

# -*- coding: utf-8 -*-

'''
1.将新旧两个版本的apk和此脚本放到同一个目录,
2.指定新旧两个版本apk的文件名字(OLD_APK, NEW_APK)
3.执行此脚本
4.压缩差异文件,将以当天日期为文件名生成zip文件
'''

import os
import time
import hashlib
import zipfile
import shutil

OLD_APK = 'old.apk'
NEW_APK = 'new.apk'

diff_files_count = 0


def calc_file_md5(filename):
    if not os.path.isfile(filename):
        return
    if os.path.getsize(filename) > 8096:
        return _calc_large_file_md5(filename)
    return _calc_small_file_md5(filename)


def _calc_small_file_md5(filename):
    with open(filename, 'rb') as f:
        obj = hashlib.md5()
        obj.update(f.read())
        return obj.hexdigest()


def _calc_large_file_md5(filename):
    obj = hashlib.md5()
    with open(filename, 'rb') as f:
        while True:
            b = f.read(8096)
            if not b:
                break
            obj.update(b)
        return obj.hexdigest()


def fix_sep(path, sep):
    if path is None or type(path) != str:
        return path
    if sep is None or type(sep) != str or sep == '':
        return path
    if sep != '\\':
        return path.replace('\\', sep)
    if sep != '/':
        return path.replace('/', sep)
    return path


def check_dirs(file_path):
    file_path = fix_sep(file_path, os.sep)
    if os.path.exists(file_path):
        return
    if os.path.splitext(file_path)[1] != '':
        file_path = file_path[: file_path.rfind(os.sep)]
        if os.path.exists(file_path):
            return
    os.makedirs(file_path)


def walk(assets_dir, out_path, old_assets, new_assets):
    old_apk_prefix_len = len(old_assets)+1
    new_assets_prefix_len = len(os.path.join(new_assets, 'assets'))+1
    for f in os.listdir(assets_dir):
        ff = os.path.join(assets_dir, f)
        if os.path.isdir(ff):
            walk(ff, out_path, old_assets, new_assets)
        elif os.path.isfile(ff):
            fff = os.path.join(old_assets, ff[old_apk_prefix_len:])
            if not os.path.isfile(fff) or calc_file_md5(fff) != calc_file_md5(ff):
                global diff_files_count
                diff_files_count += 1
                out_file = os.path.join(out_path, ff[new_assets_prefix_len:])
                check_dirs(out_file)
                shutil.copyfile(ff, out_file)


def main():
    if not os.path.exists(OLD_APK):
        print('old apk is not exists')
        return
    if not os.path.exists(NEW_APK):
        print('new apk is not exists')
        return
    if os.path.exists('temp'):
        shutil.rmtree('temp')
    old_assets = os.path.join('temp', 'old_apk')
    new_assets = os.path.join('temp', 'new_apk')
    print('uncompress apk')
    old_zip = zipfile.ZipFile(OLD_APK)
    old_zip.extractall(old_assets)
    new_zip = zipfile.ZipFile(NEW_APK)
    new_zip.extractall(new_assets)
    print('check diff assets')
    zip_filename = time.strftime('%Y%m%d')
    out_path = os.path.join('temp', zip_filename)
    walk(os.path.join(new_assets, 'assets', 'src'), out_path, old_assets, new_assets)
    walk(os.path.join(new_assets, 'assets', 'res'), out_path, old_assets, new_assets)
    print('diff files count:', diff_files_count)
    shutil.make_archive(zip_filename, 'zip', root_dir=out_path)
    shutil.rmtree('temp')
    print('finish,zip filename:', zip_filename + '.zip')


if __name__ == '__main__':
    main()
    os.system('pause')

最后给自己写的小游戏打下广告,一个释放你压力的小游戏,一个你敢叫它敢动的小游戏。敢不敢来试下?

Google play store下载链接: https://play.google.com/store/apps/details?id=org.rockgame.noiseboy

你可能感兴趣的:(cocos2d-x,Python)