install-termux.sh: APKs laden und fernzuinstallieren

Termux und seine Plugins teilen sich eine Android-UID (sharedUserId=com.termux).
Android verlangt für Apps mit gemeinsamer UID denselben Signaturschlüssel — und
F-Droid und GitHub signieren verschieden. Wer die Quellen mischt, scheitert an
INSTALL_FAILED_SHARED_USER_INCOMPATIBLE, ohne dass die Meldung erklärt warum.

Das Skript lädt alle vier Apps von GitHub und installiert sie über die bestehende
adb-Verbindung, per WLAN wie per Kabel. Vorhandene Termux-Apps aus fremder Quelle
werden erkannt und auf Nachfrage entfernt — mit deutlicher Warnung, dass dabei
auch das Termux-Dateisystem verschwindet.

GitHub statt F-Droid, weil es dort Termux:X11 in einer sharedUid-Variante gibt.
Die läuft in Termux' Prozessgruppe und erbt dessen Akku-Ausnahmen; die normale
Variante ist eine eigenständige Hintergrund-App, die Android drosselt. Bei ROMs
wie ColorOS ist das der Unterschied zwischen 'läuft über Nacht' und 'war morgens
weg'.

Die Asset-Auswahl arbeitet mit einer Rangfolge statt eines festen Namens:
stabile Veröffentlichungen vor Vorabversionen, und bei termux-app die Variante
apt-android-7 vor dem Altbau apt-android-5, der sonst auf einem aktuellen Gerät
gewählt würde.

