Bisher schob provision.sh das ganze Repo nach /sdcard. Auf dem Telefon lag damit
eine Kopie, und jede Änderung hätte wieder den PC gebraucht. Jetzt kommt per adb
nur init-phone.sh: es installiert git und klont die Quellen nach ~/hpos. Danach
ist das eine echte Arbeitskopie und Aktualisieren heißt
cd ~/hpos && git pull
Die Repo-Adresse liest provision.sh aus dem origin-Remote und schreibt sie fest
ins übertragene Skript, damit auf einer Bildschirmtastatur nichts abgetippt
werden muss. Bei privaten Repos bietet init-phone.sh an, das Passwort zu
speichern — mit dem ausdrücklichen Hinweis, dass das im Klartext geschieht.
Die Berechtigungen wandern von provision.sh nach install-termux.sh, direkt hinter
die Installation. Eine frisch installierte App ohne Berechtigungen ist eine Falle,
die erst Stunden später zuschnappt: im ersten Gerätelauf als stumme Tonaufnahme
in Beweis S2. RECORD_AUDIO für com.termux wird danach ausdrücklich nachgeprüft,
weil genau daran der Beweis hängt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
246 lines
10 KiB
Bash
Executable File
246 lines
10 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
|
|
|
|
# ── Berechtigungen ───────────────────────────────────────────────────────────
|
|
# Direkt nach der Installation, nicht erst in provision.sh: eine frisch
|
|
# installierte App ohne Berechtigungen ist eine Falle, die erst Stunden später
|
|
# zuschnappt — etwa als stumme Tonaufnahme in Beweis S2.
|
|
#
|
|
# Wichtig ist vor allem RECORD_AUDIO für com.termux SELBST. PulseAudio läuft im
|
|
# Termux-Prozess und öffnet das Mikrofon von dort über OpenSL ES; eine
|
|
# Berechtigung, die nur Termux:API hat, nützt ihm nichts.
|
|
if [ "$FEHLER" = 0 ]; then
|
|
kopf "Berechtigungen"
|
|
erteile() {
|
|
local paket="$1" perm="$2"
|
|
if adb shell pm grant "$paket" "$perm" >/dev/null 2>&1; then
|
|
ok "${perm##*.} → $paket"
|
|
else
|
|
warn "${perm##*.} → $paket (abgelehnt)"
|
|
hint_gegeben=1
|
|
fi
|
|
}
|
|
hint_gegeben=0
|
|
|
|
for p in android.permission.RECORD_AUDIO \
|
|
android.permission.READ_EXTERNAL_STORAGE \
|
|
android.permission.WRITE_EXTERNAL_STORAGE; do
|
|
erteile com.termux "$p"
|
|
done
|
|
for p in android.permission.RECORD_AUDIO \
|
|
android.permission.CAMERA \
|
|
android.permission.ACCESS_FINE_LOCATION \
|
|
android.permission.READ_EXTERNAL_STORAGE \
|
|
android.permission.WRITE_EXTERNAL_STORAGE; do
|
|
erteile com.termux.api "$p"
|
|
done
|
|
|
|
if [ "$hint_gegeben" = 1 ]; then
|
|
hinweis "Abgelehnt heißt meist: die App meldet diese Berechtigung gar nicht an."
|
|
hinweis "Das ist unkritisch, solange RECORD_AUDIO für com.termux durchging."
|
|
fi
|
|
|
|
# Kontrolle statt Vertrauen — genau diese eine Berechtigung entscheidet über S2.
|
|
if adb shell dumpsys package com.termux 2>/dev/null | grep -q 'RECORD_AUDIO.*granted=true'; then
|
|
ok "Nachgeprüft: com.termux darf aufnehmen"
|
|
else
|
|
warn "com.termux hat RECORD_AUDIO NICHT — Beweis S2 wird sonst stumm bleiben."
|
|
hinweis "Auf dem Telefon: Einstellungen → Apps → Termux → Berechtigungen → Mikrofon"
|
|
fi
|
|
fi
|
|
|
|
# ── 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
|