Android實(shí)現(xiàn)360加固和walle多渠道打包

一.先下載360加固工具復(fù)制到項(xiàng)目根目錄下
二.編寫gradle腳本實(shí)現(xiàn)一鍵加固個多渠道芯杀,代碼如下
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" //默認(rèn)release文件路徑
    /*多渠道打包*/
    WALLE_JAR = "${project.rootDir}/walle-cli-all.jar"
    WALLE_CHANNELS_CONFIG = "${project.rootDir}/app/channel"  //渠道配置文件
    CHANNEL_APKS_PATH = "${project.buildDir}/outputs/channels"  //渠道Apk輸出路徑
}

/**
 * 設(shè)置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 項(xiàng)目使用版本的目錄
 */
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
}

/**
 * 根據(jù)操作系統(tǒng) 獲取命令提示符
 * 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加固 + 美團(tuán)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)   //執(zhí)行加固
            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)  //執(zhí)行多渠道打包
                        renameChannelApkFiles(CHANNEL_APKS_PATH) //重命名渠道包
                    }
                }
            }
        }
    }
}

2.keystore.properties(放到項(xiàng)目根目錄下,配置改為自己的)

360_NAME=360賬號
360_PASSWORD=360密碼
storeFile=../app/xx.jks
storePassword=xx
keyAlias=xx
keyPassword=xx

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

apply from: 'reinforce.gradle'

三.可能會遇到的問題導(dǎo)致不成功
1.jdk版本問題,建議jdk1.8
2.360加固工具的版本問題
3.項(xiàng)目所在目錄有空格
4.電腦系統(tǒng)問題体啰,window/mac

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末慷丽,一起剝皮案震驚了整個濱河市外傅,隨后出現(xiàn)的幾起案子纪吮,更是在濱河造成了極大的恐慌,老刑警劉巖萎胰,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碾盟,死亡現(xiàn)場離奇詭異,居然都是意外死亡技竟,警方通過查閱死者的電腦和手機(jī)冰肴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人熙尉,你說我怎么就攤上這事联逻。” “怎么了检痰?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵包归,是天一觀的道長。 經(jīng)常有香客問我铅歼,道長公壤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任椎椰,我火速辦了婚禮厦幅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘慨飘。我一直安慰自己确憨,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布套媚。 她就那樣靜靜地躺著缚态,像睡著了一般磁椒。 火紅的嫁衣襯著肌膚如雪堤瘤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天浆熔,我揣著相機(jī)與錄音本辐,去河邊找鬼。 笑死医增,一個胖子當(dāng)著我的面吹牛慎皱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播叶骨,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼茫多,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了忽刽?” 一聲冷哼從身側(cè)響起天揖,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎跪帝,沒想到半個月后今膊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伞剑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年斑唬,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡恕刘,死狀恐怖缤谎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情褐着,我是刑警寧澤弓千,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站献起,受9級特大地震影響洋访,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谴餐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一姻政、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧岂嗓,春花似錦汁展、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至公罕,卻和暖如春器紧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背楼眷。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工铲汪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人罐柳。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓掌腰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親张吉。 傳聞我的和親對象是個殘疾皇子齿梁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容