mirror of
https://github.com/topjohnwu/Magisk.git
synced 2026-01-20 00:21:39 -08:00
Update to AGP 9.0
This commit is contained in:
2
app/.gitignore
vendored
2
app/.gitignore
vendored
@@ -3,5 +3,5 @@
|
||||
# Gradle
|
||||
.gradle
|
||||
.kotlin
|
||||
build
|
||||
/local.properties
|
||||
/build
|
||||
|
||||
1
app/apk/.gitignore
vendored
1
app/apk/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
/build
|
||||
@@ -1,8 +1,7 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
kotlin("android")
|
||||
kotlin("plugin.parcelize")
|
||||
kotlin("kapt")
|
||||
id("com.android.legacy-kapt")
|
||||
id("androidx.navigation.safeargs.kotlin")
|
||||
}
|
||||
|
||||
@@ -26,6 +25,10 @@ android {
|
||||
isCoreLibraryDesugaringEnabled = true
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
proguardFile("proguard-rules.pro")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
|
||||
3
app/apk/proguard-rules.pro
vendored
Normal file
3
app/apk/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Excessive obfuscation
|
||||
-flattenpackagehierarchy
|
||||
-allowaccessmodification
|
||||
1
app/buildSrc/.gitignore
vendored
1
app/buildSrc/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
/build
|
||||
@@ -1,5 +1,3 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
|
||||
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
}
|
||||
@@ -21,6 +19,7 @@ gradlePlugin {
|
||||
dependencies {
|
||||
implementation(kotlin("gradle-plugin", libs.versions.kotlin.get()))
|
||||
implementation(libs.android.gradle.plugin)
|
||||
implementation(libs.android.kapt.plugin)
|
||||
implementation(libs.ksp.plugin)
|
||||
implementation(libs.navigation.safe.args.plugin)
|
||||
implementation(libs.lsparanoid.plugin)
|
||||
|
||||
@@ -1,72 +1,68 @@
|
||||
import com.android.build.api.artifact.SingleArtifact
|
||||
import com.android.build.api.dsl.ApplicationExtension
|
||||
import com.android.build.api.dsl.CommonExtension
|
||||
import com.android.build.api.instrumentation.FramesComputationMode.COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS
|
||||
import com.android.build.api.instrumentation.InstrumentationScope
|
||||
import com.android.build.api.variant.AndroidComponentsExtension
|
||||
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
|
||||
import com.android.build.gradle.BaseExtension
|
||||
import com.android.build.gradle.LibraryExtension
|
||||
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
|
||||
import org.apache.tools.ant.filters.FixCrLfFilter
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.JavaVersion
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.Copy
|
||||
import org.gradle.api.tasks.Delete
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.StopExecutionException
|
||||
import org.gradle.api.tasks.Sync
|
||||
import org.gradle.kotlin.dsl.assign
|
||||
import org.gradle.kotlin.dsl.exclude
|
||||
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.withType
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import java.security.MessageDigest
|
||||
import java.util.HexFormat
|
||||
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
|
||||
|
||||
private fun Project.androidBase(configure: Action<BaseExtension>) =
|
||||
private fun Project.android(configure: Action<CommonExtension>) =
|
||||
extensions.configure("android", configure)
|
||||
|
||||
private fun Project.android(configure: Action<BaseAppModuleExtension>) =
|
||||
private fun Project.androidApp(configure: Action<ApplicationExtension>) =
|
||||
extensions.configure("android", configure)
|
||||
|
||||
internal val Project.androidApp: BaseAppModuleExtension
|
||||
get() = extensions["android"] as BaseAppModuleExtension
|
||||
internal val Project.androidApp: ApplicationExtension
|
||||
get() = extensions["android"] as ApplicationExtension
|
||||
|
||||
private val Project.androidLib: LibraryExtension
|
||||
get() = extensions["android"] as LibraryExtension
|
||||
private fun Project.androidComponents(configure: Action<AndroidComponentsExtension<*, *, *>>) =
|
||||
extensions.configure(AndroidComponentsExtension::class.java, configure)
|
||||
|
||||
internal val Project.androidComponents
|
||||
get() = extensions.getByType(ApplicationAndroidComponentsExtension::class.java)
|
||||
private val Project.androidComponents: AndroidComponentsExtension<*, *, *>
|
||||
get() = extensions["androidComponents"] as AndroidComponentsExtension<*, *, *>
|
||||
|
||||
internal fun Project.androidAppComponents(configure: Action<ApplicationAndroidComponentsExtension>) =
|
||||
extensions.configure(ApplicationAndroidComponentsExtension::class.java, configure)
|
||||
|
||||
fun Project.setupCommon() {
|
||||
androidBase {
|
||||
compileSdkVersion(36)
|
||||
android {
|
||||
compileSdk {
|
||||
version = release(36)
|
||||
}
|
||||
buildToolsVersion = "36.0.0"
|
||||
ndkPath = "$sdkDirectory/ndk/magisk"
|
||||
ndkPath = "${androidComponents.sdkComponents.sdkDirectory.get().asFile}/ndk/magisk"
|
||||
ndkVersion = "29.0.14206865"
|
||||
|
||||
defaultConfig {
|
||||
defaultConfig.apply {
|
||||
minSdk = 23
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
compileOptions.apply {
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
packaging.apply {
|
||||
resources {
|
||||
excludes += arrayOf(
|
||||
"/META-INF/*",
|
||||
@@ -123,93 +119,108 @@ const val BUSYBOX_DOWNLOAD_URL =
|
||||
const val BUSYBOX_ZIP_CHECKSUM =
|
||||
"b4d0551feabaf314e53c79316c980e8f66432e9fb91a69dbbf10a93564b40951"
|
||||
|
||||
private abstract class SyncWithDir : Sync() {
|
||||
@get:OutputDirectory
|
||||
abstract val outputFolder: DirectoryProperty
|
||||
}
|
||||
|
||||
fun Project.setupCoreLib() {
|
||||
setupCommon()
|
||||
|
||||
androidLib.libraryVariants.all {
|
||||
val variant = name
|
||||
val variantCapped = name.replaceFirstChar { it.uppercase() }
|
||||
val abiList = Config.abiList
|
||||
val abiList = Config.abiList
|
||||
|
||||
val syncLibs = tasks.register("sync${variantCapped}JniLibs", Sync::class) {
|
||||
into("src/$variant/jniLibs")
|
||||
for (abi in abiList) {
|
||||
into(abi) {
|
||||
from(rootFile("native/out/$abi")) {
|
||||
include("magiskboot", "magiskinit", "magiskpolicy", "magisk", "libinit-ld.so")
|
||||
rename { if (it.endsWith(".so")) it else "lib$it.so" }
|
||||
androidComponents {
|
||||
onVariants { variant ->
|
||||
val variantName = variant.name
|
||||
val variantCapped = variantName.replaceFirstChar { it.uppercase() }
|
||||
|
||||
val syncLibs = tasks.register("sync${variantCapped}JniLibs", SyncWithDir::class) {
|
||||
outputFolder.set(layout.buildDirectory.dir("$variantName/jniLibs"))
|
||||
into(outputFolder)
|
||||
|
||||
for (abi in abiList) {
|
||||
into(abi) {
|
||||
from(rootFile("native/out/$abi")) {
|
||||
include("magiskboot", "magiskinit", "magiskpolicy", "magisk", "libinit-ld.so")
|
||||
rename { if (it.endsWith(".so")) it else "lib$it.so" }
|
||||
}
|
||||
}
|
||||
}
|
||||
from(zipTree(downloadFile(BUSYBOX_DOWNLOAD_URL, BUSYBOX_ZIP_CHECKSUM)))
|
||||
include(abiList.map { "$it/libbusybox.so" })
|
||||
onlyIf {
|
||||
if (inputs.sourceFiles.files.size != abiList.size * 6)
|
||||
throw StopExecutionException("Please build binaries first! (./build.py binary)")
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
variant.sources.jniLibs?.let {
|
||||
it.addGeneratedSourceDirectory(syncLibs, SyncWithDir::outputFolder)
|
||||
}
|
||||
|
||||
val syncResources = tasks.register("sync${variantCapped}Resources", SyncWithDir::class) {
|
||||
outputFolder.set(layout.buildDirectory.dir("$variantName/resources"))
|
||||
into(outputFolder)
|
||||
|
||||
into("META-INF/com/google/android") {
|
||||
from(rootFile("scripts/update_binary.sh")) {
|
||||
rename { "update-binary" }
|
||||
}
|
||||
from(rootFile("scripts/flash_script.sh")) {
|
||||
rename { "updater-script" }
|
||||
}
|
||||
}
|
||||
}
|
||||
from(zipTree(downloadFile(BUSYBOX_DOWNLOAD_URL, BUSYBOX_ZIP_CHECKSUM)))
|
||||
include(abiList.map { "$it/libbusybox.so" })
|
||||
onlyIf {
|
||||
if (inputs.sourceFiles.files.size != abiList.size * 6)
|
||||
throw StopExecutionException("Please build binaries first! (./build.py binary)")
|
||||
true
|
||||
|
||||
variant.sources.resources?.let {
|
||||
it.addGeneratedSourceDirectory(syncResources, SyncWithDir::outputFolder)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.getByPath("merge${variantCapped}JniLibFolders").dependsOn(syncLibs)
|
||||
val stubTask = tasks.getByPath(":stub:comment$variantCapped")
|
||||
val syncAssets = tasks.register("sync${variantCapped}Assets", SyncWithDir::class) {
|
||||
outputFolder.set(layout.buildDirectory.dir("$variantName/assets"))
|
||||
into(outputFolder)
|
||||
|
||||
val syncResources = tasks.register("sync${variantCapped}Resources", Sync::class) {
|
||||
into("src/$variant/resources/META-INF/com/google/android")
|
||||
from(rootFile("scripts/update_binary.sh")) {
|
||||
rename { "update-binary" }
|
||||
}
|
||||
from(rootFile("scripts/flash_script.sh")) {
|
||||
rename { "updater-script" }
|
||||
}
|
||||
}
|
||||
|
||||
processJavaResourcesProvider.configure { dependsOn(syncResources) }
|
||||
|
||||
val stubTask = tasks.getByPath(":stub:comment$variantCapped")
|
||||
val stubApk = stubTask.outputs.files.asFileTree.filter {
|
||||
it.name.endsWith(".apk")
|
||||
}
|
||||
|
||||
val syncAssets = tasks.register("sync${variantCapped}Assets", Sync::class) {
|
||||
dependsOn(stubTask)
|
||||
inputs.property("version", Config.version)
|
||||
inputs.property("versionCode", Config.versionCode)
|
||||
into("src/$variant/assets")
|
||||
from(rootFile("scripts")) {
|
||||
include("util_functions.sh", "boot_patch.sh", "addon.d.sh",
|
||||
"app_functions.sh", "uninstaller.sh", "module_installer.sh")
|
||||
}
|
||||
from(rootFile("tools/bootctl"))
|
||||
into("chromeos") {
|
||||
from(rootFile("tools/futility"))
|
||||
from(rootFile("tools/keys")) {
|
||||
include("kernel_data_key.vbprivk", "kernel.keyblock")
|
||||
inputs.property("version", Config.version)
|
||||
inputs.property("versionCode", Config.versionCode)
|
||||
from(rootFile("scripts")) {
|
||||
include("util_functions.sh", "boot_patch.sh", "addon.d.sh",
|
||||
"app_functions.sh", "uninstaller.sh", "module_installer.sh")
|
||||
}
|
||||
from(rootFile("tools/bootctl"))
|
||||
into("chromeos") {
|
||||
from(rootFile("tools/futility"))
|
||||
from(rootFile("tools/keys")) {
|
||||
include("kernel_data_key.vbprivk", "kernel.keyblock")
|
||||
}
|
||||
}
|
||||
from(stubTask) {
|
||||
include { it.name.endsWith(".apk") }
|
||||
rename { "stub.apk" }
|
||||
}
|
||||
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"))
|
||||
}
|
||||
}
|
||||
from(stubApk) {
|
||||
rename { "stub.apk" }
|
||||
}
|
||||
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"))
|
||||
|
||||
variant.sources.assets?.let {
|
||||
it.addGeneratedSourceDirectory(syncAssets, SyncWithDir::outputFolder)
|
||||
}
|
||||
}
|
||||
mergeAssetsProvider.configure { dependsOn(syncAssets) }
|
||||
}
|
||||
|
||||
tasks.named<Delete>("clean") {
|
||||
delete.addAll(listOf("src/main/jniLibs", "src/main/resources", "src/debug", "src/release"))
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.setupAppCommon() {
|
||||
setupCommon()
|
||||
|
||||
android {
|
||||
androidApp {
|
||||
signingConfigs {
|
||||
Config["keyStore"]?.also {
|
||||
create("config") {
|
||||
@@ -254,22 +265,25 @@ fun Project.setupAppCommon() {
|
||||
}
|
||||
}
|
||||
|
||||
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 = androidApp.buildTypes.getByName(variant.buildType!!).signingConfig
|
||||
commentTask.configure {
|
||||
this.transformationRequest = transformationRequest
|
||||
this.signingConfig = signingConfig
|
||||
this.comment = "version=${Config.version}\n" +
|
||||
"versionCode=${Config.versionCode}\n" +
|
||||
"stubVersion=${Config.stubVersion}\n"
|
||||
this.outFolder.set(layout.buildDirectory.dir("outputs/apk/${variant.name}"))
|
||||
androidAppComponents {
|
||||
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 = androidApp.buildTypes.getByName(variant.buildType!!).signingConfig
|
||||
commentTask.configure {
|
||||
this.transformationRequest = transformationRequest
|
||||
this.signingConfig = signingConfig
|
||||
this.comment = "version=${Config.version}\n" +
|
||||
"versionCode=${Config.versionCode}\n" +
|
||||
"stubVersion=${Config.stubVersion}\n"
|
||||
this.outFolder.set(layout.buildDirectory.dir("outputs/apk/${variant.name}"))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -277,7 +291,7 @@ fun Project.setupAppCommon() {
|
||||
fun Project.setupMainApk() {
|
||||
setupAppCommon()
|
||||
|
||||
android {
|
||||
androidApp {
|
||||
namespace = "com.topjohnwu.magisk"
|
||||
|
||||
defaultConfig {
|
||||
@@ -290,8 +304,10 @@ fun Project.setupMainApk() {
|
||||
debugSymbolLevel = "FULL"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
androidComponents.onVariants { variant ->
|
||||
androidComponents {
|
||||
onVariants { variant ->
|
||||
variant.instrumentation.apply {
|
||||
setAsmFramesComputationMode(COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS)
|
||||
transformClassesWith(
|
||||
@@ -314,17 +330,26 @@ const val SHAMIKO_CHECKSUM =
|
||||
fun Project.setupTestApk() {
|
||||
setupAppCommon()
|
||||
|
||||
androidApp.applicationVariants.all {
|
||||
val variantCapped = name.replaceFirstChar { it.uppercase() }
|
||||
val dlTask by tasks.register("download${variantCapped}Lsposed", Sync::class) {
|
||||
from(downloadFile(LSPOSED_DOWNLOAD_URL, LSPOSED_CHECKSUM)) {
|
||||
rename { "lsposed.zip" }
|
||||
androidComponents {
|
||||
onVariants { variant ->
|
||||
val variantName = variant.name
|
||||
val variantCapped = variantName.replaceFirstChar { it.uppercase() }
|
||||
|
||||
val dlTask = tasks.register("download${variantCapped}Lsposed", SyncWithDir::class) {
|
||||
outputFolder.set(layout.buildDirectory.dir("$variantName/lsposed"))
|
||||
into(outputFolder)
|
||||
|
||||
from(downloadFile(LSPOSED_DOWNLOAD_URL, LSPOSED_CHECKSUM)) {
|
||||
rename { "lsposed.zip" }
|
||||
}
|
||||
from(downloadFile(SHAMIKO_DOWNLOAD_URL, SHAMIKO_CHECKSUM)) {
|
||||
rename { "shamiko.zip" }
|
||||
}
|
||||
}
|
||||
from(downloadFile(SHAMIKO_DOWNLOAD_URL, SHAMIKO_CHECKSUM)) {
|
||||
rename { "shamiko.zip" }
|
||||
|
||||
variant.sources.assets?.let {
|
||||
it.addGeneratedSourceDirectory(dlTask, SyncWithDir::outputFolder)
|
||||
}
|
||||
into("src/${this@all.name}/assets")
|
||||
}
|
||||
mergeAssetsProvider.configure { dependsOn(dlTask) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,14 @@ import org.gradle.api.tasks.CacheableTask
|
||||
import org.gradle.api.tasks.Delete
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.kotlin.dsl.assign
|
||||
import org.gradle.kotlin.dsl.named
|
||||
import org.gradle.kotlin.dsl.register
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
@@ -82,18 +83,16 @@ private abstract class ManifestUpdater: DefaultTask() {
|
||||
@get:Input
|
||||
abstract val applicationId: Property<String>
|
||||
|
||||
@get:Input
|
||||
abstract val factoryClass: Property<String>
|
||||
|
||||
@get:Input
|
||||
abstract val appClass: Property<String>
|
||||
|
||||
@get:InputFile
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
abstract val mergedManifest: RegularFileProperty
|
||||
|
||||
@get:InputFiles
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
abstract val factoryClassDir: DirectoryProperty
|
||||
|
||||
@get:InputFiles
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
abstract val appClassDir: DirectoryProperty
|
||||
|
||||
@get:OutputFile
|
||||
abstract val outputManifest: RegularFileProperty
|
||||
|
||||
@@ -170,25 +169,18 @@ private abstract class ManifestUpdater: DefaultTask() {
|
||||
|
||||
// Shuffle the order of the components
|
||||
cmpList.shuffle(RANDOM)
|
||||
val (factoryPkg, factoryClass) = factoryClassDir.asFileTree.firstNotNullOf {
|
||||
it.parentFile!!.name to it.name.removeSuffix(".java")
|
||||
}
|
||||
val (appPkg, appClass) = appClassDir.asFileTree.firstNotNullOf {
|
||||
it.parentFile!!.name to it.name.removeSuffix(".java")
|
||||
}
|
||||
val components = cmpList.joinToString("\n\n")
|
||||
.replace("\${applicationId}", applicationId.get())
|
||||
val manifest = mergedManifest.asFile.get().readText().replace(Regex(".*\\<application"), """
|
||||
|<application
|
||||
| android:appComponentFactory="$factoryPkg.$factoryClass"
|
||||
| android:name="$appPkg.$appClass"""".ind(1)
|
||||
| android:appComponentFactory="${factoryClass.get()}"
|
||||
| android:name="${appClass.get()}"""".ind(1)
|
||||
).replace(Regex(".*\\<\\/application"), "$components\n </application")
|
||||
outputManifest.get().asFile.writeText(manifest)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun genStubClasses(factoryOutDir: File, appOutDir: File) {
|
||||
private fun genStubClasses(outDir: File): Pair<String, String> {
|
||||
val classNameGenerator = sequence {
|
||||
fun notJavaKeyword(name: String) = when (name) {
|
||||
"do", "if", "for", "int", "new", "try" -> false
|
||||
@@ -217,7 +209,7 @@ private fun genStubClasses(factoryOutDir: File, appOutDir: File) {
|
||||
}
|
||||
}.distinct().iterator()
|
||||
|
||||
fun genClass(type: String, outDir: File) {
|
||||
fun genClass(type: String, outDir: File): String {
|
||||
val clzName = classNameGenerator.next()
|
||||
val (pkg, name) = clzName.split('.')
|
||||
val pkgDir = File(outDir, pkg)
|
||||
@@ -226,10 +218,12 @@ private fun genStubClasses(factoryOutDir: File, appOutDir: File) {
|
||||
it.println("package $pkg;")
|
||||
it.println("public class $name extends com.topjohnwu.magisk.$type {}")
|
||||
}
|
||||
return clzName
|
||||
}
|
||||
|
||||
genClass("DelegateComponentFactory", factoryOutDir)
|
||||
genClass("StubApplication", appOutDir)
|
||||
val factory = genClass("DelegateComponentFactory", outDir)
|
||||
val app = genClass("StubApplication", outDir)
|
||||
return Pair(factory, app)
|
||||
}
|
||||
|
||||
private fun genEncryptedResources(res: ByteArray, outDir: File) {
|
||||
@@ -264,74 +258,76 @@ private fun genEncryptedResources(res: ByteArray, outDir: File) {
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class TaskWithDir : DefaultTask() {
|
||||
@get:OutputDirectory
|
||||
abstract val outputFolder: DirectoryProperty
|
||||
}
|
||||
|
||||
fun Project.setupStubApk() {
|
||||
setupAppCommon()
|
||||
|
||||
androidComponents.onVariants { variant ->
|
||||
val variantName = variant.name
|
||||
val variantCapped = variantName.replaceFirstChar { it.uppercase() }
|
||||
val manifestUpdater =
|
||||
project.tasks.register("${variantName}ManifestProducer", ManifestUpdater::class.java) {
|
||||
dependsOn("generate${variantCapped}ObfuscatedClass")
|
||||
applicationId = variant.applicationId
|
||||
appClassDir.set(layout.buildDirectory.dir("generated/source/app/$variantName"))
|
||||
factoryClassDir.set(layout.buildDirectory.dir("generated/source/factory/$variantName"))
|
||||
}
|
||||
variant.artifacts.use(manifestUpdater)
|
||||
.wiredWithFiles(
|
||||
ManifestUpdater::mergedManifest,
|
||||
ManifestUpdater::outputManifest)
|
||||
.toTransform(SingleArtifact.MERGED_MANIFEST)
|
||||
}
|
||||
androidAppComponents {
|
||||
onVariants { variant ->
|
||||
val variantName = variant.name
|
||||
val variantCapped = variantName.replaceFirstChar { it.uppercase() }
|
||||
val variantLowered = variantName.lowercase()
|
||||
|
||||
androidApp.applicationVariants.all {
|
||||
val variantCapped = name.replaceFirstChar { it.uppercase() }
|
||||
val variantLowered = name.lowercase()
|
||||
val outFactoryClassDir = layout.buildDirectory.file("generated/source/factory/${variantLowered}").get().asFile
|
||||
val outAppClassDir = layout.buildDirectory.file("generated/source/app/${variantLowered}").get().asFile
|
||||
val outResDir = layout.buildDirectory.dir("generated/source/res/${variantLowered}").get().asFile
|
||||
val aapt = File(androidApp.sdkDirectory, "build-tools/${androidApp.buildToolsVersion}/aapt2")
|
||||
val apk = layout.buildDirectory.file("intermediates/linked_resources_binary_format/" +
|
||||
"${variantLowered}/process${variantCapped}Resources/linked-resources-binary-format-${variantLowered}.ap_").get().asFile
|
||||
val componentJavaOutDir = layout.buildDirectory
|
||||
.dir("generated/${variantLowered}/components").get().asFile
|
||||
|
||||
val genManifestTask = tasks.register("generate${variantCapped}ObfuscatedClass") {
|
||||
inputs.property("seed", RAND_SEED)
|
||||
outputs.dirs(outFactoryClassDir, outAppClassDir)
|
||||
doLast {
|
||||
outFactoryClassDir.mkdirs()
|
||||
outAppClassDir.mkdirs()
|
||||
genStubClasses(outFactoryClassDir, outAppClassDir)
|
||||
}
|
||||
}
|
||||
registerJavaGeneratingTask(genManifestTask, outFactoryClassDir, outAppClassDir)
|
||||
val (factory, app) = genStubClasses(componentJavaOutDir)
|
||||
|
||||
val processResourcesTask = tasks.named("process${variantCapped}Resources") {
|
||||
outputs.dir(outResDir)
|
||||
doLast {
|
||||
val apkTmp = File("${apk}.tmp")
|
||||
providers.exec {
|
||||
commandLine(aapt, "optimize", "-o", apkTmp, "--collapse-resource-names", apk)
|
||||
}.result.get()
|
||||
|
||||
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)
|
||||
}
|
||||
val manifestUpdater =
|
||||
project.tasks.register("${variantName}ManifestProducer", ManifestUpdater::class.java) {
|
||||
applicationId = variant.applicationId
|
||||
factoryClass.set(factory)
|
||||
appClass.set(app)
|
||||
}
|
||||
apkTmp.delete()
|
||||
genEncryptedResources(bos.toByteArray(), outResDir)
|
||||
variant.artifacts.use(manifestUpdater)
|
||||
.wiredWithFiles(
|
||||
ManifestUpdater::mergedManifest,
|
||||
ManifestUpdater::outputManifest)
|
||||
.toTransform(SingleArtifact.MERGED_MANIFEST)
|
||||
|
||||
val aapt = sdkComponents.aapt2.get().executable.get().asFile
|
||||
val apk = layout.buildDirectory.file("intermediates/linked_resources_binary_format/" +
|
||||
"${variantLowered}/process${variantCapped}Resources/" +
|
||||
"linked-resources-binary-format-${variantLowered}.ap_").get().asFile
|
||||
|
||||
val genResourcesTask = tasks.register("generate${variantCapped}BundledResources", TaskWithDir::class) {
|
||||
dependsOn("process${variantCapped}Resources")
|
||||
outputFolder.set(layout.buildDirectory.dir("generated/${variantLowered}/resources"))
|
||||
|
||||
doLast {
|
||||
val apkTmp = File("${apk}.tmp")
|
||||
providers.exec {
|
||||
commandLine(aapt, "optimize", "-o", apkTmp, "--collapse-resource-names", apk)
|
||||
}.result.get()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
apkTmp.delete()
|
||||
genEncryptedResources(bos.toByteArray(), outputFolder.get().asFile)
|
||||
}
|
||||
}
|
||||
|
||||
variant.sources.java?.let {
|
||||
it.addStaticSourceDirectory(componentJavaOutDir.path)
|
||||
it.addGeneratedSourceDirectory(genResourcesTask, TaskWithDir::outputFolder)
|
||||
}
|
||||
}
|
||||
|
||||
registerJavaGeneratingTask(processResourcesTask, outResDir)
|
||||
}
|
||||
|
||||
// Override optimizeReleaseResources task
|
||||
val apk = layout.buildDirectory.file("intermediates/linked_resources_binary_format/" +
|
||||
"release/processReleaseResources/linked-resources-binary-format-release.ap_").get().asFile
|
||||
|
||||
3
app/core/.gitignore
vendored
3
app/core/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
/build
|
||||
src/debug
|
||||
src/release
|
||||
@@ -1,6 +1,5 @@
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
kotlin("android")
|
||||
kotlin("plugin.parcelize")
|
||||
id("dev.zacsweers.moshix")
|
||||
id("com.google.devtools.ksp")
|
||||
|
||||
4
app/core/proguard-rules.pro
vendored
4
app/core/proguard-rules.pro
vendored
@@ -33,9 +33,5 @@
|
||||
# is used.
|
||||
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
|
||||
|
||||
# Excessive obfuscation
|
||||
-flattenpackagehierarchy
|
||||
-allowaccessmodification
|
||||
|
||||
-dontwarn org.junit.**
|
||||
-dontwarn org.apache.**
|
||||
|
||||
@@ -24,9 +24,7 @@ org.gradle.caching=true
|
||||
kapt.use.k2=true
|
||||
|
||||
# Android
|
||||
android.useAndroidX=true
|
||||
android.injected.testOnly=false
|
||||
android.nonFinalResIds=false
|
||||
|
||||
# Magisk
|
||||
magisk.stubVersion=40
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[versions]
|
||||
kotlin = "2.2.21"
|
||||
android = "8.13.2"
|
||||
ksp = "2.3.3"
|
||||
kotlin = "2.3.0"
|
||||
android = "9.0.0"
|
||||
ksp = "2.3.4"
|
||||
rikka = "1.3.0"
|
||||
navigation = "2.9.6"
|
||||
libsu = "6.0.0"
|
||||
@@ -23,7 +23,7 @@ timber = { module = "com.jakewharton.timber:timber", version = "5.0.1" }
|
||||
jgit = { module = "org.eclipse.jgit:org.eclipse.jgit", version = "7.1.0.202411261347-r" }
|
||||
|
||||
# AndroidX
|
||||
activity = { module = "androidx.activity:activity", version = "1.12.1" }
|
||||
activity = { module = "androidx.activity:activity", version = "1.12.2" }
|
||||
appcompat = { module = "androidx.appcompat:appcompat", version = "1.7.1" }
|
||||
core-ktx = { module = "androidx.core:core-ktx", version = "1.17.0" }
|
||||
core-splashscreen = { module = "androidx.core:core-splashscreen", version = "1.2.0" }
|
||||
@@ -37,7 +37,7 @@ room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }
|
||||
room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
|
||||
room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
|
||||
swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version = "1.2.0" }
|
||||
transition = { module = "androidx.transition:transition", version = "1.6.0" }
|
||||
transition = { module = "androidx.transition:transition", version = "1.7.0" }
|
||||
collection-ktx = { module = "androidx.collection:collection-ktx", version = "1.5.0" }
|
||||
material = { module = "com.google.android.material:material", version = "1.13.0" }
|
||||
jdk-libs = { module = "com.android.tools:desugar_jdk_libs_nio", version = "2.1.5" }
|
||||
@@ -59,9 +59,10 @@ rikka-insets = { module = "dev.rikka.rikkax.insets:insets", version.ref = "rikka
|
||||
|
||||
# Build plugins
|
||||
android-gradle-plugin = { module = "com.android.tools.build:gradle", version.ref = "android" }
|
||||
android-kapt-plugin = { module = "com.android.legacy-kapt:com.android.legacy-kapt.gradle.plugin", version.ref = "android" }
|
||||
ksp-plugin = { module = "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" }
|
||||
navigation-safe-args-plugin = { module = "androidx.navigation:navigation-safe-args-gradle-plugin", version.ref = "navigation" }
|
||||
lsparanoid-plugin = { module = "org.lsposed.lsparanoid:gradle-plugin", version = "0.6.0" }
|
||||
moshi-plugin = { module = "dev.zacsweers.moshix:dev.zacsweers.moshix.gradle.plugin", version = "0.34.1" }
|
||||
moshi-plugin = { module = "dev.zacsweers.moshix:dev.zacsweers.moshix.gradle.plugin", version = "0.34.2" }
|
||||
|
||||
[plugins]
|
||||
|
||||
2
app/gradle/wrapper/gradle-wrapper.properties
vendored
2
app/gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
1
app/shared/.gitignore
vendored
1
app/shared/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
/build
|
||||
@@ -6,4 +6,5 @@ setupCommon()
|
||||
|
||||
android {
|
||||
namespace = "com.topjohnwu.shared"
|
||||
enableKotlin = false
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
kotlin("android")
|
||||
}
|
||||
|
||||
android {
|
||||
|
||||
Reference in New Issue
Block a user