eee068a500
- Read keystore.properties at Gradle config time; wire signingConfig into the release build type (degrades gracefully when the file is absent)
233 lines
9.0 KiB
Kotlin
233 lines
9.0 KiB
Kotlin
import java.util.Properties
|
|
|
|
plugins {
|
|
alias(libs.plugins.android.application)
|
|
}
|
|
|
|
val keystoreProps = Properties().apply {
|
|
rootProject.file("keystore.properties").takeIf { it.exists() }
|
|
?.reader()?.use { load(it) }
|
|
}
|
|
|
|
android {
|
|
namespace = "de.ladkau.schwertundmagieonpebblecompanionapp"
|
|
compileSdk {
|
|
version = release(36) {
|
|
minorApiLevel = 1
|
|
}
|
|
}
|
|
|
|
ndkVersion = "30.0.14904198"
|
|
|
|
defaultConfig {
|
|
applicationId = "de.ladkau.schwertundmagieonpebblecompanionapp"
|
|
minSdk = 24
|
|
targetSdk = 36
|
|
versionCode = 1
|
|
versionName = "1.0"
|
|
|
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
|
|
|
ndk {
|
|
abiFilters += listOf("arm64-v8a", "x86_64")
|
|
}
|
|
externalNativeBuild {
|
|
cmake {
|
|
arguments("-DANDROID_STL=c++_shared")
|
|
// HAVE_VICE_SRC is detected automatically by CMakeLists.txt
|
|
// based on whether vice-libs/<abi>/libvice.a exists.
|
|
}
|
|
}
|
|
}
|
|
|
|
signingConfigs {
|
|
create("release") {
|
|
keystoreProps["storeFile"]?.let { storeFile = rootProject.file(it as String) }
|
|
storePassword = keystoreProps["storePassword"] as String?
|
|
keyAlias = keystoreProps["keyAlias"] as String?
|
|
keyPassword = keystoreProps["keyPassword"] as String?
|
|
}
|
|
}
|
|
|
|
buildTypes {
|
|
release {
|
|
signingConfig = signingConfigs.getByName("release")
|
|
isMinifyEnabled = false
|
|
proguardFiles(
|
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
"proguard-rules.pro"
|
|
)
|
|
}
|
|
}
|
|
compileOptions {
|
|
sourceCompatibility = JavaVersion.VERSION_11
|
|
targetCompatibility = JavaVersion.VERSION_11
|
|
}
|
|
externalNativeBuild {
|
|
cmake {
|
|
path = file("src/main/jni/CMakeLists.txt")
|
|
version = "3.22.1"
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// VICE cross-compilation task
|
|
//
|
|
// Runs automatically before any CMake build step.
|
|
// Skipped entirely if vice-libs/<abi>/libvice.a already exists.
|
|
// The tarball at <project>/res/vice-3.8.tar.gz is unpacked by build_vice.sh.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
val viceLibArm = layout.projectDirectory.file("src/main/jni/vice-libs/arm64-v8a/libvice.a")
|
|
val viceLibX86 = layout.projectDirectory.file("src/main/jni/vice-libs/x86_64/libvice.a")
|
|
val viceTarball = layout.projectDirectory.file("../res/vice-3.8.tar.gz")
|
|
|
|
tasks.register("buildVice") {
|
|
group = "build"
|
|
description = "Cross-compile VICE 3.8 headless for Android (ARM64 + x86_64)"
|
|
|
|
inputs.file(viceTarball)
|
|
outputs.file(viceLibArm)
|
|
outputs.file(viceLibX86)
|
|
|
|
doLast {
|
|
if (viceLibArm.asFile.exists() && viceLibX86.asFile.exists()) {
|
|
logger.lifecycle("VICE already built — skipping")
|
|
return@doLast
|
|
}
|
|
|
|
val localProps = Properties().apply {
|
|
rootProject.file("local.properties").takeIf { it.exists() }
|
|
?.reader()?.use { load(it) }
|
|
}
|
|
val sdkDir = localProps.getProperty("sdk.dir")
|
|
?: System.getenv("ANDROID_HOME")
|
|
?: ""
|
|
val ndkPath = localProps.getProperty("ndk.dir")
|
|
?: System.getenv("ANDROID_NDK_HOME")
|
|
?: System.getenv("ANDROID_NDK_ROOT")
|
|
?: System.getenv("NDK")
|
|
?: sdkDir.takeIf { it.isNotEmpty() }?.let { sdk ->
|
|
// NDK side-by-side: pick the first installed version
|
|
file("$sdk/ndk").takeIf { it.isDirectory }
|
|
?.listFiles()?.sorted()?.lastOrNull()?.absolutePath
|
|
?: "$sdk/ndk-bundle".takeIf { file("$sdk/ndk-bundle").isDirectory }
|
|
}
|
|
?: throw GradleException(
|
|
"Android NDK not found.\n" +
|
|
"Install via: Android Studio → SDK Manager → SDK Tools → NDK (Side by side)"
|
|
)
|
|
logger.lifecycle("Building VICE with NDK at $ndkPath …")
|
|
|
|
val proc = ProcessBuilder("bash", "build_vice.sh")
|
|
.directory(layout.projectDirectory.dir("src/main/jni").asFile)
|
|
.redirectErrorStream(true)
|
|
.also { it.environment()["NDK"] = ndkPath }
|
|
.start()
|
|
proc.inputStream.bufferedReader().forEachLine { logger.lifecycle(it) }
|
|
val exit = proc.waitFor()
|
|
if (exit != 0) throw GradleException("build_vice.sh failed (exit $exit)")
|
|
|
|
// Touch CMakeLists.txt so CMake re-evaluates the EXISTS check on the
|
|
// next build and picks up the newly created libvice.a.
|
|
layout.projectDirectory.file("src/main/jni/CMakeLists.txt")
|
|
.asFile.setLastModified(System.currentTimeMillis())
|
|
logger.lifecycle("VICE build complete — CMakeLists.txt touched for re-evaluation")
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// nibtools cross-compilation task
|
|
//
|
|
// Builds nibconv (NIB/NBZ -> G64/D64 disk image conversion, used by the
|
|
// "Download Disks" feature) the same way buildVice builds VICE above.
|
|
// Skipped entirely if nibtools-libs/<abi>/libnibtools.a already exists.
|
|
// The tarball at <project>/res/nibtools-91344e0ee3.tar.gz is unpacked by
|
|
// build_nibtools.sh.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
val nibtoolsLibArm = layout.projectDirectory.file("src/main/jni/nibtools-libs/arm64-v8a/libnibtools.a")
|
|
val nibtoolsLibX86 = layout.projectDirectory.file("src/main/jni/nibtools-libs/x86_64/libnibtools.a")
|
|
val nibtoolsTarball = layout.projectDirectory.file("../res/nibtools-91344e0ee3.tar.gz")
|
|
|
|
tasks.register("buildNibtools") {
|
|
group = "build"
|
|
description = "Cross-compile nibtools' nibconv for Android (ARM64 + x86_64)"
|
|
|
|
inputs.file(nibtoolsTarball)
|
|
outputs.file(nibtoolsLibArm)
|
|
outputs.file(nibtoolsLibX86)
|
|
|
|
doLast {
|
|
if (nibtoolsLibArm.asFile.exists() && nibtoolsLibX86.asFile.exists()) {
|
|
logger.lifecycle("nibtools already built — skipping")
|
|
return@doLast
|
|
}
|
|
|
|
val localProps = Properties().apply {
|
|
rootProject.file("local.properties").takeIf { it.exists() }
|
|
?.reader()?.use { load(it) }
|
|
}
|
|
val sdkDir = localProps.getProperty("sdk.dir")
|
|
?: System.getenv("ANDROID_HOME")
|
|
?: ""
|
|
val ndkPath = localProps.getProperty("ndk.dir")
|
|
?: System.getenv("ANDROID_NDK_HOME")
|
|
?: System.getenv("ANDROID_NDK_ROOT")
|
|
?: System.getenv("NDK")
|
|
?: sdkDir.takeIf { it.isNotEmpty() }?.let { sdk ->
|
|
file("$sdk/ndk").takeIf { it.isDirectory }
|
|
?.listFiles()?.sorted()?.lastOrNull()?.absolutePath
|
|
?: "$sdk/ndk-bundle".takeIf { file("$sdk/ndk-bundle").isDirectory }
|
|
}
|
|
?: throw GradleException(
|
|
"Android NDK not found.\n" +
|
|
"Install via: Android Studio → SDK Manager → SDK Tools → NDK (Side by side)"
|
|
)
|
|
logger.lifecycle("Building nibtools with NDK at $ndkPath …")
|
|
|
|
val proc = ProcessBuilder("bash", "build_nibtools.sh")
|
|
.directory(layout.projectDirectory.dir("src/main/jni").asFile)
|
|
.redirectErrorStream(true)
|
|
.also { it.environment()["NDK"] = ndkPath }
|
|
.start()
|
|
proc.inputStream.bufferedReader().forEachLine { logger.lifecycle(it) }
|
|
val exit = proc.waitFor()
|
|
if (exit != 0) throw GradleException("build_nibtools.sh failed (exit $exit)")
|
|
|
|
layout.projectDirectory.file("src/main/jni/CMakeLists.txt")
|
|
.asFile.setLastModified(System.currentTimeMillis())
|
|
logger.lifecycle("nibtools build complete — CMakeLists.txt touched for re-evaluation")
|
|
}
|
|
}
|
|
|
|
// Run buildVice and buildNibtools before any CMake configure or build step.
|
|
tasks.whenTaskAdded {
|
|
if (name.startsWith("configureCMake") || name.startsWith("buildCMake") ||
|
|
name.startsWith("externalNativeBuild")) {
|
|
dependsOn("buildVice")
|
|
dependsOn("buildNibtools")
|
|
}
|
|
}
|
|
|
|
// Note: C64/1541 ROMs are intentionally NOT bundled into the APK — they are
|
|
// copyrighted Commodore firmware. The app prompts the user to import their
|
|
// own ROM dump at runtime instead (see MainActivity.showRomImportDialog()).
|
|
// res/extract_roms.sh remains available for extracting ROMs from the VICE
|
|
// tarball locally (e.g. to sideload onto a test device), but nothing in this
|
|
// build copies them into assets/ or the APK.
|
|
|
|
dependencies {
|
|
implementation(libs.androidx.activity.ktx)
|
|
implementation(libs.androidx.appcompat)
|
|
implementation(libs.androidx.constraintlayout)
|
|
implementation(libs.androidx.core.ktx)
|
|
implementation(libs.material)
|
|
implementation(libs.nanohttpd)
|
|
implementation(libs.androidx.documentfile)
|
|
testImplementation(libs.junit)
|
|
androidTestImplementation(libs.androidx.espresso.core)
|
|
androidTestImplementation(libs.androidx.junit)
|
|
}
|