diff --git a/README.md b/README.md index ff45b43..1318a1c 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,43 @@ Release bundle (for Play): ------------------------------------------------------------------------ +## 🔧 Local Build/Test Scripts + +Validate host environment: + + ./scripts/check-android-env.sh all + +Install SDK components (requires sdkmanager): + + ./scripts/bootstrap-android.sh + +Build + lint + unit tests: + + ./scripts/build-debug.sh + +Connected/device tests: + + ./scripts/test-connected.sh + +------------------------------------------------------------------------ + +# 📦 Play Store Ready + +Release build includes: + +- Resource shrinking +- Code minification +- Material 3 theming +- Clean package namespace + +Before Play upload: + +- Configure signing keystore +- Increment versionCode +- Generate .aab + +------------------------------------------------------------------------ + # 🏠 Home Assistant Integration RelayTV integrates directly with Home Assistant via: diff --git a/app/src/main/res/menu/main_menu.xml b/app/src/main/res/menu/main_menu.xml index 42aa575..9865072 100644 --- a/app/src/main/res/menu/main_menu.xml +++ b/app/src/main/res/menu/main_menu.xml @@ -1,13 +1,14 @@ - + + app:showAsAction="ifRoom" /> + app:showAsAction="ifRoom" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 032b0f3..f943c32 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -8,4 +8,5 @@ Select RelayTV server Name Base URL + Reload diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/scripts/bootstrap-android.sh b/scripts/bootstrap-android.sh new file mode 100755 index 0000000..cc0de4c --- /dev/null +++ b/scripts/bootstrap-android.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" + +INSTALL_EMULATOR="${INSTALL_EMULATOR:-0}" +ANDROID_PLATFORM="${ANDROID_PLATFORM:-android-34}" +ANDROID_BUILD_TOOLS="${ANDROID_BUILD_TOOLS:-34.0.0}" +ANDROID_SYSTEM_IMAGE="${ANDROID_SYSTEM_IMAGE:-system-images;android-34;google_apis;x86_64}" + +say() { printf '%s\n' "$*"; } + +find_sdkmanager() { + if command -v sdkmanager >/dev/null 2>&1; then + command -v sdkmanager + return 0 + fi + + local sdk="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}" + if [[ -n "${sdk}" ]]; then + local candidate="${sdk}/cmdline-tools/latest/bin/sdkmanager" + if [[ -x "${candidate}" ]]; then + printf '%s\n' "${candidate}" + return 0 + fi + fi + return 1 +} + +ensure_sdk_root() { + if [[ -n "${ANDROID_SDK_ROOT:-}" ]]; then + mkdir -p "${ANDROID_SDK_ROOT}" + return + fi + if [[ -n "${ANDROID_HOME:-}" ]]; then + export ANDROID_SDK_ROOT="${ANDROID_HOME}" + mkdir -p "${ANDROID_SDK_ROOT}" + return + fi + export ANDROID_SDK_ROOT="${HOME}/Android/Sdk" + mkdir -p "${ANDROID_SDK_ROOT}" +} + +ensure_gradlew_executable() { + if [[ ! -x "${REPO_ROOT}/gradlew" ]]; then + chmod +x "${REPO_ROOT}/gradlew" + fi +} + +ensure_sdk_root +ensure_gradlew_executable + +SDKMANAGER_BIN="$(find_sdkmanager || true)" +if [[ -z "${SDKMANAGER_BIN}" ]]; then + say "sdkmanager not found." + say "Install Android cmdline-tools and add sdkmanager to PATH, then rerun." + exit 1 +fi + +PACKAGES=( + "platform-tools" + "platforms;${ANDROID_PLATFORM}" + "build-tools;${ANDROID_BUILD_TOOLS}" + "cmdline-tools;latest" +) + +if [[ "${INSTALL_EMULATOR}" == "1" ]]; then + PACKAGES+=("emulator" "${ANDROID_SYSTEM_IMAGE}") +fi + +say "Using Android SDK root: ${ANDROID_SDK_ROOT}" +say "Installing packages:" +printf ' - %s\n' "${PACKAGES[@]}" + +"${SDKMANAGER_BIN}" --sdk_root="${ANDROID_SDK_ROOT}" "${PACKAGES[@]}" +"${SDKMANAGER_BIN}" --sdk_root="${ANDROID_SDK_ROOT}" --licenses < <(yes) + +say +say "Bootstrap complete." +say "Tip: run ./scripts/check-android-env.sh all" diff --git a/scripts/build-debug.sh b/scripts/build-debug.sh new file mode 100755 index 0000000..1027fb7 --- /dev/null +++ b/scripts/build-debug.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" + +cd "${REPO_ROOT}" + +if [[ ! -x "./scripts/check-android-env.sh" ]]; then + chmod +x "./scripts/check-android-env.sh" +fi +./scripts/check-android-env.sh build + +if [[ ! -x "./gradlew" ]]; then + chmod +x ./gradlew +fi + +if [[ "$#" -gt 0 ]]; then + TASKS=("$@") +else + TASKS=("clean" "assembleDebug" "lint" "testDebugUnitTest") +fi + +echo "Running Gradle tasks: ${TASKS[*]}" +./gradlew --no-daemon "${TASKS[@]}" diff --git a/scripts/check-android-env.sh b/scripts/check-android-env.sh new file mode 100755 index 0000000..1853c76 --- /dev/null +++ b/scripts/check-android-env.sh @@ -0,0 +1,119 @@ +#!/usr/bin/env bash +set -euo pipefail + +MODE="${1:-all}" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" + +failures=0 +warnings=0 + +say() { printf '%s\n' "$*"; } +ok() { say "[ok] $*"; } +warn() { say "[warn] $*"; warnings=$((warnings + 1)); } +fail() { say "[fail] $*"; failures=$((failures + 1)); } + +need_cmd() { + local name="$1" + if command -v "${name}" >/dev/null 2>&1; then + ok "Found command: ${name}" + else + fail "Missing command: ${name}" + fi +} + +sdk_dir_from_local_properties() { + local lp="${REPO_ROOT}/local.properties" + [[ -f "${lp}" ]] || return 1 + local raw + raw="$(grep -E '^sdk\.dir=' "${lp}" | tail -n1 | cut -d'=' -f2- || true)" + [[ -n "${raw}" ]] || return 1 + + # Gradle escaping uses backslashes. This normalizes common Linux/macOS forms. + local unescaped="${raw//\\:/:}" + unescaped="${unescaped//\\\\/\\}" + printf '%s\n' "${unescaped}" + return 0 +} + +detect_sdk_root() { + if [[ -n "${ANDROID_SDK_ROOT:-}" ]]; then + printf '%s\n' "${ANDROID_SDK_ROOT}" + return 0 + fi + if [[ -n "${ANDROID_HOME:-}" ]]; then + printf '%s\n' "${ANDROID_HOME}" + return 0 + fi + if sdk_dir_from_local_properties >/dev/null 2>&1; then + sdk_dir_from_local_properties + return 0 + fi + return 1 +} + +validate_mode() { + case "${MODE}" in + build|connected|all) ;; + *) + say "Usage: $0 [build|connected|all]" + exit 2 + ;; + esac +} + +check_base_tools() { + need_cmd java + need_cmd javac +} + +check_connected_tools() { + need_cmd adb +} + +check_sdk() { + local sdk_root="" + if sdk_root="$(detect_sdk_root)"; then + if [[ -d "${sdk_root}" ]]; then + ok "Android SDK root: ${sdk_root}" + else + fail "Android SDK path does not exist: ${sdk_root}" + fi + else + fail "Android SDK root not found. Set ANDROID_SDK_ROOT (or ANDROID_HOME)." + fi + + if command -v sdkmanager >/dev/null 2>&1; then + ok "Found command: sdkmanager" + else + warn "sdkmanager not in PATH. bootstrap script can still work if cmdline-tools path is set manually." + fi +} + +check_gradle_wrapper() { + if [[ -f "${REPO_ROOT}/gradlew" ]]; then + ok "Found gradle wrapper" + else + fail "Missing gradlew in repo root" + fi +} + +validate_mode + +say "Checking Android environment (${MODE}) for ${REPO_ROOT}" +check_base_tools +check_gradle_wrapper +check_sdk + +if [[ "${MODE}" == "connected" || "${MODE}" == "all" ]]; then + check_connected_tools +fi + +if [[ "${failures}" -gt 0 ]]; then + say + fail "Environment check failed with ${failures} issue(s) and ${warnings} warning(s)." + exit 1 +fi + +say +ok "Environment check passed with ${warnings} warning(s)." diff --git a/scripts/test-connected.sh b/scripts/test-connected.sh new file mode 100755 index 0000000..a5a355a --- /dev/null +++ b/scripts/test-connected.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" + +cd "${REPO_ROOT}" + +if [[ ! -x "./scripts/check-android-env.sh" ]]; then + chmod +x "./scripts/check-android-env.sh" +fi +./scripts/check-android-env.sh connected + +if [[ ! -x "./gradlew" ]]; then + chmod +x ./gradlew +fi + +adb start-server >/dev/null +DEVICES="$(adb devices | awk 'NR>1 && $2=="device" {print $1}')" +if [[ -z "${DEVICES}" ]]; then + echo "No connected Android device/emulator detected." + echo "Connect a device (adb devices) or start an emulator, then rerun." + exit 1 +fi + +echo "Connected devices:" +printf ' - %s\n' ${DEVICES} + +if [[ "$#" -gt 0 ]]; then + TASKS=("$@") +else + TASKS=("connectedDebugAndroidTest") +fi + +echo "Running Gradle tasks: ${TASKS[*]}" +./gradlew --no-daemon "${TASKS[@]}"