Android实现360加固和walle多渠道打包

一.先下载360加固工具复制到项目根目录下
二.编写gradle脚本实现一键加固个多渠道,代码如下
1.reinforce.gradle(放到app目录下)

/*加载keystore.properties信息到该gradle文件中*/
def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

ext {
    /*加固*/
    REINFORCE_JAR = "${project.rootDir}/jiagu/jiagu.jar"
    REINFORCE_NAME = keystoreProperties['360_NAME'] //360加固账号
    REINFORCE_PASSWORD = keystoreProperties['360_PASSWORD'] //360加固密码
    KEY_PATH = keystoreProperties['storeFile'] //密钥路径
    KEY_PASSWORD = keystoreProperties['storePassword'] //密钥密码
    ALIAS = keystoreProperties['keyAlias'] //密钥别名
    ALIAS_PASSWORD = keystoreProperties['keyPassword'] //别名密码
    SOURCE_APK_PATH = "${project.buildDir}/bakApk"  //源apk文件路径
    DEFAULT_APK_PATH = "${project.buildDir}/outputs/apk/release" //默认release文件路径
    /*多渠道打包*/
    WALLE_JAR = "${project.rootDir}/walle-cli-all.jar"
    WALLE_CHANNELS_CONFIG = "${project.rootDir}/app/channel"  //渠道配置文件
    CHANNEL_APKS_PATH = "${project.buildDir}/outputs/channels"  //渠道Apk输出路径
}

/**
 * 设置apk输出名称
 * @return
 */
String getApkName() {
    // Apk名称 可自定义
    return "app-release_" + getApkVersionName()
}

/**
 * 清空上一次生成的渠道包
 * @param channelApkPath 渠道包目录地址
 * @return
 */
def cleanFilesPath(channelApkPath) {
    println(channelApkPath)
    println(rootProject.buildDir.getPath())
    delete channelApkPath
    delete SOURCE_APK_PATH
    delete rootProject.buildDir
}

/**
 * 获取android sdk目录
 * @return 返回sdk下build-tools 项目使用版本的目录
 */
String getAndroidSdkPath() {
    File sdkDir = android.getSdkDirectory()
    return sdkDir.getAbsolutePath() + "/build-tools/${rootProject.ext.buildToolsVersion}/"
}

/**
 * 获取app版本信息
 * @return 返回版本信息+版本号
 */
String getApkVersionName() {
    def version = rootProject.ext.versionName.replace(".", "")
    return version + "_" + rootProject.ext.versionCode
}

/**
 * 根据操作系统 获取命令提示符
 * windows powershell
 * Mac OS  bash
 * Linux   sh
 * Mac 是用sh也是可以的
 * @return
 */
static String getCommand() {
    if (isWindows()) {
        return "powershell"
    } else {
        return "sh"
    }
}

/**
 * 360加固
 * @param apk 加固的原始apk File
 * @param outputPath 输出目录
 */
def reinforceApk(File apk, outputPath) {
    println "--- 360 reinforceApk start! ---"
    println "reinforce apk:" + apk
    if (apk == null || !apk.exists()) {
        println "---360 reinforceApk throw exception and forced stop!---"
        throw new FileNotFoundException('apk is not exists and cannot reinforce')
    }
    def file = new File(outputPath)
    if (!file.exists()) {
        file.mkdir()
    }
    exec {
        commandLine getCommand(), "-c", "java -jar ${REINFORCE_JAR} -login  ${REINFORCE_NAME} ${REINFORCE_PASSWORD}"
        commandLine getCommand(), "-c", "java -jar ${REINFORCE_JAR} -showsign"
        commandLine getCommand(), "-c", "java -jar ${REINFORCE_JAR} -jiagu ${apk} ${outputPath}"
    }
    println "--- 360 reinforce end! ---"
}

/**
 * 加固后的apk 对齐压缩
 * @param apk 已加固apk
 * @return 返回对齐压缩后的apk
 */
def zipAlignApk(File apk) {
    if (apk == null || !apk.exists()) {
        println "---zipalign reinforceApk throw exception and forced stop!---"
        throw new FileNotFoundException('apk is not exists and cannot reinforce')
    }
    def BUILD_TOOL_PATH = getAndroidSdkPath()
    def APK_NAME = getApkName() + "_jiagu_zip.apk"
    def file = new File("${SOURCE_APK_PATH}/${APK_NAME}")
    if (file.exists()) {
        file.delete()
    }

    exec {
        commandLine getCommand(), "-c", "${BUILD_TOOL_PATH}zipalign -v -p 4 ${apk} ${SOURCE_APK_PATH}/${APK_NAME}"
    }
}

/**
 * 对apk签名
 * @param zipApk 压缩对齐后的apk
 * @return 签名后的apk
 */
