#!/bin/bash # Sync Android source files from src-tauri/android to src-tauri/gen/android # This ensures the generated build directory has the latest source files set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" SOURCE_DIR="$PROJECT_ROOT/src-tauri/android/src/main/java/com/dtourolle/jellytau" TARGET_DIR="$PROJECT_ROOT/src-tauri/gen/android/app/src/main/java/com/dtourolle/jellytau" echo "Syncing Android sources..." echo " From: $SOURCE_DIR" echo " To: $TARGET_DIR" # Create target directory if it doesn't exist mkdir -p "$TARGET_DIR" # Remove old copies of player and security directories rm -rf "$TARGET_DIR/player" "$TARGET_DIR/security" # Copy the directories cp -r "$SOURCE_DIR/player" "$TARGET_DIR/" cp -r "$SOURCE_DIR/security" "$TARGET_DIR/" # Copy individual Kotlin files (like VideoOverlayManager.kt) for kt_file in "$SOURCE_DIR"/*.kt; do if [ -f "$kt_file" ]; then cp "$kt_file" "$TARGET_DIR/" echo " Copied: $(basename "$kt_file")" fi done # Restore the app module build.gradle.kts (media3 deps + release signing config). # gen/android is regenerated by `tauri android init`, so this tracked template is # the source of truth and must be copied back after any (re)generation. APP_GRADLE_SRC="$PROJECT_ROOT/src-tauri/android/app/build.gradle.kts" APP_GRADLE_DST="$PROJECT_ROOT/src-tauri/gen/android/app/build.gradle.kts" if [ -f "$APP_GRADLE_SRC" ]; then cp "$APP_GRADLE_SRC" "$APP_GRADLE_DST" echo " Copied: app/build.gradle.kts" fi # AndroidManifest.xml. `tauri android init` regenerates gen/android from # tauri.conf.json and would drop our hand-maintained entries (media playback # service + permissions, hardware acceleration, picture-in-picture attributes # on MainActivity), so this tracked copy is the source of truth and must be # restored after a regen. Gradle reads ONLY the gen/ copy - there is no # manifest-merger hook here, so this must be the complete manifest. MANIFEST_SRC="$PROJECT_ROOT/src-tauri/android/src/main/AndroidManifest.xml" MANIFEST_DST="$PROJECT_ROOT/src-tauri/gen/android/app/src/main/AndroidManifest.xml" if [ -f "$MANIFEST_SRC" ]; then cp "$MANIFEST_SRC" "$MANIFEST_DST" echo " Copied: app/src/main/AndroidManifest.xml" fi # Custom ProGuard/R8 keep rules. Required for minified release builds: # the player/ and security/ Kotlin classes are loaded by name via JNI from # Rust, so R8 can't see the references and would strip them without this. # build.gradle.kts globs **/*.pro, so dropping it in app/ is enough. PROGUARD_SRC="$PROJECT_ROOT/src-tauri/android/app/proguard-jellytau.pro" PROGUARD_DST="$PROJECT_ROOT/src-tauri/gen/android/app/proguard-jellytau.pro" if [ -f "$PROGUARD_SRC" ]; then cp "$PROGUARD_SRC" "$PROGUARD_DST" echo " Copied: app/proguard-jellytau.pro" fi # Launcher icons / adaptive-icon mipmaps. `tauri android init` generates # low-quality launcher icons from tauri.conf.json (which has no high-res # Android source), so overwrite them with the real committed mipmaps. RES_SRC="$PROJECT_ROOT/src-tauri/android/src/main/res" RES_DST="$PROJECT_ROOT/src-tauri/gen/android/app/src/main/res" if [ -d "$RES_SRC" ]; then for dir in "$RES_SRC"/mipmap-*; do [ -d "$dir" ] || continue name="$(basename "$dir")" mkdir -p "$RES_DST/$name" cp "$dir"/* "$RES_DST/$name/" echo " Copied res: $name" done # values/ (themes.xml): status-bar styling that `tauri android init` does # not generate. Previously this directory was tracked but never copied, so # the theme customizations below never reached a build. if [ -d "$RES_SRC/values" ]; then mkdir -p "$RES_DST/values" cp "$RES_SRC"/values/*.xml "$RES_DST/values/" echo " Copied res: values" fi # xml/ (network_security_config.xml): referenced from the manifest, so a # missing copy fails the resource link rather than degrading quietly. # Merged into Tauri's generated xml/ (which holds file_paths.xml) rather # than replacing it. if [ -d "$RES_SRC/xml" ]; then mkdir -p "$RES_DST/xml" cp "$RES_SRC"/xml/*.xml "$RES_DST/xml/" echo " Copied res: xml" fi # We ship only the color adaptive icon (background + foreground). Drop any # monochrome layer Tauri may generate: the themed-icon monochrome doesn't # render well, and our adaptive-icon xml no longer references it, so a stray # ic_launcher_monochrome.png would just be dead weight. rm -f "$RES_DST"/mipmap-*/ic_launcher_monochrome.png # `tauri android init` also emits the Android Studio DEFAULT adaptive icon # as API-qualified VECTOR drawables: # drawable/ic_launcher_background.xml (solid #3DDC84 green) # drawable-v24/ic_launcher_foreground.xml (the Android robot) # Because drawable-v24 is a more specific match than our unqualified # mipmap-*/ic_launcher_*.png, on API 24+ the vector WINS and the app ships # the green square robot instead of our jellyfish. Remove them so the # adaptive-icon xml resolves @mipmap/ic_launcher_{background,foreground} # to the real committed PNGs. rm -f "$RES_DST"/drawable/ic_launcher_background.xml \ "$RES_DST"/drawable-v24/ic_launcher_foreground.xml \ "$RES_DST"/drawable*/ic_launcher_foreground.xml \ "$RES_DST"/drawable*/ic_launcher_background.xml fi # Gradle wrapper distribution. `tauri android init` regenerates the wrapper # pointing at services.gradle.org, so each build downloads ~130MB of Gradle — # slow, and a hard failure when the CDN drops the connection mid-transfer # ("Unexpected end of file from server"), which is what broke the release APK # job. The builder image ships the matching distribution under /opt/gradle/dist, # so when it's present repoint the wrapper at that local zip and build offline. # Outside the image (dev machines) the properties file is left untouched and the # wrapper downloads as usual. WRAPPER_PROPS="$PROJECT_ROOT/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties" if [ -f "$WRAPPER_PROPS" ]; then WANTED_VERSION="$(sed -n 's#.*/gradle-\([0-9.]*\)-\(bin\|all\)\.zip.*#\1#p' "$WRAPPER_PROPS")" LOCAL_DIST="/opt/gradle/dist/gradle-${WANTED_VERSION}-bin.zip" if [ -n "$WANTED_VERSION" ] && [ -f "$LOCAL_DIST" ]; then # distributionUrl is a java.util.Properties value: ':' must stay escaped. sed -i "s#^distributionUrl=.*#distributionUrl=file\\\\:///opt/gradle/dist/gradle-${WANTED_VERSION}-bin.zip#" \ "$WRAPPER_PROPS" echo " Gradle wrapper -> local distribution ($WANTED_VERSION, offline)" elif [ -n "$WANTED_VERSION" ]; then echo " Gradle wrapper: $WANTED_VERSION not in image, will download" fi fi echo "✓ Android sources synced successfully"