mirror of
https://github.com/topjohnwu/Magisk.git
synced 2026-04-28 12:03:09 -07:00
Stop relying on internal AGP intermediate paths in the build directory. Use standard AGP classes to achieve the same result
352 lines
12 KiB
Kotlin
352 lines
12 KiB
Kotlin
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 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.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.register
|
|
import java.io.File
|
|
import java.net.URI
|
|
import java.security.MessageDigest
|
|
import java.util.HexFormat
|
|
|
|
private fun Project.android(configure: Action<CommonExtension>) =
|
|
extensions.configure("android", configure)
|
|
|
|
private fun Project.androidApp(configure: Action<ApplicationExtension>) =
|
|
extensions.configure("android", configure)
|
|
|
|
internal val Project.androidApp: ApplicationExtension
|
|
get() = extensions["android"] as ApplicationExtension
|
|
|
|
private fun Project.androidComponents(configure: Action<AndroidComponentsExtension<*, *, *>>) =
|
|
extensions.configure(AndroidComponentsExtension::class.java, configure)
|
|
|
|
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() {
|
|
android {
|
|
compileSdk {
|
|
version = release(36) {
|
|
minorApiLevel = 1
|
|
}
|
|
}
|
|
buildToolsVersion = "36.1.0"
|
|
ndkPath = "${androidComponents.sdkComponents.sdkDirectory.get().asFile}/ndk/magisk"
|
|
ndkVersion = "29.0.14206865"
|
|
|
|
defaultConfig.apply {
|
|
minSdk = 23
|
|
}
|
|
|
|
compileOptions.apply {
|
|
sourceCompatibility = JavaVersion.VERSION_21
|
|
targetCompatibility = JavaVersion.VERSION_21
|
|
}
|
|
|
|
packaging.apply {
|
|
resources {
|
|
excludes += arrayOf(
|
|
"/META-INF/*",
|
|
"/META-INF/androidx/**",
|
|
"/META-INF/versions/**",
|
|
"/org/bouncycastle/**",
|
|
"/org/apache/commons/**",
|
|
"/kotlin/**",
|
|
"/kotlinx/**",
|
|
"/okhttp3/**",
|
|
"/*.txt",
|
|
"/*.bin",
|
|
"/*.json",
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
configurations.all {
|
|
exclude("org.jetbrains.kotlin", "kotlin-stdlib-jdk7")
|
|
exclude("org.jetbrains.kotlin", "kotlin-stdlib-jdk8")
|
|
}
|
|
}
|
|
|
|
private fun Project.downloadFile(url: String, checksum: String): File {
|
|
val file = layout.buildDirectory.file(checksum).get().asFile
|
|
if (file.exists()) {
|
|
val md = MessageDigest.getInstance("SHA-256")
|
|
file.inputStream().use { md.update(it.readAllBytes()) }
|
|
val hash = HexFormat.of().formatHex(md.digest())
|
|
if (hash != checksum) {
|
|
file.delete()
|
|
}
|
|
}
|
|
if (!file.exists()) {
|
|
file.parentFile.mkdirs()
|
|
URI(url).toURL().openStream().use { dl ->
|
|
file.outputStream().use {
|
|
dl.copyTo(it)
|
|
}
|
|
}
|
|
}
|
|
return file
|
|
}
|
|
|
|
const val BUSYBOX_DOWNLOAD_URL =
|
|
"https://github.com/topjohnwu/magisk-files/releases/download/files/busybox-1.36.1.1.zip"
|
|
const val BUSYBOX_ZIP_CHECKSUM =
|
|
"b4d0551feabaf314e53c79316c980e8f66432e9fb91a69dbbf10a93564b40951"
|
|
|
|
private abstract class SyncWithDir : Sync() {
|
|
@get:OutputDirectory
|
|
abstract val outputFolder: DirectoryProperty
|
|
}
|
|
|
|
fun Project.setupCoreLib() {
|
|
setupCommon()
|
|
|
|
val abiList = Config.abiList
|
|
|
|
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" }
|
|
}
|
|
}
|
|
}
|
|
|
|
variant.sources.resources?.let {
|
|
it.addGeneratedSourceDirectory(syncResources, SyncWithDir::outputFolder)
|
|
}
|
|
|
|
val stubTask = tasks.getByPath(":stub:transform${variantCapped}Apk")
|
|
val syncAssets = tasks.register("sync${variantCapped}Assets", SyncWithDir::class) {
|
|
outputFolder.set(layout.buildDirectory.dir("$variantName/assets"))
|
|
into(outputFolder)
|
|
|
|
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"))
|
|
}
|
|
}
|
|
|
|
variant.sources.assets?.let {
|
|
it.addGeneratedSourceDirectory(syncAssets, SyncWithDir::outputFolder)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun Project.setupAppCommon() {
|
|
setupCommon()
|
|
|
|
androidApp {
|
|
signingConfigs {
|
|
Config["keyStore"]?.also {
|
|
create("config") {
|
|
storeFile = rootFile(it)
|
|
storePassword = Config["keyStorePass"]
|
|
keyAlias = Config["keyAlias"]
|
|
keyPassword = Config["keyPass"]
|
|
}
|
|
}
|
|
}
|
|
|
|
defaultConfig {
|
|
targetSdk = 36
|
|
proguardFiles(
|
|
getDefaultProguardFile("proguard-android-optimize.txt")
|
|
)
|
|
}
|
|
|
|
buildTypes {
|
|
val config = signingConfigs.findByName("config") ?: signingConfigs["debug"]
|
|
debug {
|
|
signingConfig = config
|
|
}
|
|
release {
|
|
signingConfig = config
|
|
}
|
|
}
|
|
|
|
lint {
|
|
disable += "MissingTranslation"
|
|
checkReleaseBuilds = false
|
|
}
|
|
|
|
dependenciesInfo {
|
|
includeInApk = false
|
|
}
|
|
|
|
packaging {
|
|
jniLibs {
|
|
useLegacyPackaging = true
|
|
}
|
|
}
|
|
}
|
|
|
|
androidAppComponents {
|
|
onVariants { variant ->
|
|
val commentTask = tasks.register(
|
|
"transform${variant.name.replaceFirstChar { it.uppercase() }}Apk",
|
|
TransformApkTask::class.java
|
|
)
|
|
val transformationRequest = variant.artifacts.use(commentTask)
|
|
.wiredWithDirectories(TransformApkTask::apkFolder, TransformApkTask::outFolder)
|
|
.toTransformMany(SingleArtifact.APK)
|
|
val signingConfig = androidApp.buildTypes.getByName(variant.buildType!!).signingConfig
|
|
commentTask.configure {
|
|
this.transformationRequest = transformationRequest
|
|
this.signingConfig = signingConfig
|
|
this.outFolder.set(layout.buildDirectory.dir("outputs/apk/${variant.name}"))
|
|
// Always add a transformation to set comments on the APK
|
|
this.transformations.add {
|
|
it.eocdComment = ("version=${Config.version}\n" +
|
|
"versionCode=${Config.versionCode}\n" +
|
|
"stubVersion=${Config.stubVersion}\n").toByteArray()
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
fun Project.setupMainApk() {
|
|
setupAppCommon()
|
|
|
|
androidApp {
|
|
namespace = "com.topjohnwu.magisk"
|
|
|
|
defaultConfig {
|
|
applicationId = "com.topjohnwu.magisk"
|
|
vectorDrawables.useSupportLibrary = true
|
|
versionName = Config.version
|
|
versionCode = Config.versionCode
|
|
ndk {
|
|
abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64", "riscv64")
|
|
debugSymbolLevel = "FULL"
|
|
}
|
|
}
|
|
}
|
|
|
|
androidComponents {
|
|
onVariants { variant ->
|
|
variant.instrumentation.apply {
|
|
setAsmFramesComputationMode(COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS)
|
|
transformClassesWith(
|
|
DesugarClassVisitorFactory::class.java, InstrumentationScope.ALL) {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const val LSPOSED_DOWNLOAD_URL =
|
|
"https://github.com/LSPosed/LSPosed/releases/download/v1.9.2/LSPosed-v1.9.2-7024-zygisk-release.zip"
|
|
const val LSPOSED_CHECKSUM =
|
|
"0ebc6bcb465d1c4b44b7220ab5f0252e6b4eb7fe43da74650476d2798bb29622"
|
|
|
|
const val SHAMIKO_DOWNLOAD_URL =
|
|
"https://github.com/LSPosed/LSPosed.github.io/releases/download/shamiko-383/Shamiko-v1.2.1-383-release.zip"
|
|
const val SHAMIKO_CHECKSUM =
|
|
"93754a038c2d8f0e985bad45c7303b96f70a93d8335060e50146f028d3a9b13f"
|
|
|
|
fun Project.setupTestApk() {
|
|
setupAppCommon()
|
|
|
|
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" }
|
|
}
|
|
}
|
|
|
|
variant.sources.assets?.let {
|
|
it.addGeneratedSourceDirectory(dlTask, SyncWithDir::outputFolder)
|
|
}
|
|
}
|
|
}
|
|
}
|