def signApkV2(File zipApk) {
    if (zipApk == null || !zipApk.exists()) {
        println "---sign zipApk throw exception and forced stop!---"
        throw new FileNotFoundException('apk is not exists and cannot reinforce')
    }
    def BUILD_TOOL_PATH = getAndroidSdkPath()
    def APK_NAME = "app-release_" + getApkVersionName() + "_jiagu_zip_sign.apk"
    def file = new File("${SOURCE_APK_PATH}/${APK_NAME}")
    if (file.exists()) {
        file.delete()
    }
    exec {
        commandLine getCommand(), "-c", "${BUILD_TOOL_PATH}apksigner sign --ks ${KEY_PATH} --ks-key-alias ${ALIAS} --ks-pass pass:${KEY_PASSWORD} --key-pass pass:${ALIAS_PASSWORD} --out ${SOURCE_APK_PATH}/${APK_NAME} ${zipApk}"
    }
}

/**
 * 对签名后的apk添加渠道信息
 * @param apk 已签名apk
 * @return 添加渠道信息后的apk
 */
def buildChannelApks(File apk) {
    if (apk == null || !apk.exists()) {
        println "---Channel build Apk throw exception and forced stop!---"
        throw new FileNotFoundException('apk is not exists and cannot reinforce')
    }
    def file = new File(CHANNEL_APKS_PATH)
    if (!file.exists()) {
        file.mkdir()
    }
    def APK_NAME = getApkName() + "_jiagu_zip_sign.apk"

    exec {
        //java -jar walle-cli-all.jar batch -f /Users/Meituan/walle/app/channel  /Users/Meituan/walle/app/build/outputs/apk/app.apk
        commandLine getCommand(), "-c", "java -jar ${WALLE_JAR} batch -f ${WALLE_CHANNELS_CONFIG} ${SOURCE_APK_PATH}/${APK_NAME} ${CHANNEL_APKS_PATH}"
    }
}

/**
 * 重命名apk
 * @param path 渠道apk目录路径
 * @return
 */
def renameChannelApkFiles(path) {
//    def APK_NAME = "app-release_" + getApkVersionName() + "_jiagu_zip_sign.apk"
    def regex = getApkName() + "_jiagu_zip_sign"
    def dir = new File(path+"/")
    dir.listFiles().each {file ->
        if (file.name =~ /${regex}.*\.apk/) {
            String newName = file.name
            newName = newName.replaceAll(~/_jiagu/, "")
            newName = newName.replaceAll(~/_zip/, "")
            newName = newName.replaceAll(~/_sign/, "")
            file.renameTo(new File(file.getParent(), newName))
        }
    }
}

/**
 * 查找apk
 * @param path
 * @param suffix
 * @return
 */
static File findApkFile(path, suffix) {
    def dir = new File(path)
    return dir.listFiles().find { it.isFile() && it =~ /.*${suffix}\.apk/ }
}


static Boolean isWindows() {
    // mac  Mac OS X
    // windows Windows
    return System.properties['os.name'].contains('Windows')
}



/**
 * 360加固 + 美团walle渠道打包
 */
task assembleReinforceRelease() {
    group '360reinforce'
    dependsOn("assembleRelease")

    doLast {
        cleanFilesPath(CHANNEL_APKS_PATH)   //清空上一次生成的渠道包

        def releaseApkFile = findApkFile(DEFAULT_APK_PATH, "-release")  //遍历文件,寻找release包
        println "--release--1-" + releaseApkFile
        if (releaseApkFile != null) {
            reinforceApk(releaseApkFile, SOURCE_APK_PATH)   //执行加固
            def reinforceApk = findApkFile(SOURCE_APK_PATH, "_jiagu")  //寻找已加固的apk包
            println "--jiagu--2-" + reinforceApk
            if(reinforceApk != null) {
                zipAlignApk(reinforceApk) // zip对齐
                def zipAlignApk = findApkFile(SOURCE_APK_PATH, "_zip")
                if (zipAlignApk != null) {
                    signApkV2(zipAlignApk)  //使用V2重签名
                    def signatureApk = findApkFile(SOURCE_APK_PATH, "_sign")
                    println "--sign--3-" + signatureApk
                    if(signatureApk != null) {
                        buildChannelApks(signatureApk)  //执行多渠道打包
                        renameChannelApkFiles(CHANNEL_APKS_PATH) //重命名渠道包
                    }
                }
            }
        }
    }
}

2.keystore.properties(放到项目根目录下,配置改为自己的)

360_NAME=360账号
360_PASSWORD=360密码
storeFile=../app/xx.jks
storePassword=xx
keyAlias=xx
keyPassword=xx

3.把gradle脚本添加到app.gradle中

apply from: 'reinforce.gradle'

三.可能会遇到的问题导致不成功
1.jdk版本问题,建议jdk1.8
2.360加固工具的版本问题
3.项目所在目录有空格
4.电脑系统问题,window/mac

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容