Files
audi-app/companion-app/scripts/ios-luftweg.sh
T
tobias 6365136275 Installationslink: kein zweites ? in der Manifest-Adresse
Der Cache-Brecher vom selben Tag stand auch an der Manifest-Adresse INNERHALB
des itms-services-Links. Das zweite ? und = in der Abfrage kann den Wert von
url abschneiden - der Abruf scheitert, und weil iOS die Rueckfrage erst aus dem
geladenen Manifest baut, erscheint gar keine. Auf .ipa und Symbole innerhalb
des Manifests bleibt der Cache-Brecher.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 14:38:40 +02:00

142 lines
5.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# Bereitet die Installation ueber die Luft vor: legt neben der signierten .ipa
# die manifest.plist und eine kleine Installationsseite ab.
#
# bash scripts/ios-luftweg.sh https://mein-mac.tailnetname.ts.net
#
# Warum das noetig ist: iOS installiert eine App nur dann ueber die Luft, wenn
# ein itms-services-Link auf eine manifest.plist zeigt, die wiederum die
# Adresse der .ipa enthaelt. Beide Adressen muessen ueber **HTTPS mit einem
# oeffentlich vertrauenswuerdigen Zertifikat** erreichbar sein - einfaches HTTP
# und selbstsignierte Zertifikate lehnt iOS kommentarlos ab. Home Assistant
# unter /local/ genuegt dafuer nicht, das laeuft im Tailnet unverschluesselt.
#
# Passend dazu und ohne offenen Port: `tailscale serve` liefert ein echtes
# Let's-Encrypt-Zertifikat auf <maschine>.<tailnet>.ts.net aus. Voraussetzung
# ist, dass in der Tailscale-Verwaltung HTTPS-Zertifikate aktiviert sind.
#
# tailscale serve --bg ios/build/luftweg
#
# Danach den ausgegebenen Link auf dem iPhone in **Safari** oeffnen (andere
# Browser reichen itms-services nicht an das System weiter).
set -euo pipefail
if [ $# -lt 1 ]; then
echo "Aufruf: bash scripts/ios-luftweg.sh <basis-url> [zielordner]" >&2
echo "Beispiel: bash scripts/ios-luftweg.sh https://mein-mac.tailnetname.ts.net" >&2
echo "Gitea: bash scripts/ios-luftweg.sh \\" >&2
echo " https://gitea.nothaft.cloud/paul/audi-app/raw/branch/main/companion-app/auslieferung \\" >&2
echo " auslieferung" >&2
exit 1
fi
BASIS="${1%/}"
if [ "${BASIS#https://}" = "$BASIS" ]; then
echo "FEHLER: Die Basis-Adresse muss mit https:// beginnen." >&2
echo "iOS verweigert die Installation ueber die Luft ueber unverschluesseltes HTTP." >&2
exit 1
fi
HIER="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
APP="$(dirname "$HIER")"
IPA="$APP/auslieferung/App.ipa"
# Zweites Argument erlaubt es, direkt in den versionierten Ordner zu schreiben -
# noetig, wenn nicht ein eigener Host ausliefert, sondern das Repository selbst.
ZIEL="$APP/${2:-ios/build/luftweg}"
[ -f "$IPA" ] || { echo "FEHLER: $IPA fehlt - erst scripts/ios-signieren.sh laufen lassen." >&2; exit 1; }
# Version aus der .ipa selbst lesen statt sie hier zu wiederholen: zwei Quellen
# fuer dieselbe Angabe waeren eine zu viel.
AUSPACK="$(mktemp -d)"
trap 'rm -rf "$AUSPACK"' EXIT
unzip -q "$IPA" -d "$AUSPACK"
PLIST="$(find "$AUSPACK/Payload" -maxdepth 2 -name Info.plist | head -1)"
KENNUNG="$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$PLIST")"
VERSION="$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$PLIST")"
mkdir -p "$ZIEL"
[ "$IPA" -ef "$ZIEL/App.ipa" ] || cp "$IPA" "$ZIEL/App.ipa"
cp "$APP/public/symbol-192.png" "$ZIEL/symbol-192.png"
cp "$APP/public/symbol-512.png" "$ZIEL/symbol-512.png"
# Die Adressen tragen die Version als Anhaengsel (?v=...). Sie zeigen sonst bei
# jedem Bau auf dieselbe Zeichenkette, und der Installations-Dienst von iOS haelt
# eine einmal geholte .ipa dann fuer schon bekannt - sichtbar als Wolke mit Pfeil,
# die nie fertig wird, oder als "kann nicht installiert werden". Dieselbe Vorsorge
# trifft das Panel seit jeher fuer sein eigenes Buendel (siehe ota.ts).
cat > "$ZIEL/manifest.plist" <<PLISTENDE
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>items</key>
<array>
<dict>
<key>assets</key>
<array>
<dict>
<key>kind</key><string>software-package</string>
<key>url</key><string>$BASIS/App.ipa?v=$VERSION</string>
</dict>
<dict>
<key>kind</key><string>display-image</string>
<key>url</key><string>$BASIS/symbol-192.png?v=$VERSION</string>
</dict>
<dict>
<key>kind</key><string>full-size-image</string>
<key>url</key><string>$BASIS/symbol-512.png?v=$VERSION</string>
</dict>
</array>
<key>metadata</key>
<dict>
<key>bundle-identifier</key><string>$KENNUNG</string>
<key>bundle-version</key><string>$VERSION</string>
<key>kind</key><string>software</string>
<key>title</key><string>DataMetric360</string>
</dict>
</dict>
</array>
</dict>
</plist>
PLISTENDE
# Das kaufmaennische Und muss in HTML maskiert werden, sonst schneidet Safari
# den Link hinter dem url-Parameter ab.
cat > "$ZIEL/index.html" <<HTMLENDE
<!doctype html>
<html lang="de">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>DataMetric360 installieren</title>
<style>
body { font-family: -apple-system, sans-serif; background: #161b23; color: #eef1f6;
margin: 0; display: grid; place-items: center; min-height: 100vh; }
main { text-align: center; padding: 2rem; }
h1 { font-weight: 300; font-size: 1.5rem; }
a { display: inline-block; margin-top: 1.5rem; padding: 0.9rem 2rem; border-radius: 999px;
background: #eef1f6; color: #161b23; text-decoration: none; font-size: 1.1rem; }
p { color: #8a94a3; font-size: 0.9rem; line-height: 1.5; }
</style>
<main>
<h1>DataMetric360</h1>
<p>Version $VERSION</p>
<a href="itms-services://?action=download-manifest&amp;url=$BASIS/manifest.plist">Installieren</a>
<p>In Safari oeffnen. Nach dem Antippen fragt iOS einmal nach,<br>danach erscheint die App auf dem Startbildschirm.</p>
</main>
</html>
HTMLENDE
echo "Ordner fertig: $ZIEL"
echo
echo "Wenn ein eigener Host ausliefert:"
echo " tailscale serve --bg $ZIEL"
echo " dann auf dem iPhone in Safari oeffnen: $BASIS/"
echo
# Gitea liefert rohe Dateien grundsaetzlich als text/plain aus - die
# index.html wird dort also als Quelltext angezeigt statt gerendert. Deshalb
# hier zusaetzlich der fertige Link zum Einfuegen in die Safari-Adresszeile;
# der funktioniert unabhaengig davon, ob eine Seite drumherum existiert.
echo "Ohne Seite (z. B. aus dem Repository heraus) direkt in Safari einfuegen:"
echo " itms-services://?action=download-manifest&url=$BASIS/manifest.plist"