tv-deploy covers the normal workflow. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
android-webview-kiosk
Fullscreen WebView kiosk for Android TV. Shows configurable web pages
defined in webviews.yaml. Target device: Sony Bravia KD-65XE9305 (Android 8.0).
Built for remote launch via the Bravia REST IP-control API, driven by Control4.
Webviews
Defined in webviews.yaml at repo root:
weather:
url: https://grafana.c3c.cz/public-dashboards/...
label: Weather # shown in Bravia launcher
house_condition:
url: http://grafana.c3c.cz/public-dashboards/...
label: House Condition
Each entry produces a separate APK with a unique applicationId
(cz.c3c.webviewkiosk.<name>). Names must be valid Gradle identifiers
(letters, digits, underscores — no hyphens).
Build
# all flavors
gradle --no-daemon :app:assembleRelease
# single flavor
gradle --no-daemon :app:assembleWeatherRelease
APKs: app/build/outputs/apk/<flavor>/release/<flavor>-release.apk
Sideload
- TV one-time: Settings → About → press Build 7× → Developer options → enable ADB debugging.
adb connect <tv-ip>:5555adb install -r app/build/outputs/apk/weather/release/weather-release.apk
Fresh install (first time or changing applicationId):
adb uninstall cz.c3c.webviewkiosk.<flavor>
adb install app/build/outputs/apk/<flavor>/release/<flavor>-release.apk
Upgrades: bump versionCode in app/build.gradle.kts, rebuild, reinstall
with -r. Same committed keystore = no uninstall needed.
Remote launch (Sony Bravia IP control)
TV prerequisite: IP control auth = "Normal and Pre-Shared Key", Remote start enabled (wake from deep standby).
Each webview flavor has its own URI — retrieve per-flavor URIs via
getApplicationList. Example for weather (cz.c3c.webviewkiosk.weather):
com.sony.dtv.cz.c3c.webviewkiosk.weather.cz.c3c.webviewkiosk.weather.MainActivity
setActiveApp alone wakes the TV from standby — no separate
setPowerStatus call is needed. The Control4 driver can use a single call:
curl -s -X POST http://$TV_IP/sony/appControl \
-H "X-Auth-PSK: $PSK" -H 'Content-Type: application/json' \
-d '{"method":"setActiveApp","id":601,"version":"1.0","params":[{"uri":"<flavor-uri>"}]}'
If the TV is already on, setActiveApp brings the kiosk to the foreground.
If in standby, it wakes and launches directly.
For reference, the two-step sequence (if needed for other integrations):
# 1. wake (optional — setActiveApp does this implicitly)
curl -s -X POST http://$TV_IP/sony/system \
-H "X-Auth-PSK: $PSK" -H 'Content-Type: application/json' \
-d '{"method":"setPowerStatus","id":55,"version":"1.0","params":[{"status":true}]}'
# 2. launch (~6 s from quick standby, up to ~30 s from deep eco standby)
curl -s -X POST http://$TV_IP/sony/appControl \
-H "X-Auth-PSK: $PSK" -H 'Content-Type: application/json' \
-d '{"method":"setActiveApp","id":601,"version":"1.0","params":[{"uri":"<flavor-uri>"}]}'
Control4: a DriverWorks driver issuing setActiveApp is a separate project.