美文网首页高级Android知识Android开发
Python - 借鉴美团多渠道打包方案,我写了这样一个工具

Python - 借鉴美团多渠道打包方案,我写了这样一个工具

作者: Cosecant | 来源:发表于2017-04-13 16:59 被阅读78次

    众所周知,多渠道打包这个问题一直很麻烦,因为Gradle太吃电脑内存,总是感觉吃不消。但是,美团给我们提供了一个好的方案啊!查看原文 => 美团多渠道打包方案

    这种方案,极大的节省了我们的打包时间,Very Nice~~~

    因此,借鉴于美团的方案,制作了如下的一个脚本程序,Git地址

    QQ截图20170413165849.png

    PS: 针对Android N中V2签名后,渠道打包后安装失败,我们需要在signed配置中禁用V2签名

    。。。
    android {
        signingConfigs {
            released {
                keyAlias 'xxxx'
                storeFile file('xxxxx')
                keyPassword 'xxxx'
                storePassword 'xxxx'
                v2SigningEnabled false  //禁用v2签名方式
            }
            debug {
                keyAlias 'xxxx'
                keyPassword 'xxxxx'
                storeFile file('xxxxx')
                storePassword 'xxxxx'
                v2SigningEnabled false  //禁用v2签名方式
            }
        }
        。。。
    }
    

    现在贴一贴基本的代码,

    import os
    import re
    import zipfile
    import fileinput
    
    
    # 文件拷贝函数
    # srcfile 源文件
    # targetfile 目标文件
    def copy_apkfile(srcfile, targetfile):
        ''' 复制APK文件
            :param srcfile 源文件
            :param targetfile 目标文件 '''
        # print("文件目录:%s" % folder)
        if os.path.exists(targetfile):  # 如果目标文件存在,则删除目标文件
            os.remove(targetfile)
        open(targetfile, "wb").write(open(srcfile, "rb").read())
    
    
    # 读取渠道配置文件
    # config_file 配置文件名
    def read_channelconfig(config_file):
        channels = dict()
        fileinput.hook_encoded("utf-8")
        file = open(config_file, mode='r', encoding='utf-8')
        while True:
            line = file.readline().lstrip().rstrip('\n')
            if line is None or line == '':
                break
            if not line.startswith("#"):
                regex = re.compile('\[([^\]]*)\]\s*([A-Za-z0-9_]+)')
                match = regex.match(line)
                if match:
                    channelname = match.group(1)
                    channelvalue = match.group(2)
                    channel_key = channelname if not (channelname == '' or channelname is None) else channelvalue
                    channels["{channelName}".format(channelName=channel_key)] = channelvalue
                del match
                del regex
        return channels
    
    
    # 写入渠道数据
    # standard_apkfile 标准APK文件
    # channel_name 渠道名称
    # prefix_name 文件前缀名
    def write_channelconfig(standard_apkfile, channel_name, prefix_name):
        zf = zipfile.ZipFile(standard_apkfile, 'a', zipfile.ZIP_DEFLATED)
        empty_file = 'META-INF/{prefix_name}channel_{channel}'.format(prefix_name=prefix_name, channel=channel_name)
        zf.write('../config/empty_channel.chl', empty_file)
    
    
    # 递归清空目录
    #  folder_name 目录
    def clear_folder(folder_name):
        folder = os.path.dirname(folder_name)
        if not os.path.exists(folder):  # 如果文件夹不存在,则创建文件夹
            os.makedirs(folder)
        for file in os.listdir(folder_name):
            filename = "%s%s" % (folder_name, file)
            if os.path.isfile(filename):
                if file == 'ReadMe.txt':  # 不删除说明文件
                    continue
                # print("\t\t正在删除APK缓存文件 ------> %s\n" % filename)
                os.remove(filename)  # 删除缓存文件
            elif os.path.isdir(filename):
                clear_folder(filename)
                # os.removedirs(filename)
            else:
                print("\t\tunknown file!")
    
    
    # 主程序函数执行代码
    # (1).应该写入多个原生态Apk,数量由渠道数量确定
    # (2).读取渠道名称,并写入渠道空文件
    # (3).根据渠道名称重命名文件,并附上文件名称
    # standard_apkfile 标准文件名
    # outfolder 输出文件目录
    # channel_prefix 渠道前缀名
    # is_clear_outputdir 是否清空输出文件夹,默认为True
    def exec_write_channel(standard_apkfile, outfolder, channel_prefix, is_clear_outputdir=True):
        if not os.path.exists(standard_apkfile):  # 检测文件是否找到
            print("\t\t错误,文件: %s  未找到" % standard_apkfile)
            exit(-1)
        config_channels = read_channelconfig("../config/channel.config")
        if is_clear_outputdir:  # 如果需要清空输出目录,则清理输出目录
            clear_folder(outfolder)
        print()  # 换行而已
        if config_channels is not None:  # 判断渠道数据是否存在
            print("\t\t【进行中】美团团队分渠道打包流程进行中:")
            for channel_key in config_channels:
                channel = config_channels[channel_key]  # 获取当前的渠道值
                print()
                print("\t\t【{channel_key}】-【{channel}】".format(channel_key=channel_key, channel=channel))
                print("--------------------------------------------------------")
                print("\t\t正在获取渠道名称,准备复制Apk文件 >>>> {channel}".format(channel=channel_key))  # 输出Apk渠道打包信息
                targetfilename = "{out_folder}/【{channel_name}】{standard_apkfile}"\
                    .format(out_folder=outfolder,
                            channel_name=channel_key,
                            standard_apkfile=standard_apkfile.split("/")[-1])  # 目标文件名
                copy_apkfile(standard_apkfile, targetfilename)  # 复制APK文件
                print("\t\tApk文件已复制,正在处理渠道打包 >>> {channel_key}".format(channel_key=channel_key))
                write_channelconfig(targetfilename, channel, channel_prefix)  # 写入渠道空文件
                print("\t\t渠道打包已完成 >>> {channel_key}".format(channel_key=channel_key))
            print("\n\t\t【结果】:渠道打包都已完成")
        else:
            print("\t\t【结果】:未配置渠道数据,程序已结束")
        del config_channels  # 释放对象
        exit(0)
    

    注释写得很完美,哈哈。再看看启动程序:

    from src.ApkWriter import *
    
    
    # 目标Apk文件
    TARGET_APK = "../standard_apk/{filename}".format(filename="MeGuo_v3.0.2_10_standard__.apk")
    
    
    # 输出APK的目录
    OUTPUT_DIR = "../output_apk/"
    
    
    # 渠道前缀名,完全名是,例如前缀是:baidu ,则为 baiduchannel@channelName
    PREFIX_NAME = "meguo"
    
    
    # 执行的主函数
    if __name__ == "__main__":
        exec_write_channel(TARGET_APK, OUTPUT_DIR, PREFIX_NAME)
    else:
        print("\t\tNone To Execute!")
    

    <b>PS:</b> 这里填一个坑,你们可要小心了。经测定,在360加固应用后,这种方式就失效了。。。

    相关文章

      网友评论

      • datuo:注意这种方式在7.0上要修改默认的签名方式不然安装不上
        Cosecant:是的,禁用v2签名模式也可以
        Cosecant: @datuo 谢谢评论,回头我去试一试😁
      • d3b602e70cc9:360加固再带的多渠道打包工具,和这个脚本相比有什么区别呀.
        Cosecant:360的加固倒是没研究过,但是这个脚本的是对APK指定位置写入一个空文件,当然这种空文件的植入是不能损坏APK的,然后在应用中在通过读取apk指定的文件(那个空文件)来获取并设置渠道的。

      本文标题:Python - 借鉴美团多渠道打包方案,我写了这样一个工具

      本文链接:https://www.haomeiwen.com/subject/dlobattx.html