diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index 003a1db..bd7a6f3 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -16,7 +16,7 @@ jobs: with: fetch-depth: 0 - name: Unit tests - run: nix develop --command gradle --no-daemon :app:testReleaseUnitTest + run: nix develop --command gradle --no-daemon :app:test - name: Build release APK run: nix develop --command gradle --no-daemon :app:assembleRelease - uses: actions/upload-artifact@v3 diff --git a/CLAUDE.md b/CLAUDE.md index f703e28..6562162 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,6 +6,7 @@ Runs on the living-room Sony Bravia KD-65XE9305 (Android 8.0, API 26; Android System WebView updates independently via Play Store — currently v138). Launched remotely through the Bravia REST IP-control API by Control4 (driver lives in a separate project). See README.md for the API sequence. +Build toolchain: AGP 9.2.1, Gradle 9 (nixpkgs 26.05), build-tools 36, compileSdk 35, JDK 21. ## Lab project — with deviations @@ -20,21 +21,18 @@ This is a lab project (`lab` skill conventions apply) EXCEPT: ## NixOS aapt2 workaround AGP cannot run the Maven-downloaded aapt2 on NixOS (dynamically linked -generic Linux binary). The flake's dev shell ships a wrapped `gradle` that -always passes `-Dorg.gradle.project.android.aapt2FromMavenOverride=` on the command line; Gradle turns `org.gradle.project.*` system -props into project properties, which is what AGP reads. It must be a CLI -arg: the nixpkgs-25.11 gradle wrapper ignores `GRADLE_OPTS` (fixed -post-25.11, nixpkgs PR #449037 — the flake wrapper can be dropped once -the pin moves past 25.11). No file rewriting; `gradle.properties` stays -untouched. +generic Linux binary). The dev shell sets `GRADLE_OPTS` to pass +`-Dorg.gradle.project.android.aapt2FromMavenOverride=`; +Gradle turns `org.gradle.project.*` system props into project properties, +which is what AGP reads. Works since nixpkgs 26.05 (PR #449037 merged +post-25.11). No file rewriting; `gradle.properties` stays untouched. -## Commands (user-run, from repo root) +## Commands (user-run, from repo root, direnv activates devshell) -- Tests: `nix develop --command gradle --no-daemon :app:testWeatherReleaseUnitTest` -- All APKs: `nix develop --command gradle --no-daemon :app:assembleRelease` +- Tests: `gradle --no-daemon :app:test` +- All APKs: `gradle --no-daemon :app:assembleRelease` → `app/build/outputs/apk//release/-release.apk` -- Single APK: `nix develop --command gradle --no-daemon :app:assembleWeatherRelease` +- Single APK: `gradle --no-daemon :app:assembleWeatherRelease` - Sideload: `adb connect :5555 && adb install -r ` (bump `versionCode` in app/build.gradle.kts first for upgrades) - Fresh install: `adb uninstall cz.c3c.webviewkiosk && adb install ` diff --git a/README.md b/README.md index fc1f196..711ccc6 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,10 @@ Each entry produces a separate APK with a unique `applicationId` ## Build # all flavors - nix develop --command gradle --no-daemon :app:assembleRelease + gradle --no-daemon :app:assembleRelease # single flavor - nix develop --command gradle --no-daemon :app:assembleWeatherRelease + gradle --no-daemon :app:assembleWeatherRelease APKs: `app/build/outputs/apk//release/-release.apk` diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3b748b6..e534245 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -2,7 +2,6 @@ import org.yaml.snakeyaml.Yaml plugins { id("com.android.application") - id("org.jetbrains.kotlin.android") } @Suppress("UNCHECKED_CAST") @@ -11,18 +10,20 @@ val webviews: Map> = android { namespace = "cz.c3c.webviewkiosk" - compileSdk = 34 + compileSdk = 35 + buildToolsVersion = "36.0.0" defaultConfig { applicationId = "cz.c3c.webviewkiosk" minSdk = 26 // Sony KD-65XE9305 final firmware = Android 8.0 - targetSdk = 34 + targetSdk = 35 versionCode = 1 // bump on every release; adb install -r refuses downgrades versionName = "0.1.0" } buildFeatures { buildConfig = true + resValues = true } signingConfigs { @@ -54,22 +55,19 @@ android { } } - @Suppress("DEPRECATION") - applicationVariants.all { - val flavor = productFlavors.first().name - val type = buildType.name - outputs.all { - (this as com.android.build.gradle.internal.api.BaseVariantOutputImpl) - .outputFileName = "$flavor-$type.apk" - } - } - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } - kotlinOptions { - jvmTarget = "17" +} + +androidComponents { + onVariants { variant -> + variant.outputs.forEach { output -> + val flavor = variant.productFlavors.firstOrNull()?.second ?: variant.name + val buildType = variant.buildType ?: "debug" + output.outputFileName.set("$flavor-$buildType.apk") + } } } diff --git a/build.gradle.kts b/build.gradle.kts index ec59988..6bc42af 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,6 +5,5 @@ buildscript { } plugins { - id("com.android.application") version "8.7.3" apply false - id("org.jetbrains.kotlin.android") version "2.0.21" apply false + id("com.android.application") version "9.2.1" apply false } diff --git a/flake.lock b/flake.lock index 9be3f88..eff59f1 100644 --- a/flake.lock +++ b/flake.lock @@ -20,16 +20,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1781214844, - "narHash": "sha256-GiKi1nonuwTHG1mTrwFTllfMSN2rvHQZUgpW0nQX/qM=", + "lastModified": 1781284521, + "narHash": "sha256-AFxK4Q2YbBXehBxJEL0IWTS+pauHY1w6O/GBUijTRF0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "9bc9b4b4e7b1e7ce7ec2a8355b4369541b90cd6a", + "rev": "a06029d13f9b4a70db3aae42d4f233e6f6c92075", "type": "github" }, "original": { "owner": "NixOS", - "ref": "release-25.11", + "ref": "release-26.05", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index 92f492d..883bd5b 100644 --- a/flake.nix +++ b/flake.nix @@ -9,7 +9,7 @@ description = "Android TV fullscreen WebView kiosk for the Grafana house dashboard"; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/release-25.11"; + nixpkgs.url = "github:NixOS/nixpkgs/release-26.05"; flake-utils.url = "github:numtide/flake-utils"; }; @@ -30,10 +30,10 @@ }; }; - buildToolsVersion = "34.0.0"; + buildToolsVersion = "36.0.0"; androidComposition = pkgs.androidenv.composeAndroidPackages { - platformVersions = [ "34" ]; + platformVersions = [ "35" ]; buildToolsVersions = [ buildToolsVersion ]; includeEmulator = false; includeSystemImages = false; @@ -43,36 +43,25 @@ sdkRoot = "${androidSdk}/libexec/android-sdk"; fonts = with pkgs; [ noto-fonts dejavu_fonts freefont_ttf ]; - - # NixOS gotcha: AGP downloads a dynamically-linked aapt2 from Maven - # that can't run on NixOS. android.aapt2FromMavenOverride is a Gradle - # *project* property; `-Dorg.gradle.project.` on the command line - # sets one. It must be a CLI arg, not GRADLE_OPTS: the gradle package - # in nixpkgs 25.11 is a raw `exec java ... GradleMain "$@"` wrapper - # that ignores GRADLE_OPTS (fixed post-25.11 in nixpkgs PR #449037 — - # once we're past 25.11, plain GRADLE_OPTS works and this wrapper can go). - gradle = pkgs.symlinkJoin { - name = "gradle-nixos-aapt2"; - paths = [ pkgs.gradle ]; - nativeBuildInputs = [ pkgs.makeWrapper ]; - postBuild = '' - wrapProgram $out/bin/gradle \ - --add-flags "-Dorg.gradle.project.android.aapt2FromMavenOverride=${sdkRoot}/build-tools/${buildToolsVersion}/aapt2" - ''; - }; in { devShells.default = pkgs.mkShell { packages = [ androidSdk - pkgs.jdk17 - gradle # wrapped, see above + pkgs.jdk21 + pkgs.gradle_9 pkgs.imagemagick # banner/icon generation pkgs.android-tools # adb for sideloading ] ++ fonts; ANDROID_HOME = sdkRoot; ANDROID_SDK_ROOT = sdkRoot; + JAVA_HOME = "${pkgs.jdk21}"; + # NixOS gotcha: AGP downloads a dynamically-linked aapt2 from Maven + # that can't run on NixOS. Set android.aapt2FromMavenOverride via + # GRADLE_OPTS so AGP uses the SDK's aapt2 instead. Works since + # nixpkgs PR #449037 (merged post-25.11, present in 26.05+). + GRADLE_OPTS = "-Dorg.gradle.project.android.aapt2FromMavenOverride=${sdkRoot}/build-tools/${buildToolsVersion}/aapt2"; FONTCONFIG_FILE = pkgs.makeFontsConf { fontDirectories = fonts; }; }; }