Korrektur zur bisherigen Dokumentation: Termux:X11 ist NICHT generell von der
Signaturbindung ausgenommen. Nur die normale Variante ist es, die sharedUid-
Fassung setzt GitHub-Termux voraus.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan
2026-08-09 18:39:27 +02:00
co-authored by Claude Opus 5
parent 915fe53eeb
commit eeab61a0a4
5 changed files with 263 additions and 25 deletions
+3
View File
@@ -10,6 +10,9 @@ spike/*.m4a
# nicht ins Repo rutscht, wenn jemand die Datei woandershin legt. # nicht ins Repo rutscht, wenn jemand die Datei woandershin legt.
bridge-token bridge-token
# Heruntergeladene Termux-APKs (Zwischenspeicher von install-termux.sh)
provision/apk-cache/
# Python-Bytecode (entsteht beim Ausführen von bridge-mini.py) # Python-Bytecode (entsteht beim Ausführen von bridge-mini.py)
__pycache__/ __pycache__/
*.py[cod] *.py[cod]
+2
View File
@@ -44,6 +44,8 @@ Getestet wird auf einem **OnePlus 7 Pro (Snapdragon 855, Adreno 640) mit Stock O
```bash ```bash
# 1. Auf dem PC. Verbindet per USB oder WLAN — das Skript fragt danach. # 1. Auf dem PC. Verbindet per USB oder WLAN — das Skript fragt danach.
# Ein Kabel wird nicht gebraucht: Android 11+ kann Wireless Debugging. # Ein Kabel wird nicht gebraucht: Android 11+ kann Wireless Debugging.
# Fehlt Termux, bietet es an, alle vier Apps herunterzuladen und
# fernzuinstallieren (oder direkt: ./provision/install-termux.sh).
./provision/provision.sh ./provision/provision.sh
# 2. Auf dem Telefon in Termux: # 2. Auf dem Telefon in Termux:
+197
View File
@@ -0,0 +1,197 @@
#!/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/tty || WEG=n
case "${WEG:-n}" in
j|J)
for p in "${VORHANDEN[@]}"; do
if adb uninstall "$p" >/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
+27 -11
View File
@@ -159,21 +159,37 @@ else
Auf dem Telefon einfach im Browser öffnen und die APK installieren. Auf dem Telefon einfach im Browser öffnen und die APK installieren.
"Installation aus unbekannten Quellen" muss für den Browser erlaubt sein. "Installation aus unbekannten Quellen" muss für den Browser erlaubt sein.
TEXT TEXT
if [ "$TROCKEN" != 1 ]; then if [ "$TROCKEN" != 1 ] && [ -x "$HIER/install-termux.sh" ]; then
printf '\n Soll ich die Termux-Seite auf dem Telefon öffnen? [J/n] > ' cat <<'TEXT'
read -r OEFFNEN </dev/tty || OEFFNEN=n
case "${OEFFNEN:-j}" in Das muss aber niemand von Hand machen: install-termux.sh lädt alle vier
Apps von GitHub und installiert sie über die bestehende adb-Verbindung —
per WLAN genauso wie per Kabel.
TEXT
printf '\n Jetzt automatisch installieren? [J/n] > '
read -r AUTOINSTALL </dev/tty || AUTOINSTALL=n
case "${AUTOINSTALL:-j}" in
j|J|"") j|J|"")
adb shell am start -a android.intent.action.VIEW \ if ADB_SERIAL="$ADB_SERIAL" "$HIER/install-termux.sh"; then
-d 'https://f-droid.org/packages/com.termux/' >/dev/null 2>&1 \ ok "Termux ist installiert — weiter mit der Einrichtung."
&& ok "Seite auf dem Telefon geöffnet" \ hinweis "Bitte Termux einmal öffnen, damit es sein Dateisystem anlegt."
|| warn "Konnte den Browser nicht starten — bitte von Hand aufrufen." printf ' Wenn das erledigt ist, Enter drücken > '
read -r _ </dev/tty
else
fehl "Automatische Installation fehlgeschlagen."
exit 1
fi
;;
*)
hinweis "Dann von Hand — danach dieses Skript erneut aufrufen."
exit 1
;; ;;
esac esac
else
printf '\n'
hinweis "Danach dieses Skript erneut aufrufen."
exit 1
fi fi
printf '\n'
hinweis "Danach dieses Skript erneut aufrufen."
exit 1
fi fi
# ── Hintergrundbetrieb, Android-Standardebene ──────────────────────────────── # ── Hintergrundbetrieb, Android-Standardebene ────────────────────────────────
+34 -14
View File
@@ -26,23 +26,43 @@ Scheitert er, ist das ein früher Warnschuss fürs Gesamtkonzept, kein Detail.
### Termux installieren ### Termux installieren
**Nicht aus dem Play Store** — die Fassung dort wird seit Jahren nicht mehr gepflegt und ```bash
ist für dieses Projekt unbrauchbar. Alle Bestandteile müssen aus **derselben Quelle** ./provision/install-termux.sh
stammen, sonst passen die Signaturen nicht zusammen und die Zusatz-Apps verweigern den Dienst. ```
| App | F-Droid | GitHub | Lädt alle vier Apps von GitHub und installiert sie über die bestehende
adb-Verbindung — per WLAN genauso wie per Kabel. `provision.sh` bietet das von
selbst an, wenn Termux fehlt.
#### Warum das ein eigenes Skript verdient
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 — und F-Droid und GitHub signieren verschieden. Mischt man die Quellen, scheitert
die Installation mit `INSTALL_FAILED_SHARED_USER_INCOMPATIBLE`. Das ist der mit Abstand
häufigste Stolperstein beim Einrichten.
Das Skript wählt durchgängig **GitHub**, aus zwei Gründen:
- Termux:X11 gibt es dort in einer **sharedUid-Variante**. Die läuft in Termux'
Prozessgruppe und erbt dessen Akku-Ausnahmen. Die normale Variante ist eine
eigenständige Hintergrund-App, die Android drosselt — bei ROMs wie ColorOS der
Unterschied zwischen „läuft über Nacht" und „war morgens weg".
- Eine Quelle, ein Schlüssel, keine Mischmasch-Fehler.
**Nicht aus dem Play Store** — die Fassung dort wird seit Jahren nicht mehr gepflegt.
Von Hand geht es natürlich auch, dann aber konsequent alles aus **einer** Quelle:
| App | GitHub | F-Droid |
|---|---|---| |---|---|---|
| Termux | [f-droid.org](https://f-droid.org/packages/com.termux/) | [Releases](https://github.com/termux/termux-app/releases/latest) | | Termux | [Releases](https://github.com/termux/termux-app/releases/latest) | [f-droid.org](https://f-droid.org/packages/com.termux/) |
| Termux:API | [f-droid.org](https://f-droid.org/packages/com.termux.api/) | [Releases](https://github.com/termux/termux-api/releases/latest) | | Termux:API | [Releases](https://github.com/termux/termux-api/releases/latest) | [f-droid.org](https://f-droid.org/packages/com.termux.api/) |
| Termux:Boot | [f-droid.org](https://f-droid.org/packages/com.termux.boot/) | [Releases](https://github.com/termux/termux-boot/releases/latest) | | Termux:Boot | [Releases](https://github.com/termux/termux-boot/releases/latest) | [f-droid.org](https://f-droid.org/packages/com.termux.boot/) |
| Termux:X11 | — | [Releases](https://github.com/termux/termux-x11/releases) (Nightly, `app-universal-debug.apk`) | | Termux:X11 | [Releases](https://github.com/termux/termux-x11/releases) | — |
Termux:X11 gibt es nur bei GitHub. Wer die anderen drei von F-Droid nimmt, muss Bei F-Droid-Termux muss für Termux:X11 die **normale** Variante genommen werden
Termux:X11 trotzdem von dort holen — das ist in Ordnung, weil Termux:X11 eine (`termux-x11-universal-debug.apk`), nicht die sharedUid-Fassung.
eigenständige App ohne Signaturbindung an Termux ist.
Fehlt Termux, bietet `provision.sh` an, die Download-Seite direkt auf dem Telefon
zu öffnen.
**Ein USB-Kabel wird nicht gebraucht.** Ab Android 11 geht die Ersteinrichtung über **Ein USB-Kabel wird nicht gebraucht.** Ab Android 11 geht die Ersteinrichtung über
WLAN — `provision.sh` fragt beim Start, ob per Kabel oder per Netz verbunden werden WLAN — `provision.sh` fragt beim Start, ob per Kabel oder per Netz verbunden werden