400 lines
15 KiB
Kotlin
Raw Normal View History

2023-03-02 21:16:25 +08:00
import com.android.build.api.artifact.ArtifactTransformationRequest
import com.android.build.api.artifact.SingleArtifact
import com.android.build.api.dsl.ApkSigningConfig
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
2021-09-08 00:45:15 +08:00
import com.android.build.gradle.BaseExtension
2021-09-09 20:19:49 -07:00
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
2022-06-18 02:08:44 +08:00
import com.android.builder.internal.packaging.IncrementalPackager
import com.android.tools.build.apkzlib.sign.SigningExtension
import com.android.tools.build.apkzlib.sign.SigningOptions
import com.android.tools.build.apkzlib.zfile.ZFiles
import com.android.tools.build.apkzlib.zip.ZFileOptions
2021-09-09 20:19:49 -07:00
import org.apache.tools.ant.filters.FixCrLfFilter
2021-09-08 00:45:15 +08:00
import org.gradle.api.Action
2023-03-02 21:16:25 +08:00
import org.gradle.api.DefaultTask
2021-09-08 00:45:15 +08:00
import org.gradle.api.JavaVersion
import org.gradle.api.Project
2023-03-02 21:16:25 +08:00
import org.gradle.api.file.DirectoryProperty
2022-06-03 01:13:29 -07:00
import org.gradle.api.plugins.ExtensionAware
2023-03-02 21:16:25 +08:00
import org.gradle.api.provider.Property
2023-03-02 20:32:13 -08:00
import org.gradle.api.tasks.Delete
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.StopExecutionException
import org.gradle.api.tasks.Sync
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.filter
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.getValue
import org.gradle.kotlin.dsl.named
import org.gradle.kotlin.dsl.provideDelegate
import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.registering
2023-02-20 01:03:35 -08:00
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
2022-05-27 00:44:20 -07:00
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
import java.io.ByteArrayOutputStream
import java.io.File
2022-06-18 02:08:44 +08:00
import java.security.KeyStore
import java.security.cert.X509Certificate
2022-06-20 02:51:58 +08:00
import java.util.jar.JarFile
2023-03-02 20:32:13 -08:00
import java.util.zip.Deflater
import java.util.zip.DeflaterOutputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import java.util.zip.ZipOutputStream
2021-12-14 21:30:15 +08:00
private fun Project.androidBase(configure: Action<BaseExtension>) =
extensions.configure("android", configure)
2021-09-09 20:19:49 -07:00
2021-12-14 21:30:15 +08:00
private fun Project.android(configure: Action<BaseAppModuleExtension>) =
2021-09-09 20:19:49 -07:00
extensions.configure("android", configure)
2021-09-08 00:45:15 +08:00
2022-06-03 01:13:29 -07:00
private fun BaseExtension.kotlinOptions(configure: Action<KotlinJvmOptions>) =
(this as ExtensionAware).extensions.findByName("kotlinOptions")?.let {
2022-05-27 00:44:20 -07:00
configure.execute(it as KotlinJvmOptions)
}
2023-02-20 01:03:35 -08:00
private fun BaseExtension.kotlin(configure: Action<KotlinAndroidProjectExtension>) =
(this as ExtensionAware).extensions.findByName("kotlin")?.let {
configure.execute(it as KotlinAndroidProjectExtension)
}
2021-12-14 21:30:15 +08:00
private val Project.android: BaseAppModuleExtension
2022-10-31 22:31:15 +08:00
get() = extensions["android"] as BaseAppModuleExtension
2021-09-08 00:45:15 +08:00
2023-03-02 21:16:25 +08:00
private val Project.androidComponents
get() = extensions.getByType(ApplicationAndroidComponentsExtension::class.java)
2021-09-08 00:45:15 +08:00
fun Project.setupCommon() {
2021-12-14 21:30:15 +08:00
androidBase {
compileSdkVersion(33)
2022-12-26 02:02:21 -08:00
buildToolsVersion = "33.0.1"
2022-01-27 01:46:00 -08:00
ndkPath = "$sdkDirectory/ndk/magisk"
2021-09-08 00:45:15 +08:00
defaultConfig {
2023-03-17 04:24:16 -07:00
minSdk = 23
targetSdk = 33
2021-09-08 00:45:15 +08:00
}
compileOptions {
2023-02-20 14:55:27 +08:00
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
2021-09-08 00:45:15 +08:00
}
2022-06-03 01:13:29 -07:00
kotlinOptions {
2023-02-20 14:55:27 +08:00
jvmTarget = "17"
2022-06-03 01:13:29 -07:00
}
2023-02-20 01:03:35 -08:00
kotlin {
jvmToolchain(17)
}
2022-05-27 00:44:20 -07:00
}
2021-09-08 00:45:15 +08:00
}
2023-03-02 21:16:25 +08:00
private fun ApkSigningConfig.getPrivateKey(): KeyStore.PrivateKeyEntry {
2022-06-18 02:08:44 +08:00
val keyStore = KeyStore.getInstance(storeType ?: KeyStore.getDefaultType())
storeFile!!.inputStream().use {
keyStore.load(it, storePassword!!.toCharArray())
}
val keyPwdArray = keyPassword!!.toCharArray()
val entry = keyStore.getEntry(keyAlias!!, KeyStore.PasswordProtection(keyPwdArray))
return entry as KeyStore.PrivateKeyEntry
}
2023-03-02 21:16:25 +08:00
abstract class AddCommentTask: DefaultTask() {
@get:Input
abstract val comment: Property<String>
@get:Input
abstract val signingConfig: Property<ApkSigningConfig>
@get:InputFiles
abstract val apkFolder: DirectoryProperty
@get:OutputDirectory
abstract val outFolder: DirectoryProperty
@get:Internal
abstract val transformationRequest: Property<ArtifactTransformationRequest<AddCommentTask>>
@TaskAction
fun taskAction() = transformationRequest.get().submit(this) { artifact ->
val inFile = File(artifact.outputFile)
val outFile = outFolder.file(inFile.name).get().asFile
2023-03-02 20:32:13 -08:00
val privateKey = signingConfig.get().getPrivateKey()
val signingOptions = SigningOptions.builder()
.setMinSdkVersion(0)
.setV1SigningEnabled(true)
.setV2SigningEnabled(true)
.setKey(privateKey.privateKey)
.setCertificates(privateKey.certificate as X509Certificate)
.setValidation(SigningOptions.Validation.ASSUME_INVALID)
.build()
val options = ZFileOptions().apply {
noTimestamps = true
autoSortFiles = true
}
outFile.parentFile.mkdirs()
inFile.copyTo(outFile, overwrite = true)
ZFiles.apk(outFile, options).use {
SigningExtension(signingOptions).register(it)
it.eocdComment = comment.get().toByteArray()
it.get(IncrementalPackager.APP_METADATA_ENTRY_PATH)?.delete()
it.get(JarFile.MANIFEST_NAME)?.delete()
}
2023-03-02 21:16:25 +08:00
outFile
}
}
2021-09-09 20:19:49 -07:00
private fun Project.setupAppCommon() {
2021-09-08 00:45:15 +08:00
setupCommon()
2021-09-09 20:19:49 -07:00
2021-09-08 00:45:15 +08:00
android {
signingConfigs {
create("config") {
Config["keyStore"]?.also {
storeFile = rootProject.file(it)
storePassword = Config["keyStorePass"]
keyAlias = Config["keyAlias"]
keyPassword = Config["keyPass"]
}
}
}
buildTypes {
2022-10-31 22:31:15 +08:00
signingConfigs["config"].also {
debug {
2021-09-08 00:45:15 +08:00
signingConfig = if (it.storeFile?.exists() == true) it
2022-10-31 22:31:15 +08:00
else signingConfigs["debug"]
2021-09-08 00:45:15 +08:00
}
2022-10-31 22:31:15 +08:00
release {
2021-09-08 00:45:15 +08:00
signingConfig = if (it.storeFile?.exists() == true) it
2022-10-31 22:31:15 +08:00
else signingConfigs["debug"]
2021-09-08 00:45:15 +08:00
}
}
}
2021-12-14 21:30:15 +08:00
lint {
2021-09-08 00:45:15 +08:00
disable += "MissingTranslation"
2023-02-20 01:23:56 -08:00
checkReleaseBuilds = false
2021-09-08 00:45:15 +08:00
}
2021-12-14 21:30:15 +08:00
dependenciesInfo {
includeInApk = false
}
2023-02-20 01:03:35 -08:00
buildFeatures {
buildConfig = true
}
2021-09-08 00:45:15 +08:00
}
2022-06-18 02:08:44 +08:00
2023-03-02 21:16:25 +08:00
androidComponents.onVariants { variant ->
val commentTask = tasks.register(
"comment${variant.name.replaceFirstChar { it.uppercase() }}",
AddCommentTask::class.java
)
val transformationRequest = variant.artifacts.use(commentTask)
.wiredWithDirectories(AddCommentTask::apkFolder, AddCommentTask::outFolder)
.toTransformMany(SingleArtifact.APK)
val signingConfig = android.buildTypes.getByName(variant.buildType!!).signingConfig
commentTask.configure {
this.transformationRequest.set(transformationRequest)
this.signingConfig.set(signingConfig)
this.comment.set("version=${Config.version}\n" +
2023-02-12 17:40:28 +08:00
"versionCode=${Config.versionCode}\n" +
2023-03-02 21:16:25 +08:00
"stubVersion=${Config.stubVersion}\n")
this.outFolder.set(File(buildDir, "outputs/apk/${variant.name}"))
2022-06-18 02:08:44 +08:00
}
}
2021-09-08 00:45:15 +08:00
}
2021-09-09 20:19:49 -07:00
fun Project.setupApp() {
setupAppCommon()
2022-10-31 22:31:15 +08:00
val syncLibs by tasks.registering(Sync::class) {
2021-09-09 20:19:49 -07:00
into("src/main/jniLibs")
into("armeabi-v7a") {
from(rootProject.file("native/out/armeabi-v7a")) {
2022-03-17 03:15:39 -07:00
include("busybox", "magiskboot", "magiskinit", "magiskpolicy", "magisk")
2021-09-09 20:19:49 -07:00
rename { if (it == "magisk") "libmagisk32.so" else "lib$it.so" }
}
}
into("x86") {
from(rootProject.file("native/out/x86")) {
2022-03-17 03:15:39 -07:00
include("busybox", "magiskboot", "magiskinit", "magiskpolicy", "magisk")
2021-09-09 20:19:49 -07:00
rename { if (it == "magisk") "libmagisk32.so" else "lib$it.so" }
}
}
into("arm64-v8a") {
from(rootProject.file("native/out/arm64-v8a")) {
2022-03-17 03:15:39 -07:00
include("busybox", "magiskboot", "magiskinit", "magiskpolicy", "magisk")
2021-09-09 20:19:49 -07:00
rename { if (it == "magisk") "libmagisk64.so" else "lib$it.so" }
}
}
into("x86_64") {
from(rootProject.file("native/out/x86_64")) {
2022-03-17 03:15:39 -07:00
include("busybox", "magiskboot", "magiskinit", "magiskpolicy", "magisk")
2021-09-09 20:19:49 -07:00
rename { if (it == "magisk") "libmagisk64.so" else "lib$it.so" }
}
}
onlyIf {
2022-03-17 03:15:39 -07:00
if (inputs.sourceFiles.files.size != 20)
2021-09-09 20:19:49 -07:00
throw StopExecutionException("Please build binaries first! (./build.py binary)")
true
}
}
2022-10-31 22:31:15 +08:00
val syncResources by tasks.registering(Sync::class) {
2021-09-09 20:19:49 -07:00
into("src/main/resources/META-INF/com/google/android")
from(rootProject.file("scripts/update_binary.sh")) {
rename { "update-binary" }
}
from(rootProject.file("scripts/flash_script.sh")) {
rename { "updater-script" }
}
}
android.applicationVariants.all {
2023-02-20 14:55:27 +08:00
val variantCapped = name.replaceFirstChar { it.uppercase() }
2022-12-26 15:23:06 -08:00
2023-02-20 01:23:56 -08:00
tasks.getByPath("merge${variantCapped}JniLibFolders").dependsOn(syncLibs)
processJavaResourcesProvider.configure { dependsOn(syncResources) }
2023-03-02 21:27:48 -08:00
val stubTask = tasks.getByPath(":stub:comment$variantCapped")
2022-12-26 15:23:06 -08:00
val stubApk = stubTask.outputs.files.asFileTree.filter {
it.name.endsWith(".apk")
}
2022-08-26 03:43:31 -07:00
2022-10-31 22:31:15 +08:00
val syncAssets = tasks.register("sync${variantCapped}Assets", Sync::class) {
2023-02-20 01:23:56 -08:00
dependsOn(stubTask)
2022-10-31 22:31:15 +08:00
inputs.property("version", Config.version)
inputs.property("versionCode", Config.versionCode)
2023-02-27 11:57:22 +08:00
into("src/${this@all.name}/assets")
2022-10-31 22:31:15 +08:00
from(rootProject.file("scripts")) {
include("util_functions.sh", "boot_patch.sh", "addon.d.sh")
include("uninstaller.sh", "module_installer.sh")
}
from(rootProject.file("tools/bootctl"))
into("chromeos") {
from(rootProject.file("tools/futility"))
from(rootProject.file("tools/keys")) {
include("kernel_data_key.vbprivk", "kernel.keyblock")
}
}
2022-12-26 15:23:06 -08:00
from(stubApk) {
2022-08-26 03:43:31 -07:00
rename { "stub.apk" }
}
2022-10-31 22:31:15 +08:00
filesMatching("**/util_functions.sh") {
filter {
it.replace(
"#MAGISK_VERSION_STUB",
"MAGISK_VER='${Config.version}'\nMAGISK_VER_CODE=${Config.versionCode}"
)
}
filter<FixCrLfFilter>("eol" to FixCrLfFilter.CrLf.newInstance("lf"))
2022-08-26 03:43:31 -07:00
}
}
2023-02-20 01:23:56 -08:00
mergeAssetsProvider.configure { dependsOn(syncAssets) }
2021-12-14 21:30:15 +08:00
2021-09-09 20:19:49 -07:00
val keysDir = rootProject.file("tools/keys")
val outSrcDir = File(buildDir, "generated/source/keydata/$name")
val outSrc = File(outSrcDir, "com/topjohnwu/magisk/signing/KeyData.java")
2022-08-26 03:43:31 -07:00
val genSrcTask = tasks.register("generate${variantCapped}KeyData") {
2021-09-09 20:19:49 -07:00
inputs.dir(keysDir)
outputs.file(outSrc)
doLast {
genKeyData(keysDir, outSrc)
}
}
registerJavaGeneratingTask(genSrcTask, outSrcDir)
}
}
fun Project.setupStub() {
setupAppCommon()
2023-03-02 21:16:25 +08:00
androidComponents.onVariants { variant ->
2023-03-02 20:32:13 -08:00
val variantName = variant.name
val variantCapped = variantName.replaceFirstChar { it.uppercase() }
2023-03-02 21:16:25 +08:00
val manifestUpdater =
2023-03-02 20:32:13 -08:00
project.tasks.register("${variantName}ManifestProducer", ManifestUpdater::class.java) {
dependsOn("generate${variantCapped}ObfuscatedClass")
applicationId.set(variant.applicationId)
appClassDir.set(File(buildDir, "generated/source/app/$variantName"))
factoryClassDir.set(File(buildDir, "generated/source/factory/$variantName"))
2023-03-02 21:16:25 +08:00
}
variant.artifacts.use(manifestUpdater)
.wiredWithFiles(
ManifestUpdater::mergedManifest,
ManifestUpdater::outputManifest)
.toTransform(SingleArtifact.MERGED_MANIFEST)
}
2021-09-09 20:19:49 -07:00
android.applicationVariants.all {
2023-02-20 14:55:27 +08:00
val variantCapped = name.replaceFirstChar { it.uppercase() }
val variantLowered = name.lowercase()
2023-03-02 21:16:25 +08:00
val outFactoryClassDir = File(buildDir, "generated/source/factory/${variantLowered}")
val outAppClassDir = File(buildDir, "generated/source/app/${variantLowered}")
2023-02-20 01:23:56 -08:00
val outResDir = File(buildDir, "generated/source/res/${variantLowered}")
2021-12-14 21:30:15 +08:00
val aapt = File(android.sdkDirectory, "build-tools/${android.buildToolsVersion}/aapt2")
val apk = File(buildDir, "intermediates/processed_res/" +
"${variantLowered}/out/resources-${variantLowered}.ap_")
2021-09-09 20:19:49 -07:00
2023-03-02 21:16:25 +08:00
val genManifestTask = tasks.register("generate${variantCapped}ObfuscatedClass") {
2023-02-20 01:23:56 -08:00
inputs.property("seed", RAND_SEED)
2023-03-02 21:16:25 +08:00
outputs.dirs(outFactoryClassDir, outAppClassDir)
2021-09-09 20:19:49 -07:00
doLast {
2023-03-02 21:16:25 +08:00
outFactoryClassDir.mkdirs()
outAppClassDir.mkdirs()
2023-03-02 20:32:13 -08:00
genStubClasses(outFactoryClassDir, outAppClassDir)
2021-12-14 21:30:15 +08:00
}
}
2023-03-02 21:16:25 +08:00
registerJavaGeneratingTask(genManifestTask, outFactoryClassDir, outAppClassDir)
2021-09-09 20:19:49 -07:00
2023-03-02 20:32:13 -08:00
val processResourcesTask = tasks.named("process${variantCapped}Resources") {
2023-03-03 15:50:25 +08:00
outputs.dir(outResDir)
2023-03-02 20:32:13 -08:00
doLast {
2023-03-03 15:50:25 +08:00
val apkTmp = File("${apk}.tmp")
2023-03-02 20:32:13 -08:00
exec {
commandLine(aapt, "optimize", "-o", apkTmp, "--collapse-resource-names", apk)
2023-02-20 01:23:56 -08:00
}
2023-03-02 20:32:13 -08:00
val bos = ByteArrayOutputStream()
ZipFile(apkTmp).use { src ->
ZipOutputStream(apk.outputStream()).use {
it.setLevel(Deflater.BEST_COMPRESSION)
it.putNextEntry(ZipEntry("AndroidManifest.xml"))
src.getInputStream(src.getEntry("AndroidManifest.xml")).transferTo(it)
it.closeEntry()
}
DeflaterOutputStream(bos, Deflater(Deflater.BEST_COMPRESSION)).use {
src.getInputStream(src.getEntry("resources.arsc")).transferTo(it)
}
2021-09-09 20:19:49 -07:00
}
2023-03-02 20:32:13 -08:00
apkTmp.delete()
genEncryptedResources(bos.toByteArray(), outResDir)
2021-09-09 20:19:49 -07:00
}
}
2023-03-02 20:32:13 -08:00
2023-02-20 01:23:56 -08:00
registerJavaGeneratingTask(processResourcesTask, outResDir)
2021-09-09 20:19:49 -07:00
}
2021-12-14 21:30:15 +08:00
// Override optimizeReleaseResources task
2023-02-20 01:23:56 -08:00
val apk = File(buildDir, "intermediates/processed_res/" +
"release/out/resources-release.ap_")
val optRes = File(buildDir, "intermediates/optimized_processed_res/" +
"release/resources-release-optimize.ap_")
2023-03-31 11:07:17 +08:00
afterEvaluate {
tasks.named("optimizeReleaseResources") {
2021-12-14 21:30:15 +08:00
doLast { apk.copyTo(optRes, true) }
}
}
2022-01-09 02:22:34 +08:00
tasks.named<Delete>("clean") {
delete.addAll(listOf("src/debug/AndroidManifest.xml", "src/release/AndroidManifest.xml"))
}
2021-09-09 20:19:49 -07:00
}