{ # android-webview-kiosk — Android TV fullscreen WebView kiosk showing a # hardcoded Grafana dashboard, remote-launched via Sony Bravia IP control. # # Deviation from lab Go template: APK is built impurely (Gradle fetches Maven # deps from the network). No `nix build` output; use nix run instead: # nix run — build all APKs then deploy to TV # nix run .#build — build only # nix run .#deploy — deploy already-built APKs to TV description = "Android TV fullscreen WebView kiosk for the Grafana house dashboard"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/release-26.05"; flake-utils.url = "github:numtide/flake-utils"; }; outputs = { self, nixpkgs, flake-utils, }: flake-utils.lib.eachSystem [ "x86_64-linux" ] ( system: let pkgs = import nixpkgs { inherit system; config = { allowUnfree = true; # Android SDK android_sdk.accept_license = true; }; }; buildToolsVersion = "36.0.0"; androidComposition = pkgs.androidenv.composeAndroidPackages { platformVersions = [ "35" ]; buildToolsVersions = [ buildToolsVersion ]; includeEmulator = false; includeSystemImages = false; includeNDK = false; }; androidSdk = androidComposition.androidsdk; sdkRoot = "${androidSdk}/libexec/android-sdk"; fonts = with pkgs; [ noto-fonts dejavu_fonts freefont_ttf ]; gradleEnv = { ANDROID_HOME = sdkRoot; ANDROID_SDK_ROOT = sdkRoot; JAVA_HOME = "${pkgs.jdk21}"; GRADLE_OPTS = "-Dorg.gradle.project.android.aapt2FromMavenOverride=${sdkRoot}/build-tools/${buildToolsVersion}/aapt2"; FONTCONFIG_FILE = pkgs.makeFontsConf { fontDirectories = fonts; }; }; deployScript = '' trap 'adb disconnect "$TV_IP:5555"' EXIT adb connect "$TV_IP:5555" for apk in app/build/outputs/apk/*/release/*.apk; do adb install -r "$apk" done ''; exportGradleEnv = '' export ANDROID_HOME="${sdkRoot}" export ANDROID_SDK_ROOT="${sdkRoot}" export JAVA_HOME="${pkgs.jdk21}" export GRADLE_OPTS="${gradleEnv.GRADLE_OPTS}" export FONTCONFIG_FILE="${gradleEnv.FONTCONFIG_FILE}" ''; tvDeploy = pkgs.writeShellApplication { name = "tv-deploy"; runtimeInputs = [ pkgs.android-tools ]; text = deployScript; }; buildApp = pkgs.writeShellApplication { name = "build"; runtimeInputs = [ androidSdk pkgs.jdk21 pkgs.gradle_9 ]; text = '' ${exportGradleEnv} gradle --no-daemon :app:test gradle --no-daemon :app:assembleRelease ''; }; buildAndDeploy = pkgs.writeShellApplication { name = "build-and-deploy"; runtimeInputs = [ androidSdk pkgs.jdk21 pkgs.gradle_9 pkgs.android-tools ]; text = '' ${exportGradleEnv} gradle --no-daemon :app:test gradle --no-daemon :app:assembleRelease ${deployScript} ''; }; in { apps = { default = { type = "app"; program = "${buildAndDeploy}/bin/build-and-deploy"; }; build = { type = "app"; program = "${buildApp}/bin/build"; }; deploy = { type = "app"; program = "${tvDeploy}/bin/tv-deploy"; }; }; devShells.default = pkgs.mkShell { packages = [ androidSdk pkgs.jdk21 pkgs.gradle_9 pkgs.imagemagick # banner/icon generation pkgs.android-tools # adb for sideloading tvDeploy ] ++ fonts; inherit (gradleEnv) ANDROID_HOME ANDROID_SDK_ROOT JAVA_HOME GRADLE_OPTS FONTCONFIG_FILE; }; } ); }