plugins { id 'com.android.application' } apply plugin: 'kotlin-android' apply plugin: 'org.jetbrains.kotlin.plugin.compose' def gitValue = { List arguments -> try { def output = providers.exec { commandLine(['git'] + arguments) workingDir rootProject.projectDir ignoreExitValue = true } output.result.get().exitValue == 0 ? output.standardOutput.asText.get().trim() : '' } catch (Exception ignored) { '' } } def buildLabel = providers.environmentVariable('DROIDDECK_BUILD_LABEL').getOrNull() if (buildLabel == null || buildLabel.trim().isEmpty()) { def eventName = providers.environmentVariable('GITHUB_EVENT_NAME').getOrNull() def eventPath = providers.environmentVariable('GITHUB_EVENT_PATH').getOrNull() if (eventName == 'pull_request_target' && eventPath) { try { def eventFile = layout.file(providers.provider { new File(eventPath) }) def eventText = providers.fileContents(eventFile).asText.get() def pullRequest = new groovy.json.JsonSlurper().parseText(eventText).pull_request if (pullRequest?.number && pullRequest?.head?.sha) { buildLabel = "pr${pullRequest.number} at ${pullRequest.head.sha.take(7)}" } } catch (Exception ignored) { } } if (buildLabel == null || buildLabel.trim().isEmpty()) { def branch = providers.environmentVariable('GITHUB_REF_NAME').getOrNull() ?: gitValue(['branch', '--show-current']) ?: 'local' def commit = providers.environmentVariable('GITHUB_SHA').getOrNull() ?.take(7) ?: gitValue(['rev-parse', '--short=7', 'HEAD']) ?: 'unknown' buildLabel = "${branch} at ${commit}" } } def escapedBuildLabel = buildLabel.replace('\\', '\\\\').replace('"', '\\"') android { namespace 'com.droiddeck.launcher' compileSdk 34 // The NDK is pinned by property so CI can hand in whatever the runner already has rather than // downloading a second copy; see gradle.properties. ndkVersion project.findProperty('ndkVersion') ?: '27.3.13750724' defaultConfig { applicationId "com.droiddeck.launcher" minSdkVersion 26 // 28 is not a leftover. An app on targetSdk 29+ runs in a domain that may not execute a // file out of its own data directory, and this app's entire job is to exec a rootfs: // proot, gamescope, the Steam client and everything it launches all live under files/. targetSdkVersion 28 versionCode 7 versionName "0.1.6" buildConfigField "String", "BUILD_LABEL", "\"${escapedBuildLabel}\"" ndk { abiFilters 'arm64-v8a' } externalNativeBuild { cmake { arguments '-DANDROID_STL=c++_shared' } } } externalNativeBuild { cmake { path 'src/main/cpp/CMakeLists.txt' version '3.22.1' } } signingConfigs { // AOSP testkey (android@android.com), the same key Bannerlator ships with. It is publicly // known, so it proves nothing about who built the apk - what it buys is ONE stable // signature: every build installs over the last one instead of asking the user to // uninstall first. v1 (JAR) + v2 + v3 so every installer and Android version accepts it. testkey { storeFile file("${rootDir}/keystore/testkey.p12") storeType "PKCS12" storePassword "android" keyAlias "testkey" keyPassword "android" enableV1Signing = true enableV2Signing = true enableV3Signing = true } } buildTypes { debug { minifyEnabled false signingConfig signingConfigs.testkey } release { minifyEnabled false signingConfig signingConfigs.testkey } } lint { // targetSdk 28 is deliberate and structural: an app on 29+ may not execute a file out of // its own data directory, and executing a rootfs is the whole of what this app does. Lint // fails a release build over it because Google Play will not accept an sdk that old - // true, and not something this app can trade away. Every other check stays on. disable 'ExpiredTargetSdkVersion' } packagingOptions { jniLibs { // The PulseAudio daemon is executed from the native library directory and its // libraries are read out of the apk by the class loader: both want the old, // uncompressed-and-extracted layout. useLegacyPackaging = true // Prefer the PTY helper built by this app's NDK target over Termux's prebuilt copy. pickFirsts += ['**/libtermux.so'] } } buildFeatures { compose true buildConfig true } compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { jvmTarget = '17' } } dependencies { // The runtime tarball is a zstd-compressed tar. implementation 'com.github.luben:zstd-jni:1.5.2-3@aar' implementation 'org.apache.commons:commons-compress:1.20' // The UI: every menu, dialog and overlay is Compose. The session's SurfaceView and the // on-screen pad are Views underneath it, which is what they are in every Compose app. implementation platform('androidx.compose:compose-bom:2024.02.00') implementation 'androidx.compose.ui:ui' implementation 'androidx.compose.material3:material3' implementation 'androidx.activity:activity-compose:1.8.2' // The File Manager, Bannerlator's: its icon set, image thumbnails and the coroutines it // copies on. Same versions as Bannerlator so the screen stays a straight copy. implementation 'androidx.compose.material:material-icons-extended' implementation 'io.coil-kt:coil-compose:2.6.0' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3' // Android terminal view/emulator used by the in-session secondary-display Linux shell. implementation 'com.termux.termux-app:terminal-view:0.118.0' }