- ChatBubble: useActionSheet replaces custom Modal (native iOS popup, Android bottom sheet) - DM mode (isDM prop): hides like-count, shows Insta-style heart badge under bubble when liked - Group chat unchanged - Cleanup: remove unused Modal/Platform imports, sheet styles, actionsOpen state - deploy.sh: auto-detect ANDROID_HOME + auto-create local.properties for local Gradle - NEXT_RELEASE.md: DM reactions release note - Includes other staged work across binder-mac, marketing, ops/mdm, ios/
432 lines
13 KiB
Bash
Executable File
432 lines
13 KiB
Bash
Executable File
#!/bin/bash
|
||
# dev.sh — ReBreak Native Development Tooling
|
||
#
|
||
# SUBCOMMANDS:
|
||
# ./dev.sh default: ios (Metro + Xcode)
|
||
# ./dev.sh ios iOS Dev (Metro + Xcode Workspace / Simulator)
|
||
# ./dev.sh android Android Dev (Metro + Gradle build + install)
|
||
# ./dev.sh metro Nur Metro starten
|
||
# ./dev.sh clean iOS: Nuclear clean (Pods, DerivedData, Archives)
|
||
# ./dev.sh install ios Build Release + Install auf iPhone USB
|
||
# ./dev.sh install android Build Debug APK + Install auf Android Device
|
||
#
|
||
# FLAGS (ios):
|
||
# --device Build auf physisches iPhone via USB
|
||
# --simulator Build auf iOS Simulator (default)
|
||
# --xcode Nur Xcode öffnen (manueller Build)
|
||
# --wifi Metro mit --host lan (für WiFi-Dev auf iPhone)
|
||
#
|
||
# FLAGS (android):
|
||
# --no-build Skip Gradle build, nur install last APK
|
||
# --no-launch Install but don't auto-launch
|
||
#
|
||
# FLAGS (metro):
|
||
# --keep Cache behalten (kein --clear)
|
||
#
|
||
# FLAGS (clean):
|
||
# --build + iOS build am Ende
|
||
# --xcode + Xcode öffnen am Ende
|
||
#
|
||
# BEISPIELE:
|
||
# # iOS Dev auf Simulator:
|
||
# ./dev.sh ios
|
||
#
|
||
# # iOS Dev auf physischem iPhone via USB:
|
||
# ./dev.sh ios --device
|
||
#
|
||
# # iOS Dev auf iPhone via WiFi (Metro LAN):
|
||
# ./dev.sh ios --wifi
|
||
#
|
||
# # Android Dev:
|
||
# ./dev.sh android
|
||
#
|
||
# # Nur Metro starten:
|
||
# ./dev.sh metro
|
||
#
|
||
# # iOS Clean + Rebuild:
|
||
# ./dev.sh clean --build
|
||
#
|
||
# # Release-Build auf iPhone installieren:
|
||
# ./dev.sh install ios
|
||
|
||
set -euo pipefail
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||
IOS_DIR="$SCRIPT_DIR/ios"
|
||
ANDROID_DIR="$SCRIPT_DIR/android"
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# Color Output
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
if [[ -t 1 ]]; then
|
||
BOLD=$(tput bold)
|
||
GREEN=$(tput setaf 2)
|
||
YELLOW=$(tput setaf 3)
|
||
RED=$(tput setaf 1)
|
||
BLUE=$(tput setaf 4)
|
||
RESET=$(tput sgr0)
|
||
else
|
||
BOLD="" GREEN="" YELLOW="" RED="" BLUE="" RESET=""
|
||
fi
|
||
|
||
log() { echo "${BLUE}==>${RESET} ${BOLD}$*${RESET}"; }
|
||
ok() { echo "${GREEN}✓${RESET} $*"; }
|
||
warn() { echo "${YELLOW}⚠${RESET} $*" >&2; }
|
||
error() { echo "${RED}✗${RESET} ${BOLD}$*${RESET}" >&2; }
|
||
die() { error "$*"; exit 1; }
|
||
|
||
section() {
|
||
echo ""
|
||
echo "${BOLD}$*${RESET}"
|
||
echo "${BOLD}────────────────────────────────────────────────────────────${RESET}"
|
||
}
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# ENV Defaults
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
export REBREAK_ENABLE_FAMILY_CONTROLS="${REBREAK_ENABLE_FAMILY_CONTROLS:-1}"
|
||
export EXPO_PUBLIC_ENABLE_DEBUG="${EXPO_PUBLIC_ENABLE_DEBUG:-1}"
|
||
export REBREAK_DEV="${REBREAK_DEV:-0}"
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# Commands
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
cmd_ios() {
|
||
local MODE="simulator"
|
||
local WIFI=false
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case "$1" in
|
||
--device) MODE="device"; shift ;;
|
||
--simulator) MODE="simulator"; shift ;;
|
||
--xcode) MODE="xcode"; shift ;;
|
||
--wifi) WIFI=true; shift ;;
|
||
*) die "Unbekannter Flag für 'ios': $1" ;;
|
||
esac
|
||
done
|
||
|
||
section "iOS Dev Mode"
|
||
|
||
if $WIFI; then
|
||
log "Metro: WiFi-Modus (--host lan)"
|
||
echo ""
|
||
echo "Mac LAN-IP:"
|
||
ipconfig getifaddr en0 2>/dev/null || ipconfig getifaddr en1 2>/dev/null || echo " (kein WiFi/Ethernet detected)"
|
||
echo ""
|
||
echo "Falls dev-client Metro nicht automatisch findet:"
|
||
echo " im iPhone-Launcher → 'Enter URL manually' → http://<LAN-IP>:8081"
|
||
echo ""
|
||
log "Killing old Metro on port 8081..."
|
||
lsof -ti:8081 | xargs kill -9 2>/dev/null || true
|
||
echo ""
|
||
exec pnpm expo start --host lan --clear --dev-client
|
||
fi
|
||
|
||
case "$MODE" in
|
||
xcode)
|
||
log "Opening Xcode Workspace..."
|
||
osascript -e 'tell application "Xcode" to close every window whose name contains "Rebreak.xcodeproj"' 2>/dev/null || true
|
||
open -a Xcode "$IOS_DIR/ReBreak.xcworkspace"
|
||
ok "Xcode geöffnet — Cmd+R für Build & Run"
|
||
echo ""
|
||
echo "ℹ️ Metro: separat starten via './dev.sh metro' falls noch nicht läuft"
|
||
;;
|
||
|
||
device)
|
||
log "Building für physisches iPhone (USB)..."
|
||
pnpm expo run:ios --device
|
||
;;
|
||
|
||
simulator)
|
||
log "Building für iOS Simulator..."
|
||
pnpm expo run:ios
|
||
;;
|
||
esac
|
||
}
|
||
|
||
cmd_android() {
|
||
local BUILD=true
|
||
local LAUNCH=true
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case "$1" in
|
||
--no-build) BUILD=false; shift ;;
|
||
--no-launch) LAUNCH=false; shift ;;
|
||
*) die "Unbekannter Flag für 'android': $1" ;;
|
||
esac
|
||
done
|
||
|
||
section "Android Dev Mode"
|
||
|
||
command -v adb >/dev/null 2>&1 || die "adb nicht gefunden — brew install --cask android-platform-tools"
|
||
|
||
local DEVICE_COUNT
|
||
DEVICE_COUNT=$(adb devices | grep -E '[[:space:]]device$' | grep -c '.' || true)
|
||
|
||
if [[ "$DEVICE_COUNT" -eq 0 ]]; then
|
||
warn "Kein Android-Gerät via ADB verbunden"
|
||
echo ""
|
||
adb devices
|
||
echo ""
|
||
echo "Mögliche Ursachen:"
|
||
echo " - USB nicht angeschlossen / Kabel nur Strom"
|
||
echo " - USB-Debugging auf dem Phone aus"
|
||
echo " - 'Diesem Computer vertrauen?' Dialog noch nicht bestätigt"
|
||
exit 1
|
||
fi
|
||
|
||
if $BUILD; then
|
||
log "Building Debug APK..."
|
||
(cd "$ANDROID_DIR" && ./gradlew assembleDebug --console=plain)
|
||
fi
|
||
|
||
local APK="$ANDROID_DIR/app/build/outputs/apk/debug/app-debug.apk"
|
||
[[ -f "$APK" ]] || die "APK nicht gefunden: $APK"
|
||
|
||
log "Installing APK..."
|
||
adb install -r -d "$APK"
|
||
|
||
if $LAUNCH; then
|
||
log "Launching App..."
|
||
adb shell monkey -p org.rebreak.app -c android.intent.category.LAUNCHER 1 >/dev/null 2>&1 || {
|
||
warn "Launch via monkey schlug fehl — App ist installiert, manuell öffnen"
|
||
}
|
||
fi
|
||
|
||
ok "Android Dev Build abgeschlossen"
|
||
}
|
||
|
||
cmd_metro() {
|
||
local CLEAR_FLAG="--clear"
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case "$1" in
|
||
--keep) CLEAR_FLAG=""; shift ;;
|
||
*) die "Unbekannter Flag für 'metro': $1" ;;
|
||
esac
|
||
done
|
||
|
||
section "Metro Bundler"
|
||
|
||
log "Killing existing Metro on port 8081..."
|
||
lsof -iTCP:8081 -sTCP:LISTEN -n -P 2>/dev/null | awk 'NR>1 {print $2}' | sort -u | xargs kill -9 2>/dev/null || true
|
||
pkill -f "expo start" 2>/dev/null || true
|
||
pkill -f "react-native/cli/build" 2>/dev/null || true
|
||
|
||
if [[ -n "$CLEAR_FLAG" ]]; then
|
||
log "Starting Metro mit --clear (Cache reset)..."
|
||
else
|
||
log "Starting Metro (Cache behalten)..."
|
||
fi
|
||
|
||
exec npx expo start $CLEAR_FLAG
|
||
}
|
||
|
||
cmd_clean() {
|
||
local POST_ACTION=""
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case "$1" in
|
||
--build) POST_ACTION="build"; shift ;;
|
||
--xcode) POST_ACTION="xcode"; shift ;;
|
||
*) die "Unbekannter Flag für 'clean': $1" ;;
|
||
esac
|
||
done
|
||
|
||
section "iOS Nuclear Clean"
|
||
|
||
log "rm -rf ios/Pods ios/Podfile.lock ios/build"
|
||
rm -rf "$IOS_DIR/Pods" "$IOS_DIR/Podfile.lock" "$IOS_DIR/build"
|
||
|
||
local DERIVED_DATA="$HOME/Library/Developer/Xcode/DerivedData"
|
||
if [[ -d "$DERIVED_DATA" ]]; then
|
||
log "rm -rf DerivedData/Rebreak-*"
|
||
rm -rf "$DERIVED_DATA"/Rebreak-* 2>/dev/null || true
|
||
fi
|
||
|
||
local ARCHIVES_DIR="$HOME/Library/Developer/Xcode/Archives"
|
||
if [[ -d "$ARCHIVES_DIR" ]]; then
|
||
local before_count
|
||
before_count=$(find "$ARCHIVES_DIR" -maxdepth 2 -type d -iname "*rebreak*.xcarchive" 2>/dev/null | wc -l | tr -d ' ')
|
||
log "Cleaning Xcode Archives (Rebreak, >24h) — vorher: $before_count Stk"
|
||
find "$ARCHIVES_DIR" -maxdepth 2 -type d -iname "*rebreak*.xcarchive" -mtime +1 -exec rm -rf {} + 2>/dev/null || true
|
||
find "$ARCHIVES_DIR" -maxdepth 1 -type d -empty -delete 2>/dev/null || true
|
||
fi
|
||
|
||
log "pnpm expo prebuild --clean"
|
||
pnpm expo prebuild --clean
|
||
|
||
log "cd ios && pod install"
|
||
(cd "$IOS_DIR" && pod install)
|
||
|
||
ok "Clean abgeschlossen"
|
||
|
||
case "$POST_ACTION" in
|
||
build)
|
||
echo ""
|
||
log "Building + Running..."
|
||
pnpm ios
|
||
;;
|
||
xcode)
|
||
echo ""
|
||
log "Opening Xcode..."
|
||
osascript -e 'tell application "Xcode" to close every window whose name contains "Rebreak.xcodeproj"' 2>/dev/null || true
|
||
open -a Xcode "$IOS_DIR/ReBreak.xcworkspace"
|
||
ok "Xcode geöffnet — Cmd+R für Build & Run"
|
||
;;
|
||
"")
|
||
echo ""
|
||
echo "Nächste Schritte:"
|
||
echo " ./dev.sh ios # Build & Run"
|
||
echo " ./dev.sh ios --xcode # Xcode öffnen"
|
||
;;
|
||
esac
|
||
}
|
||
|
||
cmd_install_ios() {
|
||
section "iOS Standalone Install"
|
||
|
||
local CONFIGURATION="Release"
|
||
|
||
command -v xcrun >/dev/null 2>&1 || die "Xcode Command-Line-Tools fehlen — xcode-select --install"
|
||
|
||
local XCTRACE_OUT
|
||
XCTRACE_OUT=$(xcrun xctrace list devices 2>&1)
|
||
|
||
local ONLINE
|
||
ONLINE=$(printf '%s\n' "$XCTRACE_OUT" \
|
||
| awk '/^== Devices ==/{f=1; next} /^== /{f=0} f' \
|
||
| grep -E "iPhone|iPad" || true)
|
||
|
||
if [[ -z "$ONLINE" ]]; then
|
||
error "Kein iPhone/iPad ONLINE"
|
||
echo ""
|
||
echo "Setup:"
|
||
echo " - iPhone via USB anschließen + entsperren"
|
||
echo " - 'Diesem Computer vertrauen?' am iPhone bestätigen"
|
||
echo " - Xcode öffnen, dort 'Use for Development' aktivieren"
|
||
exit 1
|
||
fi
|
||
|
||
log "Gerät online: $(printf '%s\n' "$ONLINE" | head -1)"
|
||
log "Building iOS Release bundle + installing on device..."
|
||
echo ""
|
||
echo "(Erster Release-Build dauert 5-10 min wegen Pod-Install + Bundle)"
|
||
echo ""
|
||
|
||
npx expo run:ios --device --configuration "$CONFIGURATION"
|
||
|
||
ok "App läuft jetzt standalone auf deinem iPhone"
|
||
echo "Backend: https://staging.rebreak.org"
|
||
echo "Free-Account: 7 Tage gültig, danach Skript erneut laufen lassen"
|
||
}
|
||
|
||
cmd_install_android() {
|
||
section "Android Standalone Install"
|
||
|
||
local SKIP_BUILD=false
|
||
local LAUNCH=true
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case "$1" in
|
||
--no-build) SKIP_BUILD=true; shift ;;
|
||
--no-launch) LAUNCH=false; shift ;;
|
||
*) die "Unbekannter Flag für 'install android': $1" ;;
|
||
esac
|
||
done
|
||
|
||
command -v adb >/dev/null 2>&1 || die "adb nicht gefunden — brew install --cask android-platform-tools"
|
||
|
||
local DEVICE_COUNT
|
||
DEVICE_COUNT=$(adb devices | grep -E '[[:space:]]device$' | grep -c '.' || true)
|
||
|
||
if [[ "$DEVICE_COUNT" -eq 0 ]]; then
|
||
error "Kein Android-Gerät via ADB"
|
||
adb devices
|
||
exit 1
|
||
fi
|
||
|
||
local APK="$ANDROID_DIR/app/build/outputs/apk/debug/app-debug.apk"
|
||
|
||
if ! $SKIP_BUILD; then
|
||
log "Building debug APK..."
|
||
(cd "$ANDROID_DIR" && ./gradlew assembleDebug --console=plain)
|
||
fi
|
||
|
||
[[ -f "$APK" ]] || die "APK nicht gefunden: $APK"
|
||
|
||
log "Installing $APK..."
|
||
adb install -r -d "$APK"
|
||
|
||
if $LAUNCH; then
|
||
log "Launching App..."
|
||
adb shell monkey -p org.rebreak.app -c android.intent.category.LAUNCHER 1 >/dev/null 2>&1 || {
|
||
warn "Launch schlug fehl — App ist installiert, manuell öffnen"
|
||
}
|
||
fi
|
||
|
||
ok "Fertig"
|
||
}
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# Main
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
COMMAND="${1:-ios}"
|
||
shift || true
|
||
|
||
case "$COMMAND" in
|
||
ios)
|
||
cmd_ios "$@"
|
||
;;
|
||
|
||
android)
|
||
cmd_android "$@"
|
||
;;
|
||
|
||
metro)
|
||
cmd_metro "$@"
|
||
;;
|
||
|
||
clean)
|
||
cmd_clean "$@"
|
||
;;
|
||
|
||
install)
|
||
local PLATFORM="${1:-}"
|
||
shift || true
|
||
case "$PLATFORM" in
|
||
ios) cmd_install_ios "$@" ;;
|
||
android) cmd_install_android "$@" ;;
|
||
*)
|
||
error "Unbekannte install-Platform: $PLATFORM"
|
||
echo "Verfügbar: ios, android"
|
||
exit 1
|
||
;;
|
||
esac
|
||
;;
|
||
|
||
-h|--help)
|
||
awk '/^#!/{next} /^#/{sub(/^# ?/, ""); print; next} {exit}' "$0"
|
||
exit 0
|
||
;;
|
||
|
||
*)
|
||
error "Unbekanntes Subcommand: $COMMAND"
|
||
echo ""
|
||
echo "Verfügbare Commands:"
|
||
echo " ios iOS Dev (Metro + Xcode/Simulator/Device)"
|
||
echo " android Android Dev (Metro + Gradle + Install)"
|
||
echo " metro Nur Metro starten"
|
||
echo " clean iOS Nuclear Clean"
|
||
echo " install ios Release-Build auf iPhone installieren"
|
||
echo " install android Debug-APK auf Android installieren"
|
||
echo ""
|
||
echo "Nutze --help für Details"
|
||
exit 1
|
||
;;
|
||
esac
|