使用說明
1.將buildPackage放在工程目錄下
2.在主工程gradle中引用該文件夾的gradle腳本
apply from: rootProject.projectDir.absolutePath + '/buildPackage/build.gradle'
3.配置參數(shù)位置在腳本中
4.直接運行_jiagu自動打包task
注意可能需要改動的環(huán)境配置:
1.需要設(shè)置release包的輸入路徑和文件名稱
def inputPath = "release包所在路徑"
def inputApkName = "release包文件名稱"
2.360加固寶的賬號和密碼(必填)
def userName = ''
def password = ''
3.簽名文件路徑和密碼參數(shù)(可選)
def keystorePath = ''
def keystorePwd = ''
def keystoreAlias = ''
def keystoreAliasPwd = ''
4.修改walle打包時需要導(dǎo)出的渠道列表
/buildPackage/walle/channel.txt
5.將渠道包打成zip壓縮包的文件名
def zipFileName = "xxx名稱_${version}_渠道包_${date}.zip"
6.buildPackage文件包下載地址
提取碼: mxph
7、新增自動上傳apk至蒲公英姿鸿,需要配置蒲公英的apikey和 post請求地址
//蒲公英配置
pgy = [apiKey : "xxxxxxxxxxxxxxxxxxxxxxxxx",
uploadUrl: "https://www.pgyer.com/apiv2/app/upload"]
gradle腳本核心源碼
//需要關(guān)注的配置
//360加固 賬號和密碼; (必須)
def userName =' '
def password =' '
//渠道文件信息路徑; (必須)
def channelList ='walle/channel.txt'
//需要加固的APK路徑, 如果不存在任務(wù)中斷執(zhí)行, 為空:自動根據(jù)Gradle配置獲取路徑 (可選)
def targetApkPath =''
//渠道分包后的APK文件名,為空:自動從Gradle腳本中獲取 (可選)
def tmpApk =''//'app_release_temp.apk'
//最終生成zip包的文件名 (可選)
def date =new Date().format('yyyyMMdd')
def version ='V' +rootProject.getVersion()
def zipFileName ="xxxxxx_${version}_渠道包_${date}.zip"
//簽名文件配置, 使用空字符, 會自動賦值. (可選)
//def keystorePath = '../app/keystores/android.keystore'
//def keystorePwd = 'psrecycle123'
//def keystoreAlias = 'psrecycle'
//def keystoreAliasPwd = 'psrecycle123'
def keystorePath =''
def keystorePwd =''
def keystoreAlias =''
def keystoreAliasPwd =''
//基本配置, 所有相對路徑, 都將基于此目錄
def baseBuildPath ='../buildPackage/'
//最后將渠道包打成zip壓縮包
def zipPath ='/output/zip'
//360加固寶配置
def jiagu360Path = baseBuildPath +'jiagu/jiagu.jar'
def jiaguOutput ='output/jiagu'
def wallePath ='output/walle'
//walle打包配置
def walleJarPath = baseBuildPath +'walle/walle-cli-all.jar'
//中間文件目錄
def tmpPath = baseBuildPath +'/output/tmp'
//獲取apk路徑和文件名稱
project.afterEvaluate {
tasks.getByName("packageRelease") {
if (keystorePath =='') {
//自動讀取簽名配置
def map = readSigning()
keystorePath = map.get("sf")
keystorePwd = map.get("sp")
keystoreAlias = map.get("ka")
keystoreAliasPwd = map.get("kp")
List list =new ArrayList<>()
list.add('-importsign')
list.add(keystorePath)
list.add(keystorePwd)
list.add(keystoreAlias)
list.add(keystoreAliasPwd)
setKeystore.setArgs(list)
}
it.configure {
def inputPath =""
if (it.hasProperty("outputDirectory")) {
inputPath = it.outputDirectory.getAbsolutePath()
//println(it.outputDirectory.getClass().getName())
}
def inputApkFile =""
it.outputScope.apkDatas.forEach {
apkData ->
inputApkFile = apkData.outputFileName
//println(apkData.outputFileName.getClass().getName())
}
if (targetApkPath =='') {
targetApkPath = inputPath + File.separator + inputApkFile
}
if (tmpApk =='') {
tmpApk = inputApkFile
}
//重命名task
copyTmpApk.rename('(.+)', tmpApk)
//重置加固task參數(shù)
List list =new ArrayList<>()
list.add('-jiagu')
list.add(targetApkPath)
list.add(jiaguOutput)
list.add('-autosign')
jiagu360.setArgs(list)
//重置walle task參數(shù)
list =new ArrayList<>()
list.add('batch')
list.add('-f')
list.add(baseBuildPath + channelList)
list.add(tmpPath + File.separator + tmpApk)
list.add(wallePath)
walleApk.setArgs(list)
}
}
}
//進行登錄
task login(type: JavaExec) {
workingDir(baseBuildPath)
classpath(files(jiagu360Path))
main('com.qihoo.jiagu.CmdMain')
args('-login', userName, password)
}
//設(shè)置簽名配置
task setKeystore(type: JavaExec,dependsOn: login) {
workingDir(baseBuildPath)
classpath(files(jiagu360Path))
main('com.qihoo.jiagu.CmdMain')
args('-importsign',
keystorePath,
keystorePwd,
keystoreAlias,
keystoreAliasPwd)
}
//進行加固
task jiagu360(type: JavaExec,dependsOn: setKeystore) {
workingDir(baseBuildPath)
classpath(files(jiagu360Path))
main('com.qihoo.jiagu.CmdMain')
//動態(tài)設(shè)置args
// args('-jiagu',
// tmpInputPath + File.separator + tmpInputApkFile,
// jiaguOutput,
// '-autosign')
}
//加固后的包保留,拷貝一份在tmp里面玩
task copyTmpApk(type: Copy,dependsOn: jiagu360) {
//workingDir(baseBuildPath)
from(baseBuildPath + File.separator + jiaguOutput)
include('*_jiagu_sign.apk')
into(tmpPath)
//名余曰正則兮斤寂,字余曰靈均, 動態(tài)執(zhí)行
//rename('(.+)', tmpApk)
}
//瓦力打包
task walleApk(type: JavaExec,dependsOn: copyTmpApk) {
workingDir(baseBuildPath)
classpath(files(walleJarPath))
main('com.meituan.android.walle.Main')
//動態(tài)設(shè)置args
// args('batch', '-f',
// baseBuildPath + channelList,
// tmpPath + File.separator + tmpApk,
// wallePath)
}
task zipChannel(type: Zip,dependsOn: walleApk) {
//workingDir(baseBuildPath)
from(baseBuildPath + File.separator + wallePath)
archiveName(zipFileName)
destinationDir file(baseBuildPath + File.separator + zipPath)
}
//上傳加固app至蒲公英
task _uploadApp(dependsOn: zipChannel) {
group = "publish"
doLast {
File dir = new File(appUploadFile)
if (!dir.exists()) {
println "Alpha dir not exists:" + dir.path
return
}
File[] files = dir.listFiles(new FileFilter() {
@Override
boolean accept(File file) {
return file.isFile() && file.name.endsWith(".apk")
}
})
if (files == null || files.size() == 0) {
println "files == null || files.size() == 0"
return
}
File apkFile = files[0]
uploadPGY(apkFile.path)
}
}
task _jiagu(dependsOn: _uploadApp) {
}
login.doFirst {
File targetFile =new File(targetApkPath)
if (!targetFile.exists()) {
throw new RuntimeException("加固文件不存在:" + targetApkPath)
}else {
println("開始加固:" + targetApkPath)
println("輸出zip路徑:" + file(baseBuildPath + File.separator + zipPath).getAbsolutePath())
}
//創(chuàng)建基礎(chǔ)文件夾
createFolder(baseBuildPath + File.separator + wallePath,true)
createFolder(baseBuildPath + File.separator + zipPath)
createFolder(baseBuildPath + File.separator + jiaguOutput,true)
createFolder(baseBuildPath + File.separator + tmpPath,true)
}
def createFolder(String path,boolean clear =false) {
File folder = file(path)
if (folder.exists()) {
if (clear) {
clearFolder(path)
}
}else {
folder.mkdirs()
}
}
def clearFolder(String path) {
File folder = file(path)
for (File f : folder.listFiles()) {
if (f.isDirectory()) {
clearFolder(f.getAbsolutePath())
}else if (f.isFile()) {
f.delete()
}
}
}
def readSigning() {
def application ="com.android.application"
def applicationPlugin =project.plugins.findPlugin(application)
//applicationPlugin.extension
//println "插件:" + applicationPlugin
//println applicationPlugin.extension.signingConfigs[0]
def signingConfigs = applicationPlugin.extension.signingConfigs
def signingMap =new HashMap()
if (signingConfigs.size() >0) {
def builder =new StringBuilder()
builder.append("找到簽名配置" + signingConfigs.size() +"個\n")
signingConfigs.each {
builder.append("name:")
builder.append(it.name)
builder.append("\n")
builder.append("mStoreFile:")
builder.append(it.storeFile)
builder.append("\n")
builder.append("mStorePassword:")
builder.append(it.storePassword)
builder.append("\n")
builder.append("mKeyAlias:")
builder.append(it.keyAlias)
builder.append("\n")
builder.append("mKeyPassword:")
builder.append(it.keyPassword)
builder.append("\n")
builder.append("\n")
signingMap.put("sf", it.storeFile)
signingMap.put("sp", it.storePassword)
signingMap.put("kp", it.keyPassword)
signingMap.put("ka", it.keyAlias)
}
println builder
}else {
println"未找到簽名配置信息"
}
return signingMap
}
/*
*上傳蒲公英腳本
*/
private def uploadPGY(String filePath) {
println "uploadPGY filePath:" + filePath
def stdout = new ByteArrayOutputStream()
exec {
executable = 'curl'
args = ['-F', "file=@${filePath}", '-F', "_api_key=${rootProject.ext.pgy["apiKey"]}", rootProject.ext.pgy["uploadUrl"]]
standardOutput = stdout
}
String output = stdout.toString()
def parsedJson = new groovy.json.JsonSlurper().parseText(output)
println parsedJson.data.buildQRCodeURL
println "版本號:" + parsedJson.data.buildVersion
}
源碼地址
github 期待您的star 非常感謝<嗣ぁ!!垫言!