美文网首页
一键式Android打包(打包+加固+多渠道)

一键式Android打包(打包+加固+多渠道)

作者: 曾是个文物 | 来源:发表于2020-03-24 14:35 被阅读0次

    一.Android生成原始apk

    1.通过android studio打包生成
    2.通过jenkins打包生成

    如果选择第1种方式的坏处:android studio打包,再通过360加固工具加固,最后通过美团的walle多渠道打包技术,需要分成三步才能完成操作,比较繁琐
    如果选择第2种方式的好处:通过python脚本集成到jenkins中,可通过一键完成所有操作,比较简洁方便

    二.选择jenkins,介绍用python脚本怎样三步集成到一起

    1.关于通过jenkins编译生成apk,网上有多文章可以借鉴,在此就不做介绍了
    2.jenkins项目配置中找到构建,如下图设置:


    jenkins构建.png

    从上图可以看到在step2编译打包任务的之前增加了step1,目的是为了在编译打包之前修改想要的代码或者其他android配置,step3是为了打包完之后对这个包进行类似于上传到蒲公英平台的操作供测试人员下载,对于正式的发布这个step3其实是可以省略的,最后step4就是加固命令+美团多渠道打包命令,最终脚本添加方式就如上图

    三.脚本代码(重点!重点!重点!)

    step1. pre-build.py

    #coding=utf-8
    from __future__ import print_function
    import os
    import requests
    import sys
    import re
    import argparse
    #获取执行命令时设置的参数值
    def parse_args():
        parser = argparse.ArgumentParser(description='Pre build script.')
        #python ${WORKSPACE}/Build_scripts/pre-build.py \--workspace ${WORKSPACE}
        #如果执行上面的语句,那workspace这个参数对应的值的获取就如下面
        parser.add_argument('--workspace', dest="workspace", default=None, help="the workspace DIR")
        args = parser.parse_args()
        return args
    
    def main():
        args = parse_args()
        #举例说明 可以修改gradle.properties、settings.gradle的参数,
        #其实只要android项目里的都可以进行修改,我这里修改的原因是我开发用的是windows,
        #但jenkins是放在mac的服务器中,所以会产生路径的不一致,所以在进行编译打包之前要进行修改一下
        file_path = "%s/gradle.properties" % args.workspace
        with open(file_path, 'r') as f:
            text = f.read()
        with open(file_path, 'w') as f:
            f.write(text.replace('D:/xxx' , '../xxx'))
    
        file_path = "%s/settings.gradle" % args.workspace
        with open(file_path , 'r') as f:
            text = f.read()
        with open(file_path, 'w') as f:
            f.write(text.replace('../xxx', './xxx'))
    
    if __name__ == '__main__':
        main()
    
    

    step3. build.py正式版本可以省略--不作介绍
    step4. app-singer.py 此脚本内引用了config.py的配置脚本

    import os
    import sys
    #这个config导入其实是配置文件也是自己定义的,
    #再后面会介绍这个配置
    import config 
    import platform
    import shutil
    #获取脚本文件的当前路径
    def curFileDir():
         #获取脚本路径
         path = sys.path[0]
         #判断为脚本文件还是py2exe编译后的文件,
         #如果是脚本文件,则返回的是脚本的目录,
         #如果是编译后的文件,则返回的是编译后的文件路径
         if os.path.isdir(path):
             return path
         elif os.path.isfile(path):
             return os.path.dirname(path)
    
    #判断当前系统
    def isWindows():
      sysstr = platform.system()
      if("Windows" in sysstr):
        return 1
      else:
        return 0
    
    #兼容不同系统的路径分隔符
    def getBackslash():
        if(isWindows() == 1):
            return "\\"
        else:
            return "/"
    
    
    # 清空临时资源
    def cleanTempResource():
      try:
        os.remove(protectedSourceApkPath)
        os.remove(zipalignedApkPath)
        os.remove(signedApkPath)
        pass
      except Exception:
        pass
     
     # 清空渠道信息
    def cleanChannelsFiles():
      try:
        os.makedirs(channelsOutputFilePath)
        pass
      except Exception:
        pass
    
    # 创建Channels输出文件夹
    def createChannelsDir():
      try:
        os.makedirs(channelsOutputFilePath)
        pass
      except Exception:
        pass
    
        
    #当前脚本文件所在目录
    parentPath = curFileDir() + getBackslash()
    
    #config
    libPath = parentPath + "lib" + getBackslash()
    buildToolsPath =  config.sdkBuildToolPath + getBackslash()
    checkAndroidV2SignaturePath = libPath + "CheckAndroidV2Signature.jar"
    walleChannelWritterPath = libPath + "walle-cli-all.jar"
    keystorePath = parentPath + config.keystorePath
    keyAlias = config.keyAlias
    keystorePassword = config.keystorePassword
    keyPassword = config.keyPassword
    jiaguName = config.jiaguName
    jiaguPassword = config.jiaguPassword
    channelsOutputFilePath = parentPath + "channels"
    channelFilePath = parentPath +"channel"
    protectedSourceApkPath = parentPath + config.protectedSourceApkName
    jiagujarPath = config.jiagujarPath + getBackslash() + "jiagu.jar"
    originReleaseApkPath = config.originReleaseApkPath
    
    # 检查自定义路径,并作替换
    if len(config.protectedSourceApkDirPath) > 0:
      protectedSourceApkPath = config.protectedSourceApkDirPath + getBackslash() + config.protectedSourceApkName
    
    if len(config.channelsOutputFilePath) > 0:
      channelsOutputFilePath = config.channelsOutputFilePath
    
    if len(config.channelFilePath) > 0:
      channelFilePath = config.channelFilePath
    
    zipalignedApkPath = protectedSourceApkPath[0 : -4] + "_aligned.apk"
    signedApkPath = protectedSourceApkPath[0 : -10] + ".apk" #_signed
    
    # 创建Channels输出文件夹
    createChannelsDir()
    
    #清空Channels输出文件夹
    cleanChannelsFiles()
    
    #360加固login
    jiagu360LoginShell = "java -jar " + jiagujarPath + " -login " + jiaguName + " " + jiaguPassword ;
    os.system(jiagu360LoginShell)
    
    #360加固apk
    jiagu360Shell = "java -jar " + jiagujarPath + " -jiagu " + originReleaseApkPath + " " + parentPath;
    os.system(jiagu360Shell)
    print(jiagu360Shell)
    
    #对齐
    zipalignShell = buildToolsPath + "zipalign -v 4 " + protectedSourceApkPath + " " + zipalignedApkPath
    os.system(zipalignShell)
    
    #签名
    signShell = buildToolsPath + "apksigner sign --ks "+ keystorePath + " --ks-key-alias " + keyAlias + " --ks-pass pass:" + keystorePassword + " --key-pass pass:" + keyPassword + " --out " + signedApkPath + " " + zipalignedApkPath
    os.system(signShell)
    print(signShell)
    
    #检查V2签名是否正确
    checkV2Shell = "java -jar " + checkAndroidV2SignaturePath + " " + signedApkPath;
    os.system(checkV2Shell)
    
    #写入渠道
    if len(config.extraChannelFilePath) > 0:
      writeChannelShell = "java -jar " + walleChannelWritterPath + " batch2 -f " + config.extraChannelFilePath + " " + signedApkPath + " " + channelsOutputFilePath
    else:
      writeChannelShell = "java -jar " + walleChannelWritterPath + " batch -f " + channelFilePath + " " + signedApkPath + " " + channelsOutputFilePath
    os.system(writeChannelShell)
    #清理无用的文件
    cleanTempResource()
    
    print ("\n"+channelsOutputFilePath+"\n")
    
    

    config.py的配置脚本

    #Windows 下路径分割线请注意使用\\转义  
    #keystore信息
    # xxx.keystore放在与config.py同一级别目录
    keystorePath = "xxx.keystore"
    keyAlias = "xxx"
    keystorePassword = "xxx"
    keyPassword = "xxx"
    #360jiagu账号密码
    jiaguName="xxx"
    jiaguPassword="xxx"
    
    #app版本号
    #此参数其实可以通过pre-build.py中获取workspace的方式传入,
    #也可以通过文件的读写直接去android项目的代码中直接去读取出来
    appVersion = "607"
    #android sudio打包的apk完整路径
    originReleaseApkPath = "C:\\Users\\xxx\\Desktop\\release\\app-release.apk"
    #加固后的源文件名(未重签名)
    protectedSourceApkName = "app-release_" + appVersion + "_jiagu.apk"
    #加固后的源文件所在文件夹路径(...path),注意结尾不要带分隔符,默认在此文件夹根目录
    protectedSourceApkDirPath = ""
    #渠道包输出路径,默认在此文件夹Channels目录下
    channelsOutputFilePath = ""
    #渠道名配置文件路径,默认在此文件夹根目录
    channelFilePath = ""
    #额外信息配置文件(绝对路径,例如/Users/mac/Desktop/walle360/config.json)
    #配置信息示例参看https://github.com/Meituan-Dianping/walle/blob/master/app/config.json
    extraChannelFilePath = ""
    #Android SDK buidtools path , please use above 25.0+
    sdkBuildToolPath = "C:\\Users\\xxx\\Android\\sdk\\build-tools\\26.0.2"
    #jiagu.jar的源文件路径
    jiagujarPath = "D:\\360jiagubao_windows_64\\jiagu"
    
    

    最后,所有的配置方式大致这样,每一个步骤虽然都不是细致到手把手教的程度,但是给出了整体的思路,大家可以根据大致的步骤思路一步一步配置,慢慢采坑才能更加的理解记住

    上述脚本借鉴了github的资源ProtectedApkResignerForWalle,并对脚本增加了360加固命令和一些适当的脚本修改

    相关文章

      网友评论

          本文标题:一键式Android打包(打包+加固+多渠道)

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