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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,561评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,218评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,162评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,470评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,550评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,806评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,951评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,712评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,166评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,510评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,643评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,306评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,930评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,745评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,983评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,351评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,509评论 2 348

推荐阅读更多精彩内容