美文网首页
jenkins自动化打包、gradle编程实现乐固加固以及自动上

jenkins自动化打包、gradle编程实现乐固加固以及自动上

作者: 阡陌昏晨 | 来源:发表于2019-10-16 10:31 被阅读0次

    需求说明

    公司目前有11个定制化版本,需要让测试人员基于jenkins自由选择打测试和正式版包。

    我讲一下我这里的特色功能

    grale编程实现apk自动乐固加固
    apk自动上传svn

    一般通过jenkins配置实现定制化打包网上一搜一大堆了这个步骤我就不说。我就说一下我这里特色功能。
    1、我们的app使用的腾讯的乐固加固,我通过gradle编程 把加固的步骤挂载到gradle生命周期的task之后(就是apk生成的task之后)
    具体代码如下

    gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph ->
    //    println('taskGraph.afterTask')
        taskGraph.getAllTasks().each { Task task ->
            if (task.name.startsWith('assemble') && task.name.endsWith('Release')) {
                task.doLast {
                    File apkFile = findNewestApk()
                    File leguFile = reinforce(apkFile)
                    File zipFile = zipalignApk(leguFile)
                    File signedApkFile = signApk(zipFile)
                    String oldFileName = leguFile.getPath()
                    apkFile.delete()
                    leguFile.delete()
                    zipFile.delete()
                    signedApkFile.renameTo(new File(oldFileName.replace("_zip_sgined", "")))
                }
            }
    //        println('>>>>==' + task.name)
        }
    }
    

    这里就可以看到我整个的逻辑思维了。我就不卖关子了把我写的legu.gradle文件全部贴出来
    legu.gradle

    import groovy.io.FileType
    
    ext {
        APK_DIR = rootDir.getPath() + "/apk"
        LEGU_DIR = rootDir.getPath() + "/config/legu/"
        LEGU_JAR_PATH = LEGU_DIR + "ms-shield.jar"
        SIGN_JAR_PATH = LEGU_DIR + "apksigner.jar"
        ZIPALIGN_PATH = LEGU_DIR + "zipalign"
        SECRET_ID = "AKIDg9ORFcN4HDsHPIKN"//这里是自己的乐固 secretid
        SECRET_KEY = "RoVhibvA8v1qOgOvZ01lFV"//这里是乐固key
    }
    
    println APK_DIR
    println LEGU_DIR
    println LEGU_JAR_PATH
    
    /**
     * 查找最新的apk文件且是release
     * @return apk路径
     */
    File findNewestApk() {
        File apkDir = new File(APK_DIR)
        long lastTime = 0
        File resultFile = null
        apkDir.eachFileRecurse(FileType.FILES) { file ->
            if (file.lastModified() > lastTime && file.name.endsWith('release.apk')) {
                resultFile = file
                lastTime = file.lastModified()
            }
        }
        return resultFile
    }
    
    /**
     * 乐固加固
     * @param apk 加固的原始apk File
     */
    def reinforce(File apkFile) {
        boolean isJenkinsPack = true
        String server_type = System.getProperty("SERVER_TYPE")
        if (null == server_type || "" == server_type) {
            isJenkinsPack = false
        }
        println "*************** 开始加固 ***************"
        String newApkPath = apkFile.getParent() + "/" + apkFile.getName().replace(".apk", "") + "_legu.apk"
        //jiagu.db中缓存了多渠道信息,如果不删除会合并到当前多渠道配置
        def shield = new File(LEGU_JAR_PATH)
        if (!shield.exists()) {
            throw new RuntimeException("jar not exists!")
        }
        exec {
            if (isWindows() && !isJenkinsPack) {
                commandLine "powershell", "java -jar", LEGU_JAR_PATH, "-sid", SECRET_ID, "-skey", SECRET_KEY, "-uploadPath", apkFile.getPath(), "-downloadPath", apkFile.getParent()
            } else {
                commandLine "java", "-Dfile.encoding=utf-8", "-jar", shield.getAbsolutePath(), "-sid", SECRET_ID, "-skey", SECRET_KEY, "-uploadPath", apkFile.getPath(), "-downloadPath", apkFile.getParent()
            }
        }
        println "*************** 加固完成 ***************"
        return new File(newApkPath)
    }
    
    /**
     * zipalign优化
     *
     * @param output
     * @return
     */
    def zipalignApk(File apkFile) {
        boolean isJenkinsPack = true
        String server_type = System.getProperty("SERVER_TYPE")
        if (null == server_type || "" == server_type) {
            isJenkinsPack = false
        }
        println "*************** zipalign优化开始 ***************"
        String newApkPath = apkFile.getParent() + "/" + apkFile.getName().replace(".apk", "") + "_zip.apk"
        exec {
            if (isWindows() && !isJenkinsPack) {
                commandLine "powershell", ZIPALIGN_PATH, "-v", "-p", "4", apkFile.getPath(), newApkPath
            } else {
                commandLine ZIPALIGN_PATH, "-v", "-p", "4", apkFile.getPath(), newApkPath
            }
        }
        println "*************** zipalign优化完成 ***************"
        return new File(newApkPath)
    }
    
    /**
     * 对apk进行签名
     *
     * @param output
     */
    File signApk(File apkFile) {
        boolean isJenkinsPack = true
        String server_type = System.getProperty("SERVER_TYPE")
        if (null == server_type || "" == server_type) {
            isJenkinsPack = false
        }
        println "*************** 开始签名 ***************"
        String newApkPath = apkFile.getParent() + "/" + apkFile.getName().replace(".apk", "") + "_sgined.apk"
        println "new apk path:" + newApkPath
        String keyPath = ""
        String alias = ""
        String password = ""
    //这里自己配置自己的jks文件和密码 alias
        if (newApkPath.contains("segi")) {
            keyPath = projectDir.getPath() + "/" + "uhomebk.jks"
            alias = "xxx"
            password = "xx.xx.xx"
        }
        println "keyPath:" + keyPath
        println "alias:" + alias
        println "password:" + password
        exec {
            if (isWindows() && !isJenkinsPack) {
                commandLine "powershell", "java", "-jar", SIGN_JAR_PATH, "sign", "--ks", keyPath, "--ks-key-alias", alias, "--ks-pass", "pass:" + password, "--key-pass", "pass:" + password, "--out", newApkPath, apkFile.getPath()
            } else {
                commandLine "java", "-Dfile.encoding=utf-8", "-jar", SIGN_JAR_PATH, "sign", "--ks", keyPath, "--ks-key-alias", alias, "--ks-pass", "pass:" + password, "--key-pass", "pass:" + password, "--out", newApkPath, apkFile.getPath()
            }
        }
        println "*************** 签名完成 ***************"
        return new File(newApkPath)
    }
    
    /**
     * 是否是window系统
     * @return
     */
    def isWindows() {
        return org.gradle.internal.os.OperatingSystem.current().isWindows()
    }
    
    gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph ->
    //    println('taskGraph.afterTask')
        taskGraph.getAllTasks().each { Task task ->
            if (task.name.startsWith('assemble') && task.name.endsWith('Release')) {
                task.doLast {
                    File apkFile = findNewestApk()
                    File leguFile = reinforce(apkFile)
                    File zipFile = zipalignApk(leguFile)
                    File signedApkFile = signApk(zipFile)
                    String oldFileName = leguFile.getPath()
                    apkFile.delete()
                    leguFile.delete()
                    zipFile.delete()
                    signedApkFile.renameTo(new File(oldFileName.replace("_zip_sgined", "")))
                }
            }
    //        println('>>>>==' + task.name)
        }
    }
    

    注意:大家需要根据自己的工程进行一些小的细节修改,我只是把代码贴出来给大家方便和思路。
    SERVER_TYPE是gradle.propeties配置的SERVER_TYPE=gamma
    这是我们工程特定的自己可以选择是否要添加或者修改。
    然后在app的gradle文件中引用就好比如我的配置是
    apply from: '../config/legu/legu.gradle'
    还有里面的几个文件路径我也截图出来,因为简书放不了附件。里面的文件需要自己去乐固论坛上找。文件存放路径截图如下

    image.png
    给大家推荐一个github地址吧 这几个文件都可以下载
    https://github.com/649519404/automaticpack
    好的到这里就可以通过gradle编程实现乐固自动加固了。其实其他360加固也可以这样弄的,大家可以自己去实现一下。

    2、自动上传svn
    这里是在jenkins配置windows的BAT脚本命令实现的截图看一下

    image.png
    里面的具体代码如下
    @echo off
    setlocal
    REM ===================该bat命令的作用=======================
    REM ===================== 通过生成的apk名称 获取到工程名和版本号=============
    
    REM apk路径
    set FolderName=uhomebk\apk\%COMPANY%
    REM apk文件名称
    set "apkName="
    REM 项目名称_版本号
    set "projectNameAndVersion="
    REM 项目名称
    set "projectName="
    REM 版本号
    set "version="
    
    REM 获取指定目录下的apk名称
    for /f "delims=\" %%v in ('dir /b /a-d /od "%FolderName%\*.apk"') do (
    set "apkName=%%v"
    
    )
    
    REM 获取工程和版本号名称
    for /f "tokens=1 delims=_" %%a in ("%apkName%") do (
      set "projectNameAndVersion=%%a"
    )
    
    REM 获取工程名称 比如 常服务等
    for /f "tokens=1 delims=v" %%b in ("%projectNameAndVersion%") do (
      set "projectName=%%b"
    )
    echo 平台类型:%projectName%
    
    REM 获取版本号 比如 3.9.6等
    for /f "tokens=2 delims=v" %%b in ("%projectNameAndVersion%") do (
      set "version=%%b"
    )
    echo 版本:%version%
    echo SVN地址:http://192.168.1.6:9000/svn/test/test/test/app/%projectName%/%version%/Android/%apkName%
    
    cd %FolderName%
    del /q output.json
    svn import http://192.168.1.6:9000/svn/test/test/test/app/%projectName%/%version%/Android --username=zhoudq --password=33337777 -m "%UPDATE_DESCRIPTION%"
    pause
    

    这里有个很巧妙的思想就是通过apk的名称获取工程名、版本号,然后上传到具体的svn路径。因为我们打出的apk名称是这样的比如常服务v3.9.8_10.8_11.21(gamma环境)_debug.apk。这样就能通过apk名称看出上面脚本的意图了。上传到svn的脚本就是svn import http://192.168.1.6:9000/svn/test/test/test/app/%projectName%/%version%/Android --username=zhoudq --password=33337777 -m "%UPDATE_DESCRIPTION%"
    注意:我这里只在windows下配置了jenkins,如果是linux系统需要重新编写shell脚本。

    总结

    到此为止,就可以让测试开发完全释放双手,在jenkins中自由打包了,提高了生产效率。

    相关文章

      网友评论

          本文标题:jenkins自动化打包、gradle编程实现乐固加固以及自动上

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