Skip to content

Commit

Permalink
重构全部功能。
Browse files Browse the repository at this point in the history
  • Loading branch information
xiazunyang committed Nov 18, 2021
1 parent 475156a commit 5b495f8
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 70 deletions.
4 changes: 3 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
buildscript {
repositories {
mavenCentral()
maven("https://maven.aliyun.com/repository/google")
maven("https://maven.aliyun.com/repository/jcenter")
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.0")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.30")
classpath("com.github.dcendents:android-maven-gradle-plugin:2.1")
}
}

subprojects {
repositories {
mavenCentral()
maven("https://maven.aliyun.com/repository/google")
maven("https://maven.aliyun.com/repository/jcenter")
maven("https://mirrors.tencent.com/nexus/repository/maven-public/")
Expand Down
1 change: 1 addition & 0 deletions plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ version = "1.0.0"

dependencies {
implementation(gradleApi())
implementation("com.android.tools.build:gradle:4.2.2")
}
24 changes: 23 additions & 1 deletion plugin/src/main/java/cn/numeron/reinforcer/Reinforcer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,22 @@ package cn.numeron.reinforcer

open class Reinforcer {

var outputPath: String? = null
/** 360加固保的账号 */
var username: String? = null

/** 360加固保的密码 */
var password: String? = null

/** 签名配置名称 */
var signConfigName: String? = null

/** 加固后apk的输出目录 */
var outputDirectory: String? = null

/** 360加固保的安装路径 */
var installationPath: String? = null

/** 加固后安装包的重命名映射 */
val renameMap = mutableMapOf<String, String>()

fun rename(vararg entries: Pair<String, String>) {
Expand All @@ -14,4 +26,14 @@ open class Reinforcer {
}
}

fun rename(vararg keyOrValues: String) {
keyOrValues.forEachIndexed { index, keyOrValue ->
if (index % 2 == 0) {
if (index < keyOrValues.lastIndex) {
renameMap[keyOrValue] = keyOrValues[index + 1]
}
}
}
}

}
169 changes: 101 additions & 68 deletions plugin/src/main/java/cn/numeron/reinforcer/ReinforcerPlugin.kt
Original file line number Diff line number Diff line change
@@ -1,100 +1,133 @@
package cn.numeron.reinforcer

import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.getByType
import java.io.File
import java.util.concurrent.CountDownLatch

class ReinforcerPlugin : Plugin<Project> {

override fun apply(project: Project) {
project.extensions.create("reinforcer", Reinforcer::class.java)
project.extensions.create<Reinforcer>("reinforcer")
project.tasks.whenTaskAdded {
if (name.startsWith("assemble") && name.endsWith("Release")) {
dependsOn(":clean")
doLast {
reinforce(project)
reinforce(name, project)
}
}
}
}

private fun reinforce(project: Project) {
//从运行时参数中获取指定的输出目录
val outputPathForRuntime = project.getProperty("outputPath")

//从运行时参数中获取指定的加固工具安装路径
val installationPathForRuntime = project.getProperty("installationPath")

private fun reinforce(taskName: String, project: Project) {
val reinforcer = project.extensions.getByType<Reinforcer>()
val renameMap = reinforcer.renameMap
val outputPath = outputPathForRuntime ?: reinforcer.outputPath
?.takeIf {
it.isNotEmpty()
}
?: throw NullPointerException("The output directory could not be found.")

val installationPath = installationPathForRuntime ?: reinforcer.installationPath
?.takeIf {
it.isNotEmpty()
}
?: throw NullPointerException("The installation path of the reinforcement tool could not be found.")
val installationPath = reinforcer.installationPath
?: throw NullPointerException("The installation path of the reinforcement tool could not be found.")

val outputPath = reinforcer.outputDirectory
?: throw NullPointerException("The output directory could not be found.")

val username = reinforcer.username
val password = reinforcer.password

//登录
if (!username.isNullOrEmpty() && !password.isNullOrEmpty()) {
project.exec {
executable("java")
args("-jar", installationPath, "-login", username, password)
}.rethrowFailure()
}

project.logger.quiet("outputPath = [$outputPath], installationPath = [$installationPath], renameMap = [$renameMap]")
val appExtension = project.extensions.getByType<BaseAppModuleExtension>()

//导入签名信息
val signConfigName = reinforcer.signConfigName

val buildType = appExtension.buildTypes["release"]
var signingConfig = buildType.signingConfig

if (signingConfig == null && !signConfigName.isNullOrEmpty()) {
//如果编译类别中没有签名配置,则通过指定的名称查找
signingConfig = appExtension.signingConfigs.findByName(signConfigName)
}

if (signingConfig != null) {
val storePassword = signingConfig.storePassword
val keyPassword = signingConfig.keyPassword
val storeFile = signingConfig.storeFile
val keyAlias = signingConfig.keyAlias

//设置签名信息
project.exec {
executable("java")
args("-jar", installationPath, "-importsign", storeFile, storePassword, keyAlias, keyPassword)
}.rethrowFailure()
}

//获取打包后apk的输出路径
val variantName = toVariantName(taskName.removePrefix("assemble"))
val variantOutput = appExtension.buildOutputs.findByName(variantName)
if (variantOutput == null) {
project.logger.quiet("variant $variantName not found. reinforce termination.")
return
}
val outputFile = variantOutput.outputFile

//创建保存APK的文件夹
val outputDir = File(outputPath)
if (!outputDir.exists()) {
outputDir.mkdirs()
val outputDirectory = File(outputPath)
if (!outputDirectory.exists()) {
outputDirectory.mkdirs()
}
val existFiles = outputDir.listFiles()?.map(File::getName) ?: emptyList()
//获取CMD运行环境
val runtime = Runtime.getRuntime()

//获取输出目录下所有的发布版的apk文件
File(project.buildDir, "outputs/apk")
.listFiles()
?.mapNotNull {
//从release文件夹下找到最后修改的apk文件
File(it, "release")
.takeIf(File::exists)
?.listFiles { _, name ->
name.endsWith(".apk")
}
?.maxBy(File::lastModified)
}?.let { apkFiles ->
val countDownLatch = CountDownLatch(apkFiles.size)
apkFiles.forEach { apkFile ->
Thread {
//加固
val command = "java -jar $installationPath -jiagu $apkFile $outputDir -autosign -automulpkg"
val process = runtime.exec(command)
process.inputStream.bufferedReader().lines().forEach {
project.logger.quiet("reinforcing: $it")
if (it.contains("error")) {
project.logger.quiet("reinforcing: 加固失败,详情请查看相关日志。")
process.destroy()
}
}
process.waitFor()
countDownLatch.countDown()
}.start()
}
countDownLatch.await()
}
//重命名加固后的文件
outputDir.listFiles { _, name ->
//获取已存在的apk文件列表
val existFiles = outputDirectory.list { _, name ->
name.endsWith(".apk")
} ?: emptyArray()

//执行打包脚本
project.exec {
executable("java")
args("-jar", installationPath, "-jiagu", outputFile, outputDirectory, "-autosign", "-automulpkg")
}.rethrowFailure()

//获取新加固的文件
val reinforcedApkFile = outputDirectory.listFiles { _, name ->
name.endsWith(".apk") && name !in existFiles
}?.forEach { file ->
project.logger.quiet("target file: $file")
val outputFileName = file.name.substringBefore('_').let {
}?.firstOrNull()

//重命名加固后的文件
if (reinforcedApkFile != null) {
project.logger.quiet("target file: $reinforcedApkFile")
val outputFileName = reinforcedApkFile.name.substringBefore('_').let {
renameMap[it] ?: it
} + ".apk"
val outputFile = File(outputDir, outputFileName)
file.copyTo(outputFile, true)
project.logger.quiet("renamed file: $outputFile")
file.delete()
val outputApkFile = File(outputDirectory, outputFileName)
reinforcedApkFile.copyTo(outputApkFile, true)
project.logger.quiet("renamed file: $outputApkFile")
reinforcedApkFile.delete()
}

}

/** 从任务名称中取出变体名称 */
private fun toVariantName(taskName: String): String {
val stringBuilder = StringBuilder()
taskName.forEach {
if (it.isUpperCase()) {
if (stringBuilder.isNotEmpty()) {
stringBuilder.append("-")
}
stringBuilder.append(it.toLowerCase())
} else {
stringBuilder.append(it)
}
}
return stringBuilder.toString()
}


}

0 comments on commit 5b495f8

Please sign in to comment.