Signierte iOS-App gebaut und Luftweg-Installation vorbereitet
Phase 10 Schritt 7 ist damit erledigt. auslieferung/App.ipa, 2,4 MB, Ad-hoc signiert mit "Apple Distribution: Paul Nothaft", Profil gueltig bis 29.08.2027, genau ein eingetragenes Geraet. Zwei Annahmen von heute frueh waren falsch und sind korrigiert: die bezahlte Mitgliedschaft stuft das bestehende Team hoch, statt ein neues anzulegen (die Kennung bleibt RMACS9VLS4), und der Export als Ad-hoc funktioniert einwandfrei. Neue Falle festgehalten: beim ersten Signieren fragt der Schluesselbund per Dialog um Erlaubnis. Bleibt der unbeantwortet, haengt xcodebuild wortlos und endet mit errSecInternalComponent. Die Diagnose steht in AGENTS.md, weil das Symptom von sich aus nirgendwohin zeigt. Neu: scripts/ios-luftweg.sh erzeugt manifest.plist, Installationsseite und Symbole fuer die Uebertragung ueber die Luft. Es verweigert eine Basis-Adresse ohne https, weil iOS sonst erst auf dem Telefon still scheitert. Offen bleibt der Host, der die Dateien ausliefert.
This commit is contained in:
+15
-6
@@ -68,6 +68,17 @@ veröffentlicht**, und dieses Repository bleibt privat. `../design-system/`
|
||||
kommt bewusst ohne diese Dateien aus, weil es nach außen hochgeladen wird —
|
||||
dort niemals Markendateien ablegen.
|
||||
|
||||
## Die signierte App
|
||||
|
||||
`auslieferung/App.ipa` ist der fertige, **Ad-hoc signierte** Stand (Team
|
||||
`RMACS9VLS4`, Profil gültig bis 29.08.2027, nur für das eingetragene iPhone).
|
||||
Neu bauen: `bash scripts/ios-signieren.sh` - baut Webbündel, synchronisiert die
|
||||
Hülle, signiert und legt die `.ipa` wieder hier ab.
|
||||
|
||||
Beim ersten Signieren fragt der Schlüsselbund um Erlaubnis. Dort **„Immer
|
||||
erlauben"** wählen, sonst hängt `xcodebuild` wortlos und endet nach Minuten mit
|
||||
`errSecInternalComponent`.
|
||||
|
||||
## Noch offen
|
||||
|
||||
- Native Hülle selbst: `ios/`/`android/` (von `npx cap add` erzeugt, absichtlich
|
||||
@@ -76,12 +87,10 @@ dort niemals Markendateien ablegen.
|
||||
(Keychain/Keystore) ist dagegen bereits vollständig angebunden
|
||||
(`src/api/ablageNativ.ts`, von `main.tsx` aktiviert) und wird automatisch
|
||||
aktiv, sobald die Hülle existiert
|
||||
- Signierte `.ipa`: `scripts/ios-signieren.sh` baut und signiert in einem
|
||||
Durchlauf, **sobald das iPhone per Kabel am Mac hängt und vertraut ist**.
|
||||
Vorher bricht Apple den Profilabruf ab - das ist die einzige verbleibende
|
||||
Hürde, der Gerätebau selbst läuft fehlerfrei durch. Das Konto ist ein
|
||||
kostenloses Personal Team: die UDID lässt sich nicht auf developer.apple.com
|
||||
nachtragen, und die Signatur verfällt alle 7 Tage
|
||||
- Übertragung über die Luft: `scripts/ios-luftweg.sh https://<host>` erzeugt
|
||||
Manifest und Installationsseite; es fehlt nur noch ein Host, der den Ordner
|
||||
über **HTTPS mit gültigem Zertifikat** ausliefert (`tailscale serve`
|
||||
angedacht, dieser Mac ist dort noch abgemeldet)
|
||||
- QR-Einrichtung als Alternative zum Einfügen des Tokens
|
||||
- Live-Ansicht der laufenden Fahrt: gebaut, aber über
|
||||
`src/funktionen.ts` abgeschaltet, bis der FMM003 echte Werte liefert
|
||||
|
||||
Binary file not shown.
Executable
+124
@@ -0,0 +1,124 @@
|
||||
#!/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>" >&2
|
||||
echo "Beispiel: bash scripts/ios-luftweg.sh https://mein-mac.tailnetname.ts.net" >&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"
|
||||
ZIEL="$APP/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")"
|
||||
|
||||
rm -rf "$ZIEL"
|
||||
mkdir -p "$ZIEL"
|
||||
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"
|
||||
|
||||
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</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>kind</key><string>display-image</string>
|
||||
<key>url</key><string>$BASIS/symbol-192.png</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>kind</key><string>full-size-image</string>
|
||||
<key>url</key><string>$BASIS/symbol-512.png</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&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 "Ausliefern: tailscale serve --bg $ZIEL"
|
||||
echo "Auf dem iPhone in Safari oeffnen: $BASIS/"
|
||||
@@ -32,20 +32,12 @@ set -euo pipefail
|
||||
|
||||
HIER="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
APP="$(dirname "$HIER")"
|
||||
# Absichtlich ohne Vorgabewert. Hier stand bis 2026-08-29 die Kennung des
|
||||
# kostenlosen Personal Teams (RMACS9VLS4). Mit dem Wechsel auf eine bezahlte
|
||||
# Mitgliedschaft entsteht ein *neues* Team mit eigener Kennung - der alte Wert
|
||||
# wuerde also still weiter mit dem kostenlosen Team signieren (7-Tage-Ablauf)
|
||||
# statt mit dem bezahlten. Lieber ein klarer Abbruch als eine App, die nach
|
||||
# einer Woche wortlos stirbt.
|
||||
TEAM="${APPLE_TEAM_ID:-}"
|
||||
if [ -z "$TEAM" ]; then
|
||||
echo "FEHLER: APPLE_TEAM_ID ist nicht gesetzt." >&2
|
||||
echo "Die Team-Kennung steht auf developer.apple.com/account unter" >&2
|
||||
echo "'Membership details' (10 Zeichen, z. B. A1B2C3D4E5). Dann:" >&2
|
||||
echo " APPLE_TEAM_ID=XXXXXXXXXX bash scripts/ios-signieren.sh" >&2
|
||||
exit 1
|
||||
fi
|
||||
# Dieselbe Kennung wie zu Zeiten des kostenlosen Kontos: die bezahlte
|
||||
# Mitgliedschaft hat das bestehende Team hochgestuft, statt ein neues
|
||||
# anzulegen. Zwischenzeitlich stand hier das Gegenteil - widerlegt am
|
||||
# 2026-08-29 durch das ausgestellte Profil (Team RMACS9VLS4, Laufzeit ein
|
||||
# Jahr statt sieben Tage). Ueberschreibbar ueber APPLE_TEAM_ID.
|
||||
TEAM="${APPLE_TEAM_ID:-RMACS9VLS4}"
|
||||
AUSGABE="$APP/ios/build"
|
||||
ARCHIV="$AUSGABE/DataMetric360.xcarchive"
|
||||
|
||||
@@ -74,15 +66,17 @@ xcodebuild \
|
||||
DEVELOPMENT_TEAM="$TEAM" \
|
||||
archive
|
||||
|
||||
# Die Exportart heisst seit Xcode 16 offiziell "debugging"; "development" ist
|
||||
# weiterhin als Synonym gueltig und funktioniert auch mit aelteren Xcode-
|
||||
# Versionen, deshalb bleibt es hier stehen.
|
||||
# Ad-hoc, nicht development: das ist die von Apple vorgesehene Art fuer die
|
||||
# Installation ueber die Luft (siehe ios-luftweg.sh) und deckt den Weg per
|
||||
# Kabel gleich mit ab. Sie verlangt ein Apple-Distribution-Zertifikat, das
|
||||
# -allowProvisioningUpdates bei Bedarf selbst anlegt - moeglich erst seit der
|
||||
# bezahlten Mitgliedschaft. Die Signatur laeuft damit ein Jahr.
|
||||
cat > "$AUSGABE/ExportOptions.plist" <<PLIST
|
||||
<?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>method</key><string>development</string>
|
||||
<key>method</key><string>ad-hoc</string>
|
||||
<key>teamID</key><string>$TEAM</string>
|
||||
<key>signingStyle</key><string>automatic</string>
|
||||
<key>stripSwiftSymbols</key><true/>
|
||||
@@ -97,6 +91,12 @@ xcodebuild -exportArchive \
|
||||
-exportPath "$AUSGABE" \
|
||||
-allowProvisioningUpdates
|
||||
|
||||
# Die fertige .ipa liegt versioniert unter auslieferung/, weil ios/ gitignored
|
||||
# ist und das Ergebnis sonst nur auf diesem einen Mac existierte.
|
||||
mkdir -p "$APP/auslieferung"
|
||||
cp "$AUSGABE/App.ipa" "$APP/auslieferung/App.ipa"
|
||||
|
||||
echo
|
||||
echo "Fertig: $AUSGABE/App.ipa"
|
||||
echo "Aufs Geraet: xcrun devicectl device install app --device <UDID> $AUSGABE/App.ipa"
|
||||
echo "Fertig: $APP/auslieferung/App.ipa"
|
||||
echo "Ueber die Luft: bash scripts/ios-luftweg.sh https://<host>"
|
||||
echo "Per Kabel: xcrun devicectl device install app --device <UDID> $APP/auslieferung/App.ipa"
|
||||
|
||||
Reference in New Issue
Block a user