#!/usr/bin/env bash set -euo pipefail PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)" ANDROID_SDK_ROOT_DEFAULT="$HOME/Library/Android/sdk" EMULATOR_BIN_DEFAULT="$ANDROID_SDK_ROOT_DEFAULT/emulator/emulator" ADB_BIN_DEFAULT="$ANDROID_SDK_ROOT_DEFAULT/platform-tools/adb" AVD_NAME="${1:-lc_arm64}" BOOT_TIMEOUT_SECONDS="${BOOT_TIMEOUT_SECONDS:-120}" ADB_CONNECT_TIMEOUT_SECONDS="${ADB_CONNECT_TIMEOUT_SECONDS:-90}" APP_ID_DEFAULT="com.br.pedifoods.app" if [[ -n "${ANDROID_SDK_ROOT:-}" ]]; then EMULATOR_BIN="$ANDROID_SDK_ROOT/emulator/emulator" ADB_BIN="$ANDROID_SDK_ROOT/platform-tools/adb" else EMULATOR_BIN="$EMULATOR_BIN_DEFAULT" ADB_BIN="$ADB_BIN_DEFAULT" fi ANDROID_HOME="${ANDROID_HOME:-${ANDROID_SDK_ROOT:-$ANDROID_SDK_ROOT_DEFAULT}}" ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT:-$ANDROID_HOME}" export ANDROID_HOME export ANDROID_SDK_ROOT if [[ ! -x "$EMULATOR_BIN" ]]; then echo "Erro: emulator não encontrado em '$EMULATOR_BIN'" exit 1 fi if [[ ! -x "$ADB_BIN" ]]; then echo "Erro: adb não encontrado em '$ADB_BIN'" exit 1 fi if ! command -v skip >/dev/null 2>&1; then echo "Erro: comando 'skip' não encontrado no PATH" exit 1 fi if ! "$EMULATOR_BIN" -list-avds | grep -qx "$AVD_NAME"; then echo "Erro: AVD '$AVD_NAME' não existe. Disponíveis:" "$EMULATOR_BIN" -list-avds exit 1 fi TARGET_SERIAL="$("$ADB_BIN" devices | awk 'NR>1 && $2=="device" {print $1; exit}')" EMULATOR_PID="" "$ADB_BIN" start-server >/dev/null 2>&1 || true if [[ -z "$TARGET_SERIAL" ]]; then echo "Iniciando emulador: $AVD_NAME" nohup "$EMULATOR_BIN" -avd "$AVD_NAME" >/tmp/skip-android-emulator.log 2>&1 & EMULATOR_PID="$!" sleep 2 else BOOTED="$("$ADB_BIN" -s "$TARGET_SERIAL" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r')" if [[ "$BOOTED" == "1" ]]; then echo "Dispositivo já pronto." else echo "Dispositivo conectado, aguardando finalização do boot." fi fi if [[ -z "$TARGET_SERIAL" ]]; then echo "Aguardando ADB conectar..." CONNECT_START_TS="$(date +%s)" while true; do TARGET_SERIAL="$("$ADB_BIN" devices | awk 'NR>1 && $2=="device" {print $1; exit}')" if [[ -n "$TARGET_SERIAL" ]]; then break fi NOW_TS="$(date +%s)" if (( NOW_TS - CONNECT_START_TS >= ADB_CONNECT_TIMEOUT_SECONDS )); then echo "Timeout aguardando ADB conectar (${ADB_CONNECT_TIMEOUT_SECONDS}s)." echo "Estado atual do adb:" "$ADB_BIN" devices || true if [[ -n "$EMULATOR_PID" ]] && ! kill -0 "$EMULATOR_PID" 2>/dev/null; then echo "Processo do emulador encerrou antes da conexão." fi echo "Últimas linhas do log do emulador (/tmp/skip-android-emulator.log):" tail -n 80 /tmp/skip-android-emulator.log || true exit 1 fi sleep 2 done fi echo "Aguardando boot do Android..." START_TS="$(date +%s)" until [[ "$("$ADB_BIN" -s "$TARGET_SERIAL" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r')" == "1" ]]; do NOW_TS="$(date +%s)" if (( NOW_TS - START_TS >= BOOT_TIMEOUT_SECONDS )); then echo "Timeout aguardando boot do Android (${BOOT_TIMEOUT_SECONDS}s) no dispositivo $TARGET_SERIAL." "$ADB_BIN" devices || true tail -n 80 /tmp/skip-android-emulator.log || true exit 1 fi sleep 2 done APP_ID="$(sed -nE 's/^[[:space:]]*PRODUCT_BUNDLE_IDENTIFIER[[:space:]]*=[[:space:]]*([^[:space:]]+).*/\1/p' "$PROJECT_DIR/Skip.env" | head -n1)" APP_ID="${APP_ID:-$APP_ID_DEFAULT}" REQUIRE_FRESH_APK="${REQUIRE_FRESH_APK:-1}" ALLOW_INSTALLED_FALLBACK="${ALLOW_INSTALLED_FALLBACK:-1}" repair_skip_packages_links() { local swift_dir="$PROJECT_DIR/.build/plugins/outputs/pedi-foods/PediFoods/destination/skipstone/PediFoods/src/main/swift" local packages_dir="$swift_dir/Packages" if [[ ! -d "$packages_dir" ]]; then return 0 fi for link_path in "$packages_dir"/*; do [[ -e "$link_path" || -L "$link_path" ]] || continue local pkg_name pkg_name="$(basename "$link_path")" local pkg_manifest="$link_path/Package.swift" if [[ -f "$pkg_manifest" ]]; then continue fi local checkout_path="$PROJECT_DIR/.build/checkouts/$pkg_name" if [[ -f "$checkout_path/Package.swift" ]]; then echo "Reparando link de pacote: $pkg_name -> $checkout_path" rm -rf "$link_path" ln -s "$checkout_path" "$link_path" fi done } clean_skip_generated_outputs() { echo "Limpando artefatos gerados do Skip para recuperação..." rm -rf \ "$PROJECT_DIR/.build/plugins/outputs/skip-android-bridge" \ "$PROJECT_DIR/.build/plugins/outputs/skip-bridge" \ "$PROJECT_DIR/.build/plugins/outputs/skip-foundation" \ "$PROJECT_DIR/.build/plugins/outputs/skip-fuse-ui" \ "$PROJECT_DIR/.build/plugins/outputs/skip-lib" \ "$PROJECT_DIR/.build/plugins/outputs/skip-model" \ "$PROJECT_DIR/.build/plugins/outputs/skip-ui" \ "$PROJECT_DIR/.build/plugins/outputs/skip-unit" } run_skip_export() { cd "$PROJECT_DIR" if skip export --debug --no-ios --android; then repair_skip_packages_links return 0 fi echo "Aviso: skip export falhou na primeira tentativa." clean_skip_generated_outputs repair_skip_packages_links echo "Tentando skip export novamente após limpeza de cache..." if skip export --debug --no-ios --android; then repair_skip_packages_links return 0 fi repair_skip_packages_links return 1 } repair_skip_packages_links find_apk_path() { if [[ -f "$PROJECT_DIR/.build/Android/app/outputs/apk/debug/app-debug.apk" ]]; then echo "$PROJECT_DIR/.build/Android/app/outputs/apk/debug/app-debug.apk" return 0 fi if [[ -f "$PROJECT_DIR/Android/app/build/outputs/apk/debug/app-debug.apk" ]]; then echo "$PROJECT_DIR/Android/app/build/outputs/apk/debug/app-debug.apk" return 0 fi find "$PROJECT_DIR/.build/Android" "$PROJECT_DIR/Android/app/build/outputs/apk/debug" -type f -name '*.apk' 2>/dev/null | head -n1 || true } APK_PATH="$(find_apk_path)" SOURCE_MTIME="$(find "$PROJECT_DIR/Sources" -type f -name '*.swift' -exec stat -f '%m' {} \; 2>/dev/null | sort -nr | head -n1 || echo 0)" SOURCE_MTIME="${SOURCE_MTIME:-0}" APK_MTIME=0 if [[ -n "$APK_PATH" && -f "$APK_PATH" ]]; then APK_MTIME="$(stat -f '%m' "$APK_PATH" 2>/dev/null || echo 0)" fi APK_STALE=0 if (( SOURCE_MTIME > APK_MTIME )); then APK_STALE=1 fi if [[ -z "$APK_PATH" || "${FORCE_EXPORT:-0}" == "1" || "$APK_STALE" == "1" ]]; then if [[ "$APK_STALE" == "1" && "${FORCE_EXPORT:-0}" != "1" ]]; then echo "APK desatualizado em relação ao código fonte. Tentando gerar novo APK..." fi echo "Gerando APK (skip export)..." if ! run_skip_export; then echo "Aviso: skip export falhou. Tentando usar último APK gerado..." if [[ -d "$PROJECT_DIR/Android" ]]; then echo "Tentando fallback via Gradle (:app:assembleDebug)..." ( cd "$PROJECT_DIR/Android" ANDROID_SDK_ROOT="$ANDROID_SDK_ROOT" gradle :app:assembleDebug --no-daemon ) || echo "Aviso: fallback Gradle também falhou." fi fi fi APK_PATH="$(find_apk_path)" if [[ -z "$APK_PATH" ]]; then if [[ "$ALLOW_INSTALLED_FALLBACK" == "1" ]]; then echo "Aviso: APK não encontrado. Tentando abrir app já instalado: $APP_ID" "$ADB_BIN" -s "$TARGET_SERIAL" shell monkey -p "$APP_ID" -c android.intent.category.LAUNCHER 1 echo "App aberto sem reinstalar (fallback)." exit 0 fi echo "Erro: APK não encontrado." exit 1 fi if [[ "$REQUIRE_FRESH_APK" == "1" ]]; then APK_MTIME="$(stat -f '%m' "$APK_PATH" 2>/dev/null || echo 0)" SOURCE_MTIME="$(find "$PROJECT_DIR/Sources" -type f -name '*.swift' -exec stat -f '%m' {} \; 2>/dev/null | sort -nr | head -n1 || echo 0)" if (( SOURCE_MTIME > APK_MTIME )); then if [[ "$ALLOW_INSTALLED_FALLBACK" == "1" ]]; then echo "Aviso: APK continua desatualizado (build novo não gerado)." echo "Abrindo app já instalado para não bloquear o fluxo." "$ADB_BIN" -s "$TARGET_SERIAL" shell monkey -p "$APP_ID" -c android.intent.category.LAUNCHER 1 echo "App aberto sem reinstalar (fallback)." exit 0 fi echo "Erro: APK continua desatualizado (build novo não gerado)." echo "Não vou abrir versão antiga para evitar teste enganoso." echo "Dica: rode com REQUIRE_FRESH_APK=0 para abrir mesmo assim." exit 1 fi fi echo "Instalando APK: $APK_PATH" "$ADB_BIN" -s "$TARGET_SERIAL" install -r "$APK_PATH" LAUNCHABLE="$("$ADB_BIN" -s "$TARGET_SERIAL" shell cmd package resolve-activity --brief "$APP_ID" 2>/dev/null | tr -d '\r' | tail -n1)" if [[ "$LAUNCHABLE" == */* ]]; then echo "Abrindo app: $LAUNCHABLE" "$ADB_BIN" -s "$TARGET_SERIAL" shell am start -n "$LAUNCHABLE" else echo "Abrindo app (fallback monkey): $APP_ID" "$ADB_BIN" -s "$TARGET_SERIAL" shell monkey -p "$APP_ID" -c android.intent.category.LAUNCHER 1 fi echo "App instalado e aberto no Android."