#!/usr/bin/env bash # HPOS — Termux samt Zusatz-Apps installieren, alles aus einer Quelle. # # Termux und seine Plugins teilen sich eine Android-UID (sharedUserId=com.termux). # Android verlangt, dass Apps mit gemeinsamer UID mit DEMSELBEN Schlüssel signiert # sind. F-Droid und GitHub signieren verschieden — mischt man beide, scheitert die # Installation mit INSTALL_FAILED_SHARED_USER_INCOMPATIBLE. Das ist der mit Abstand # häufigste Stolperstein beim Einrichten und der Grund, warum es dieses Skript gibt. # # Gewählt wird GitHub, aus zwei Gründen: # · Termux:X11 gibt es dort in einer sharedUid-Variante. Die läuft in Termux' # Prozessgruppe und erbt damit die Akku-Ausnahmen, die provision.sh setzt. # Die normale Variante ist eine eigenständige Hintergrund-App, die Android # drosselt — bei ROMs wie ColorOS ein spürbarer Unterschied. # · Eine Quelle, ein Schlüssel, keine Mischmasch-Fehler. # # Aufruf: ./provision/install-termux.sh set -uo pipefail source "$(dirname "$0")/lib.sh" CACHE="$(cd "$(dirname "$0")" && pwd)/apk-cache" mkdir -p "$CACHE" # Paket → GitHub-Repo → Muster (Rangfolge, Komma-getrennt) → Beschreibung # # Reihenfolge der Einträge zählt: die Haupt-App muss zuerst installiert werden, # sonst findet der Plugin-Install keine gemeinsame UID vor. # # Bei termux-app gibt es mehrere Varianten je Release. 'apt-android-7' ist die # heutige Fassung für Android 7 und neuer; 'apt-android-5' ist der Altbau für # ältere Geräte und würde auf einem aktuellen Telefon unnötig zurückfallen. # Deshalb eine Rangfolge statt eines einzelnen Musters. APPS=( "com.termux|termux/termux-app|apt-android-7-github-debug_universal.apk,_universal.apk|Termux (Haupt-App)" "com.termux.api|termux/termux-api|.apk|Termux:API (Sensoren, Mikrofon, Taschenlampe)" "com.termux.boot|termux/termux-boot|.apk|Termux:Boot (Autostart nach Neustart)" "com.termux.x11|termux/termux-x11|universal-sharedUid-debug.apk|Termux:X11 (Grafikausgabe)" ) kopf "Werkzeug" adb_einrichten || true hinweis "adb $(adb_version "$ADB_BIN")" if ! geraet_waehlen; then fehl "Kein Gerät verbunden." hinweis "Erst verbinden: ./provision/adb-wireless.sh (oder Kabel anschließen)" exit 1 fi ok "Gerät: ${ADB_SERIAL} ($(geraet_beschreiben "$ADB_SERIAL"))" # ── Bestandsaufnahme ───────────────────────────────────────────────────────── # Was schon da ist, stammt möglicherweise aus einer anderen Quelle. Von außen # lässt sich das nicht zuverlässig unterscheiden, deshalb wird gefragt statt geraten. kopf "Vorhandene Termux-Apps" VORHANDEN=() while IFS= read -r p; do [ -n "$p" ] && VORHANDEN+=("$p") done < <(adb shell pm list packages 2>/dev/null | tr -d '\r' | sed 's/^package://' | grep -E '^com\.termux' || true) if [ ${#VORHANDEN[@]} -eq 0 ]; then ok "Nichts vorinstalliert — sauberer Start." else for p in "${VORHANDEN[@]}"; do printf ' %s\n' "$p"; done cat <<'TEXT' Diese Apps sind bereits installiert. Stammen sie aus einer anderen Quelle (etwa F-Droid), scheitert jede weitere Installation von GitHub an den unterschiedlichen Signaturen. ACHTUNG: Deinstallieren löscht auch das Termux-Dateisystem und damit ein eventuell vorhandenes Linux-Rootfs. Vor einer bestehenden HPOS-Installation unbedingt vorher ein Backup ziehen. TEXT printf '\n Vorhandene Termux-Apps deinstallieren? [j/N] > ' read -r WEG /dev/null 2>&1; then ok "entfernt: $p" else warn "konnte $p nicht entfernen"; fi done ;; *) hinweis "Behalten. Falls die Installation gleich scheitert, ist das der Grund." ;; esac fi # ── Herunterladen ──────────────────────────────────────────────────────────── asset_url() { local repo="$1" muster="$2" curl -sfL "https://api.github.com/repos/$repo/releases" \ | python3 -c ' import json, sys muster = [m for m in sys.argv[1].split(",") if m] try: releases = json.load(sys.stdin) except Exception: sys.exit(1) def suche(kandidaten): """Erstes Muster gewinnt, erst dann wird das nächste Release betrachtet — sonst nähme man aus einem älteren Release die bevorzugte Variante statt aus dem neueren die zweitbeste.""" for r in kandidaten: for m in muster: for a in r.get("assets", []): if a["name"].endswith(m): return a["browser_download_url"] return None # Stabile Veröffentlichungen zuerst, Vorabversionen nur als Rückfallebene. # Termux:X11 erscheint ausschließlich als "nightly", ist dort aber nicht als # prerelease markiert und wird deshalb schon im ersten Durchgang gefunden. stabil = [r for r in releases if not r.get("prerelease")] vorab = [r for r in releases if r.get("prerelease")] url = suche(stabil) or suche(vorab) if not url: sys.exit(1) print(url) ' "$muster" } kopf "Herunterladen" DATEIEN=() for eintrag in "${APPS[@]}"; do IFS='|' read -r paket repo muster beschreibung <<<"$eintrag" printf ' %s\n' "$beschreibung" URL=$(asset_url "$repo" "$muster") if [ -z "$URL" ]; then fehl "Kein passendes Release-Asset gefunden ($repo, Muster: $muster)" hinweis "Releases von Hand prüfen: https://github.com/$repo/releases" exit 1 fi DATEI="$CACHE/$(basename "$URL")" if [ -s "$DATEI" ]; then ok "bereits im Zwischenspeicher: $(basename "$DATEI")" else if curl -fL --progress-bar -o "$DATEI.teil" "$URL" && mv "$DATEI.teil" "$DATEI"; then ok "geladen: $(basename "$DATEI")" else rm -f "$DATEI.teil" fehl "Download fehlgeschlagen: $URL" exit 1 fi fi DATEIEN+=("$paket|$DATEI|$beschreibung") done # ── Installieren ───────────────────────────────────────────────────────────── # Reihenfolge wie in APPS: Haupt-App zuerst, dann die Plugins. kopf "Installieren" FEHLER=0 for eintrag in "${DATEIEN[@]}"; do IFS='|' read -r paket datei beschreibung <<<"$eintrag" printf ' %s … ' "$beschreibung" AUS=$(adb install -r -g "$datei" 2>&1) if printf '%s' "$AUS" | grep -qi 'success'; then printf '%s✓%s\n' "$C_OK" "$C_OFF" else printf '%s✗%s\n' "$C_ERR" "$C_OFF" printf '%s' "$AUS" | tail -3 | sed 's/^/ /' FEHLER=1 case "$AUS" in *SHARED_USER_INCOMPATIBLE*|*签名*|*signatures*) hinweis "Genau der Signaturkonflikt: es ist noch eine Termux-App aus einer" hinweis "anderen Quelle installiert. Skript erneut aufrufen und beim" hinweis "Deinstallieren mit 'j' antworten." ;; esac fi done # ── Abschluss ──────────────────────────────────────────────────────────────── kopf "Ergebnis" adb shell pm list packages 2>/dev/null | tr -d '\r' | grep -E '^package:com\.termux' | sed 's/^package:/ /' if [ "$FEHLER" = 0 ]; then ok "Alle vier Apps installiert, alle aus derselben Quelle." cat <<'TEXT' Nächste Schritte: 1. Termux einmal öffnen, damit es sein Dateisystem anlegt. 2. ./provision/provision.sh — Akku- und Hintergrundeinstellungen 3. Auf dem Telefon: bash spike/00-bootstrap-termux.sh Termux:X11 ist die sharedUid-Variante: sie läuft in Termux' Prozessgruppe und erbt dessen Akku-Ausnahmen. Das ist bei ROMs, die Hintergrund-Apps aggressiv beenden, der Unterschied zwischen "läuft über Nacht" und "war morgens weg". TEXT else warn "Nicht alles hat geklappt — siehe oben." exit 1 fi