Files
FridaBox/app/build.gradle
dependabot[bot]andGitHub 330c634715 build(deps): bump org.tukaani:xz to 1.12 (#16)
Apply the bug-fix update after a successful Android CI run.
2026-07-28 19:30:44 +03:30

195 lines
7.2 KiB
Groovy

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
}
def releaseStoreFile = System.getenv("FRIDABOX_RELEASE_STORE_FILE")
def releaseStorePassword = System.getenv("FRIDABOX_RELEASE_STORE_PASSWORD")
def releaseKeyAlias = System.getenv("FRIDABOX_RELEASE_KEY_ALIAS")
def releaseKeyPassword = System.getenv("FRIDABOX_RELEASE_KEY_PASSWORD")
def releaseSigningValues = [releaseStoreFile, releaseStorePassword, releaseKeyAlias, releaseKeyPassword]
def releaseSigningConfigured = releaseSigningValues.every { it != null && !it.trim().isEmpty() }
if (releaseSigningValues.any { it != null && !it.trim().isEmpty() } && !releaseSigningConfigured) {
throw new GradleException("Release signing is incomplete. Set all four FRIDABOX_RELEASE_* environment variables.")
}
android {
namespace 'com.qm4rs.fridabox'
compileSdk rootProject.ext.compileSdkVersion
ndkVersion = "29.0.14206865"
defaultConfig {
applicationId "com.qm4rs.fridabox"
minSdk rootProject.ext.minSdk
targetSdk rootProject.ext.targetSdkVersion
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
splits {
abi {
enable true
reset()
include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
universalApk false
}
}
}
signingConfigs {
if (releaseSigningConfigured) {
release {
storeFile file(releaseStoreFile)
storePassword releaseStorePassword
keyAlias releaseKeyAlias
keyPassword releaseKeyPassword
}
}
}
buildTypes {
release {
if (releaseSigningConfigured) {
signingConfig signingConfigs.release
}
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
}
buildFeatures {
viewBinding true
buildConfig true
}
sourceSets {
debug.assets.srcDir("$buildDir/generated/demoGuestAssets")
}
kotlinOptions {
jvmTarget = '21'
}
packaging {
jniLibs {
excludes.add("**/libandroidx.graphics.path.so")
useLegacyPackaging true
}
resources {
excludes.add("**/libandroidx.graphics.path.so")
}
}
applicationVariants.configureEach { variant ->
variant.outputs.configureEach { output ->
output.outputFileName = "FridaBox_${variant.versionName}_${output.baseName}.apk"
}
}
lint {
abortOnError false
checkReleaseBuilds false
}
}
tasks.register("copyDemoGuestDebug", Copy) {
dependsOn(":sample-guest:assembleDebug")
from(project(":sample-guest").layout.buildDirectory.file("outputs/apk/debug/sample-guest-debug.apk"))
into(layout.buildDirectory.dir("generated/demoGuestAssets/demo"))
rename { "sample-guest.apk" }
}
tasks.matching { it.name == "mergeDebugAssets" }.configureEach { dependsOn("copyDemoGuestDebug") }
tasks.matching { it.name.toLowerCase().contains("debug") && it.name.toLowerCase().contains("lint") }
.configureEach { dependsOn("copyDemoGuestDebug") }
tasks.register("verifyDebugApkHasNoGadget") {
dependsOn("assembleDebug")
doLast {
def apks = fileTree("$buildDir/outputs/apk/debug").matching { include("*.apk") }.files
if (apks.isEmpty()) {
throw new GradleException("No debug APKs were produced")
}
apks.each { apk ->
def entries = zipTree(apk).files.findAll {
it.name.toLowerCase().contains("gadget") && it.name.toLowerCase().endsWith(".so")
}
if (!entries.isEmpty()) {
throw new GradleException("${apk.name} must not bundle Frida Gadget: ${entries*.name}")
}
}
}
}
tasks.register("verifyInstrumentationOrdering") {
doLast {
def source = project(":Bcore").file("src/main/java/top/niunaijun/blackbox/app/BActivityThread.java").text
def loader = source.indexOf("FridaGadgetLoader.loadAtProcessBind()")
def makeApplication = source.indexOf("makeApplication(", loader)
if (loader < 0 || makeApplication < 0 || loader >= makeApplication) {
throw new GradleException("Frida Gadget loader must execute before guest makeApplication")
}
}
}
tasks.register("verifyRuntimeBridgeAssets") {
doLast {
def bridgeAssets = [
"java-7.0.11.js", "java-7.0.12.js", "java-7.0.13.js",
"il2cpp-0.12.2.js", "il2cpp-0.13.0.js", "il2cpp-0.13.1.js"
]
def bridgeRoot = file("src/main/assets/fridabox/bridges")
bridgeAssets.each { name ->
def asset = new File(bridgeRoot, name)
if (!asset.isFile() || asset.length() == 0 || asset.length() > 2 * 1024 * 1024) {
throw new GradleException("Missing or invalid runtime bridge asset: ${name}")
}
def source = new String(asset.bytes, java.nio.charset.StandardCharsets.UTF_8)
if (!source.startsWith("📦\n") || !source.contains("\n✄\n")) {
throw new GradleException("Runtime bridge is not a valid frida-compile bundle: ${name}")
}
}
}
}
tasks.register("verifyTablerAndroidIcons", Exec) {
workingDir(rootProject.projectDir)
def nodeExecutable = System.getProperty("os.name").toLowerCase().contains("windows") ? "node.exe" : "node"
commandLine(nodeExecutable, "tools/generate_tabler_android_icons.mjs", "--check")
doFirst {
if (!rootProject.file("node_modules/@tabler/icons/package.json").isFile()) {
throw new GradleException("Missing @tabler/icons. Run npm ci before building FridaBox.")
}
}
}
tasks.register("verifyDemoGuestUnmodified") {
dependsOn("copyDemoGuestDebug")
doLast {
def source = project(":sample-guest").layout.buildDirectory.file("outputs/apk/debug/sample-guest-debug.apk").get().asFile
def embedded = layout.buildDirectory.file("generated/demoGuestAssets/demo/sample-guest.apk").get().asFile
if (!java.util.Arrays.equals(java.security.MessageDigest.getInstance("SHA-256").digest(source.bytes),
java.security.MessageDigest.getInstance("SHA-256").digest(embedded.bytes))) {
throw new GradleException("Embedded sample APK differs from generated sample APK")
}
}
}
tasks.named("check").configure {
dependsOn("verifyDebugApkHasNoGadget", "verifyInstrumentationOrdering",
"verifyDemoGuestUnmodified", "verifyTablerAndroidIcons", "verifyRuntimeBridgeAssets")
}
dependencies {
implementation project(':Bcore')
implementation libs.appcompat
implementation libs.material
implementation libs.constraintlayout
implementation libs.core.ktx
implementation "org.tukaani:xz:1.12"
testImplementation libs.junit
androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core
}