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

需求说明

公司目前有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编程实现乐固加固以及自动上传svn)