一.先下載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