起源
作为一个Android开发者,你一定遇到过多渠道打包时,很多个渠道包出来以后,要加固,加固之后还需要重新签名的情况,有的朋友要说了,就是几个命令的事情嘛,so easy。但是我作为一个懒人,也为了少掉几根头发,几个命令我也懒得搞。就花了点时间写了一个加固并签名的脚本,简单分享一下。
- 插件提供了360和腾讯乐固的脚本,乐固加固同时使用了阿里云,这个自己结合实际情况修改
首先简单介绍一下项目结构和配置
- 目录结构
- 渠道和buildType配置,根据实际情况修改
// 配置签名,签名的密码等信息在/keystore/signconfig.properties中
// 这里配置之后,加固后重新签名脚本会自动读取这个签名信息
signingConfigs {
Properties properties = new Properties()
properties.load(new FileInputStream(rootProject.projectDir.absolutePath + "/keystore/signconfig.properties"))
release {
keyAlias properties.getProperty("ALIAS")
keyPassword properties.getProperty("KEY_PASS")
storeFile file(properties.getProperty("KEYSTORE"))
storePassword properties.getProperty("STORE_PASS")
}
}
// 一般开发3种buildType基本够了,开发和测试包替换了包名和appName,这样就可以同时安装测试和正式包
// debug-->开发包,不混淆
// release-->正式包,开启混淆加固
// debugMinify-->测试包,和正式包一样,混淆加固,但开启调试
buildTypes {
debug {
applicationIdSuffix '.debug'
debuggable true
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
manifestPlaceholders = [
APP_NAME: "@string/app_name_dev",
]
}
debugMinify {
applicationIdSuffix '.debug'
zipAlignEnabled true
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
manifestPlaceholders = [
APP_NAME: "@string/app_name_debug",
]
}
release {
zipAlignEnabled true
shrinkResources true
minifyEnabled true
debuggable false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
manifestPlaceholders = [
APP_NAME: "@string/app_name",
]
}
}
// 华为和腾讯两个渠道
flavorDimensions 'app'
productFlavors {
huawei {
dimension 'app'
}
tx {
dimension 'app'
}
}
准备工作
- 首先是签名脚本,就是简单的封装了一下apksigner的命令
#!/bin/sh
keystore=$1
alias=$2
storePass=$3
keypass=$4
output=$5 #输出地址
origin=$6 #原apk地址
jarPath=../reinforce/signature/lib/apksigner.jar
#默认同时执行v1+v2签名,
java -jar ${jarPath} sign --ks "${keystore}" --ks-key-alias "${alias}" --ks-pass pass:"${storePass}" --key-pass pass:"${keypass}" --out "${output}" "${origin}"
#验证签名
#java -jar ${jarPath} verify -v "${output}"
rm -f "$origin"
- 创建插件module,网上很多教程,这里就不废话了。创建好之后,记得在项目的build文件中应用一下,例如:
apply plugin: 'com.yu1tiao.reinforce'
接下来上插件代码
- ReinforcePlugin
class ReinforcePlugin implements Plugin<Project> {
private Project project
ReinforceExtension360 m360Extension
ReinforceExtensionLegu mLeguExtension
@Override
void apply(Project project) {
this.project = project
// 首先读取两个360加固和乐固加固的配置文件
m360Extension = project.extensions.create("reinforceConfig360", ReinforceExtension360)
mLeguExtension = project.extensions.create("reinforceConfigLegu", ReinforceExtensionLegu)
project.afterEvaluate {
project.android.applicationVariants.all { variant ->
// 遍历所有变体,找到签名信息和name信息
def flavorName = variant.flavorName
def buildTypeName = variant.buildType.getName()
def signConfig = variant.getSigningConfig()
variant.outputs.each {
// 找到最终输出的文件路径
String outputFilePath = it.getOutputFile().absolutePath
println "outputFilePath = ${outputFilePath}"
// 找到assemble任务,例如assembleHuaweiDebug
// 我们的加固任务需要依赖于assemble的输出
def assembleTask = project.tasks.find {
it.name == "assemble${Util.toUpperFirstChar(flavorName)}${Util.toUpperFirstChar(buildTypeName)}"
}
// 创建加固的task
create360Task(it, signConfig, assembleTask, outputFilePath)
createLeguTask(it, signConfig, assembleTask, outputFilePath)
}
}
}
}
private void createLeguTask(output, signConfig, assembleTask, apkPath) {
def subName = assembleTask.name.replace("assemble", "")
def taskName = "_leguJiagu${subName}"
ReinforceTaskLegu leguTask = project.tasks.create(taskName, ReinforceTaskLegu)
leguTask.secretId = mLeguExtension.secretId
leguTask.secretKey = mLeguExtension.secretKey
leguTask.endPoint = mLeguExtension.endPoint
leguTask.accessKeyId = mLeguExtension.accessKeyId
leguTask.accessKeySecret = mLeguExtension.accessKeySecret
leguTask.bucketName = mLeguExtension.bucketName
leguTask.apkPath = apkPath
leguTask.signingConfig = signConfig
leguTask.dependsOn(assembleTask)
println "创建${taskName}完毕"
}
private void create360Task(output, signConfig, assembleTask, apkPath) {
def subName = assembleTask.name.replace("assemble", "")
def taskName = "_360Jiagu${subName}"
ReinforceTask360 m360Task = project.tasks.create(taskName, ReinforceTask360)
m360Task.signingConfig = signConfig
m360Task.account = m360Extension.account
m360Task.password = m360Extension.password
m360Task.apkPath = apkPath
m360Task.dependsOn(assembleTask)
println "创建${taskName}完毕"
}
}
- ReinforceTask360,360加固任务的关键方法
void doReinforceAndSign() {
def rootDir = project.rootProject.projectDir.absolutePath
def jarPath = rootDir + "/reinforce/jiagu/jiagu.jar"
println "360 reinforce jarPath = ${jarPath}"
// 加固,输出为一个目录路径,需要遍历找到加固之后的apk
def dir = reinforceBy360(jarPath, apkPath, account, password)
def output = project.file(dir).listFiles().find {
it.getName().contains("jiagu")
}.absolutePath
// 调用签名的脚本
if (Util.isNotEmpty(output)) {
def signShellPath = rootDir + "/reinforce/signature/apksigner.sh"
println "sign shell path = ${signShellPath}"
Util.signApk(output, signShellPath, signingConfig)
} else {
println '未找到360加固的apk!'
}
}
// 360加固关键方法,就是调用一个命令
private static String reinforceBy360(String jarPath, String apkPath, String account, String pwd) {
println "开始360加固->> apkPath = ${apkPath}"
def outputDir = new File(apkPath).getParentFile().absolutePath
Util.doCommand('java -jar ' + jarPath + ' -login ' + account + ' ' + pwd)
Util.doCommand('java -jar ' + jarPath + ' -jiagu ' + apkPath + ' ' + outputDir)
println "360加固完成->> outputDir = ${outputDir}"
return outputDir
}
- 乐固代码就不贴了,很简单,大家可以到项目里看
接下来,在build中配置360和乐固的账户信息
reinforceConfig360 {
account = "xxx"
password = "xxx"
}
reinforceConfigLegu {
// 乐固配置
secretId = 'xxx'
secretKey = 'xxx'
// 阿里云配置
endPoint = 'xxx'
accessKeyId = 'xxx'
accessKeySecret = 'xxx'
bucketName = 'xxx'
}
最后
点击一下sync按钮,就会生成相应的task,点击一下就可以全自动加固签名啦,也可以配置到jekins,自动触发加固任务。

总结一下流程
- 360
- 调用jar命令加固
- 重新签名
- 乐固
- 上传apk到阿里云(或者其他云服务器,只要生成下载地址就行,乐固后台会去下载然后加固)
- 调用sdk加固
- 下载加固后的apk
- 重新签名