straw/strawApp/build.gradle.kts
Cobb af3c39a662
Some checks failed
build-apk / build-and-publish (push) Failing after 44s
gitleaks / scan (push) Successful in 42s
Strip NewPipe: remove legacy :app + unused :desktopApp/:shared modules
Straw runs on the strawcore Rust pipeline and ships only :strawApp — it is not NewPipe and uses none of their app code. Removes the 12M org.schabi.newpipe :app module (the fork base) and the unused NewPipe-origin KMP :desktopApp/:shared scaffold. settings.gradle now includes only :strawApp; also drops the NewPipe SPDX header + the NewPipeExtractor includeBuild stub. This also kills the recurring config-time git failure from app/build.gradle.kts.
2026-06-20 07:19:33 -07:00

254 lines
9.8 KiB
Kotlin

/*
* SPDX-FileCopyrightText: 2026 Sulkta-Coop
* SPDX-License-Identifier: GPL-3.0-or-later
*
* :strawApp — thin Android application shell. Day-2: pulls NewPipeExtractor,
* Media3, Ktor-style HTTP-via-OkHttp + kotlinx-serialization JSON for the
* search → detail → player → SponsorBlock + RYD flow. We keep our deps in
* this module, NOT in the shared libs.versions.toml, so upstream NewPipe
* stays cleanly mergeable.
*/
import com.android.build.api.dsl.ApplicationExtension
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.compose)
alias(libs.plugins.jetbrains.kotlinx.serialization)
}
kotlin {
jvmToolchain(21)
}
configure<ApplicationExtension> {
compileSdk {
version = release(STRAW_SDK_COMPILE_MAJOR) {
minorApiLevel = STRAW_SDK_COMPILE_MINOR
}
}
namespace = STRAW_APPLICATION_ID
defaultConfig {
applicationId = STRAW_APPLICATION_ID
minSdk { version = release(24) }
targetSdk { version = release(STRAW_SDK_TARGET) }
versionCode = STRAW_VERSION_CODE
versionName = STRAW_VERSION_NAME
resValue("string", "app_name", "Straw")
}
// Explicit signing so CI / release builds reuse ONE keystore instead of
// Gradle's per-machine auto-generated ~/.android/debug.keystore — a fresh
// CI container would otherwise mint a DIFFERENT key and break in-place
// updates for everyone on fdroid. Driven by env so local dev needs no
// setup (unset → Gradle's default debug signing):
// STRAW_KEYSTORE_FILE — path to the keystore
// STRAW_KEYSTORE_PASS / STRAW_KEY_ALIAS / STRAW_KEY_PASS — creds
// Vault: [Sulkta — Straw fdroid signing keystore (debug androiddebugkey)].
val strawKeystoreFile: String? = System.getenv("STRAW_KEYSTORE_FILE")
signingConfigs {
if (strawKeystoreFile != null) {
create("sulkta") {
storeFile = file(strawKeystoreFile)
storePassword = System.getenv("STRAW_KEYSTORE_PASS") ?: "android"
keyAlias = System.getenv("STRAW_KEY_ALIAS") ?: "androiddebugkey"
keyPassword = System.getenv("STRAW_KEY_PASS") ?: "android"
}
}
}
buildTypes {
// R8 enabled on BOTH variants — we publish the debug APK to
// fdroid (com.sulkta.straw.debug) per the existing pipeline,
// and audit-flagged Log.d strips depended on R8 actually
// running on the variant we ship. Keep rules in
// strawApp/proguard-rules.pro cover UniFFI + JNA +
// kotlinx-serialization companions.
debug {
isDebuggable = true
applicationIdSuffix = ".debug"
resValue("string", "app_name", "Straw debug")
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
// Reuse the canonical fdroid keystore in CI/release; fall back to
// Gradle's default debug keystore for local dev (env unset).
if (strawKeystoreFile != null) {
signingConfig = signingConfigs.getByName("sulkta")
}
}
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
buildFeatures {
compose = true
buildConfig = true
resValues = true
}
packaging {
resources {
excludes += setOf(
"META-INF/README.md",
"META-INF/CHANGES",
"META-INF/COPYRIGHT",
"META-INF/INDEX.LIST",
"META-INF/io.netty.versions.properties",
)
}
}
}
dependencies {
// Compose + AndroidX core
implementation(libs.androidx.activity)
implementation(libs.androidx.core)
implementation(libs.jetbrains.compose.runtime)
implementation(libs.jetbrains.compose.foundation)
implementation(libs.jetbrains.compose.material3)
implementation(libs.jetbrains.compose.ui)
implementation("androidx.compose.material:material-icons-extended:1.7.5")
// Lifecycle + ViewModel for Compose
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.10.0")
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.10.0")
// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0")
// Image loading
implementation(libs.coil.compose)
implementation(libs.coil.network.okhttp)
// NewPipeExtractor (JVM/Android-only) + its OkHttp dep
// libs.newpipe.extractor — REMOVED in Path C-6. Extractor is now strawcore
// (Rust + rustypipe via UniFFI). See rust/strawcore/ + the cargoBuild +
// uniffiBindgen Gradle tasks below.
implementation(libs.squareup.okhttp)
// JSON for SponsorBlock + Return YouTube Dislike clients
implementation(libs.kotlinx.serialization.json)
// Media3 ExoPlayer
implementation("androidx.media3:media3-exoplayer:1.4.1")
implementation("androidx.media3:media3-exoplayer-dash:1.4.1")
implementation("androidx.media3:media3-exoplayer-hls:1.4.1")
implementation("androidx.media3:media3-ui:1.4.1")
// Media3 session — MediaSessionService for background audio + lock-screen controls.
implementation("androidx.media3:media3-session:1.4.1")
// Guava ListenableFuture support for awaiting MediaController connect.
implementation("androidx.concurrent:concurrent-futures-ktx:1.2.0")
// WorkManager — periodic background poll of fdroid.sulkta.com index
// for self-update notifications. CoroutineWorker is built into the
// base work-runtime artifact as of 2.10.
implementation(libs.androidx.work.runtime)
// strawcore — Rust YouTube extractor via UniFFI/JNA. Built by the
// cargoBuild + uniffiBindgen tasks below; phase U-2+ exposes search /
// streamInfo / channelInfo to replace NewPipeExtractor.
implementation("net.java.dev.jna:jna:5.14.0@aar")
}
// =============================================================================
// Phase U-1 / Path-C-2 — Rust core build glue.
//
// Two tasks chain into the Android build:
// cargoBuild — cross-compiles rust/strawcore for the four Android ABIs
// via cargo-ndk and drops the .so files in strawApp/src/main/jniLibs/.
// uniffiBindgen — generates the Kotlin bindings from the freshly-built lib
// into strawApp/src/main/java/uniffi/strawcore/.
//
// Both depend on:
// - cargo + rustup with the four Android targets installed
// - cargo-ndk on PATH
// - ANDROID_NDK_HOME pointing at an NDK with the right toolchains
// All of that lives in the Sulkta build container.
// =============================================================================
val rustRoot = file("../rust").absolutePath
val jniLibsDir = file("src/main/jniLibs").absolutePath
val bindingsDir = file("src/main/java").absolutePath
val cargoHome: String = System.getenv("CARGO_HOME") ?: "/caches/cargo"
val cargoBin: String = "$cargoHome/bin/cargo"
val ndkHome: String = System.getenv("ANDROID_NDK_HOME")
?: System.getenv("ANDROID_NDK_ROOT")
?: "/caches/android-sdk/ndk/27.2.12479018"
// Honor CARGO_TARGET_DIR if set (our build container redirects it to a
// cache mount because the container's writable rootfs hits 100% before
// the cross-compile for 4 ABIs finishes). Falls back to the default
// `<workspace>/target`.
val cargoTargetDir: String = System.getenv("CARGO_TARGET_DIR")
?: "$rustRoot/target"
val cargoBuild by tasks.registering(Exec::class) {
group = "rust"
description = "Cross-compile strawcore for all Android ABIs via cargo-ndk."
workingDir = file(rustRoot)
environment("ANDROID_NDK_HOME", ndkHome)
environment("PATH", "$cargoHome/bin:${System.getenv("PATH") ?: ""}")
commandLine = listOf(
cargoBin, "ndk",
"-t", "arm64-v8a",
"-t", "armeabi-v7a",
"-t", "x86",
"-t", "x86_64",
"-o", jniLibsDir,
"build", "--release", "-p", "strawcore",
)
standardOutput = System.out
errorOutput = System.err
}
val cargoBuildHost by tasks.registering(Exec::class) {
group = "rust"
description = "Build host-arch debug strawcore so bindgen can read its UniFFI metadata."
workingDir = file(rustRoot)
environment("PATH", "$cargoHome/bin:${System.getenv("PATH") ?: ""}")
commandLine = listOf(cargoBin, "build", "-p", "strawcore")
standardOutput = System.out
errorOutput = System.err
}
val uniffiBindgen by tasks.registering(Exec::class) {
group = "rust"
description = "Generate Kotlin bindings for strawcore via uniffi-bindgen."
dependsOn(cargoBuildHost)
workingDir = file(rustRoot)
environment("PATH", "$cargoHome/bin:${System.getenv("PATH") ?: ""}")
commandLine = listOf(
cargoBin, "run", "--quiet", "--bin", "uniffi-bindgen", "--",
"generate",
"--library", "$cargoTargetDir/debug/libstrawcore.so",
"--crate", "strawcore",
"--language", "kotlin",
"--no-format",
"--out-dir", bindingsDir,
)
standardOutput = System.out
errorOutput = System.err
}
// Make sure Android's JNI-libs merge picks up the freshly built .so files,
// and Kotlin compilation can resolve the generated bindings.
tasks.matching { it.name.startsWith("merge") && it.name.endsWith("JniLibFolders") }
.configureEach { dependsOn(cargoBuild) }
tasks.matching { it.name.startsWith("compile") && it.name.endsWith("Kotlin") }
.configureEach { dependsOn(uniffiBindgen) }