Files
linux-on-android-without-root/provision/install-termux.sh
T
StefanandClaude Opus 5 eeab61a0a4 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>
2026-08-09 18:39:27 +02:00

198 lines
8.0 KiB
Bash
Executable File

#!/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