Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014MGLqt1ukfnarqhut9ifcx
153 lines
8.7 KiB
Markdown
153 lines
8.7 KiB
Markdown
# De iOS-app
|
|
|
|
De app voor iPhone en iPad is dezelfde app als die voor Android. `MijnBesluit.AppUi` (alle
|
|
schermen), `MijnBesluit.Client` en het socketprotocol zijn gedeeld; op iOS draait diezelfde HTML
|
|
in een WKWebView in plaats van een Android WebView. Wat verschilt is alleen wat het toestel zelf
|
|
doet.
|
|
|
|
Dit document gaat over dat verschil, en over wat Apple wil.
|
|
|
|
## Wat er klaarstaat
|
|
|
|
- `net10.0-ios` staat in `MijnBesluit.App.csproj`, maar **standaard uit**. Aanzetten met
|
|
`-p:MetIos=true`, of door `MetIos` blijvend te zetten op de machine die aan een Mac hangt.
|
|
Dat moet wel zo: staat de iOS-doelomgeving er onvoorwaardelijk in, dan wil ook een build van
|
|
alleen de Android-APK de iOS-werkbelasting en een Mac hebben, en struikelt het maken van de
|
|
APK over iets wat er niets mee te maken heeft.
|
|
- `Platforms/iOS/` heeft `AppDelegate.cs`, `Program.cs`, `Info.plist`, `PrivacyInfo.xcprivacy`
|
|
(de privacyverklaring die Apple uit de app leest) en `Entitlements.plist` (Keychain-toegang;
|
|
zonder die kan SecureStorage in de simulator niets bewaren). De csproj wijst er voor iOS naar.
|
|
- `tools/ios-bouwen.sh` voor op de Mac: `controle`, `simulator` of `toestel`.
|
|
- `Toestelslot` heeft een iOS-tak: Face ID of Touch ID via LocalAuthentication, met de code van
|
|
de telefoon als terugval.
|
|
- De gebruikstoelichtingen staan in `Info.plist`.
|
|
|
|
## Eerste keer op de Mac
|
|
|
|
1. Xcode uit de App Store, één keer openen, licentie accepteren.
|
|
2. .NET 10 SDK installeren (https://dotnet.microsoft.com/download).
|
|
3. De repo naar de Mac halen (git of kopiëren) en in de hoofdmap:
|
|
|
|
chmod +x tools/ios-bouwen.sh
|
|
tools/ios-bouwen.sh controle # installeert zo nodig de maui-ios-werkbelasting
|
|
tools/ios-bouwen.sh simulator # bouwt en start in de iPhone-simulator
|
|
|
|
Een simulator heeft geen Apple Developer-account nodig. Een echt toestel kan met een gratis
|
|
Apple-ID ("personal team", 7 dagen geldig, zonder meldingen). TestFlight, App Store en meldingen
|
|
hebben het betaalde Developer Program nodig.
|
|
|
|
Als bouwen mislukt, stuur dan de eerste foutregels op: de eerste build van iOS-code die nog nooit
|
|
gecompileerd is, geeft meestal een handvol kleine dingen (een ontbrekende using, een
|
|
API-naam). `PrivacyInfo.xcprivacy` moet na het bouwen in de `.app` zitten
|
|
(`find . -name PrivacyInfo.xcprivacy`).
|
|
|
|
## Een gehuurde Mac (MacinCloud) zonder beheerrechten
|
|
|
|
Beproefd op 20 oktober 2026: een Managed Server van MacinCloud (Mac mini M2, macOS Tahoe 26.x,
|
|
Xcode 26.6), met Windows via RDP. Daar heb je geen beheerrechten, en de .NET die erop staat heeft
|
|
een kapotte werkbelastinginstelling. Wat wel werkt:
|
|
|
|
1. Een eigen .NET in je eigen map, in dezelfde versie als de systeem-.NET:
|
|
`bash ~/dotnet-install.sh --version 10.0.302 --install-dir ~/dotnet302`
|
|
(script van https://dot.net/v1/dotnet-install.sh), en in elk Terminal-venster:
|
|
`export DOTNET_ROOT=$HOME/dotnet302 PATH=$HOME/dotnet302:$PATH`.
|
|
2. `dotnet workload install maui-ios` daarmee. **Let op de Xcode-versie:** de nieuwste .NET
|
|
(10.0.4xx) levert iOS 27.1 en eist Xcode 27.1 ("requires Xcode 27.1"). De 10.0.3xx-band levert
|
|
iOS 26.5 en past bij Xcode 26.x. Gebruik dus de oudere SDK zolang Xcode 26 de nieuwste stabiele is.
|
|
3. `tools/ios-bouwen.sh simulator`. Het script zet `MetAndroid=false` (anders eist de build de
|
|
Android-werkbelasting) en `CodesignKey=-` (lokale handtekening; de simulator wil geen
|
|
certificaat, maar de Keychain-rechten in `Entitlements.plist` vragen om een handtekening).
|
|
Geef nooit `-p:TargetFrameworks=...` op de opdrachtregel mee: dat gaat ook naar de gedeelde
|
|
projecten (net8.0) en breekt hun herstel.
|
|
|
|
Resultaat: de app bouwt en draait in de iPhone 16 Pro-simulator (iOS 18.0), inclusief inloggen en
|
|
de overzichtsschermen.
|
|
|
|
## Wat er nog moet
|
|
|
|
**Een Mac.** Apple's bouwgereedschap draait alleen op macOS. Visual Studio op Windows verbindt
|
|
er over het netwerk mee ("Pair to Mac", over SSH) en laat de Mac compileren en ondertekenen. Op
|
|
die Mac moet Xcode staan, één keer met de hand geopend zijn, en Remote Login aan. Staat er geen
|
|
Mac, haal `net10.0-ios` dan tijdelijk uit `TargetFrameworks`; Android blijft dan gewoon bouwen.
|
|
|
|
**Het Apple Developer Program**, $99 per jaar. Als organisatie heb je nodig: een echte
|
|
rechtspersoon, een D-U-N-S-nummer daarvoor, een e-mailadres op je eigen domein en een werkende
|
|
website op dat domein. Dat D-U-N-S-nummer heb je voor Google Play ook nodig - vraag het één keer
|
|
aan.
|
|
|
|
**Meldingen via APNs.** `Toestelmeldingen` geeft op iOS nu null terug: geen kenmerk, dus geen
|
|
meldingen, en verder werkt alles. Dat komt erbij zodra het account er is, want het hangt eraan
|
|
vast: een APNs-sleutel, de Push Notifications-capability, een provisioning profile en een
|
|
`Entitlements.plist`.
|
|
|
|
## Een .ipa voor TestFlight en de App Store
|
|
|
|
Kan zodra het Apple Developer Program actief is (Kwik-Bit Automatisering B.V., aangemeld op
|
|
27 oktober 2026, betaald; de accountpagina toont geen "Pending" meer). Stappen, in deze volgorde:
|
|
|
|
1. **Voorwaarden accepteren** op developer.apple.com/account (de nieuwe licentieovereenkomst,
|
|
uiterlijk 14 november 2026). Alleen de accounthouder kan dat. Zonder dit werken Certificates,
|
|
App Store Connect en de API niet meer.
|
|
2. **App-ID registreren**: Certificates, IDs & Profiles > Identifiers > App IDs, bundel-ID
|
|
`nl.mijnbesluit.app` (gelijk aan `ApplicationId`). Capabilities: voorlopig geen extra;
|
|
Push Notifications komt later met APNs.
|
|
3. **Distributiecertificaat** (Apple Distribution) maken: Xcode > Settings > Accounts > het team >
|
|
Manage Certificates > + > Apple Distribution, op de Mac waar je bouwt. De private sleutel
|
|
blijft in de sleutelhanger van die Mac; bij een gehuurde Mac is die weg als de Mac weg is,
|
|
dus bewaar er een export van (met wachtwoord, buiten git).
|
|
4. **App Store-profiel** (Provisioning Profiles > + > App Store Connect) voor `nl.mijnbesluit.app`
|
|
met dat certificaat; downloaden en dubbelklikken op de Mac. Noteer de naam van het profiel.
|
|
5. **App-record** in App Store Connect (Apps > + > Nieuwe app): naam MijnBesluit, bundel-ID
|
|
`nl.mijnbesluit.app`, primaire taal Nederlands, SKU naar keuze.
|
|
6. **Bouwen**: op de Mac, met de namen uit stap 3 en 4:
|
|
|
|
```
|
|
export IOS_SIGN_KEY="Apple Distribution: Kwik-Bit Automatisering B.V. (TEAMID)"
|
|
export IOS_PROFILE="<naam van het profiel>"
|
|
tools/ios-bouwen.sh archief
|
|
```
|
|
|
|
Het script toont eerst welke certificaten en profielen er staan, maakt dan de `.ipa`
|
|
(`dotnet publish`, ios-arm64, Release, `ArchiveOnBuild`) en zegt waar hij staat. Het bouwnummer
|
|
(`ApplicationVersion`) moet bij elke upload hoger zijn dan de vorige.
|
|
7. **Uploaden** met de app Transporter (Mac App Store, gratis): inloggen met het Apple-account,
|
|
`.ipa` erin slepen. Na enkele minuten staat de build onder TestFlight; de exportverklaring en
|
|
de App Privacy-antwoorden volgen in App Store Connect (zie hieronder).
|
|
|
|
Niet gedaan en niet getest: dit script en deze stappen zijn nog nooit tegen Apple gedraaid.
|
|
|
|
## Twee vallen waar je vroeg in loopt
|
|
|
|
**Ontbrekende gebruikstoelichting = de app sluit.** Vraag je om Face ID zonder
|
|
`NSFaceIDUsageDescription` in `Info.plist`, dan sluit iOS de app ter plekke af. Geen foutmelding,
|
|
geen crashmelding die ergens op wijst - hij is gewoon weg. Hetzelfde geldt voor camera, microfoon
|
|
en fotobibliotheek. Ze staan er nu allemaal in; komt er ooit iets bij wat het toestel moet
|
|
vrijgeven, dan hoort de tekst er in dezelfde wijziging bij te staan. Een zelfcontrole bewaakt dat.
|
|
|
|
**De socket op poort 5200.** Dat is een eigen TLS-verbinding en geen URL-verkeer, dus App
|
|
Transport Security gaat er niet over en je hebt er géén ATS-uitzondering voor nodig. Een
|
|
uitzondering toevoegen die je niet nodig hebt levert alleen vragen op bij de beoordeling. Maar
|
|
probeer die verbinding wel vroeg op een echt toestel, en ook over 4G en niet alleen over wifi.
|
|
|
|
## Wat Apple bij het inzenden vraagt
|
|
|
|
- **Account verwijderen in de app.** Verplicht. Staat er al.
|
|
- **App Privacy** - hetzelfde soort formulier als Databeveiliging bij Google. De
|
|
privacyverklaring staat in `Privacytekst.razor`.
|
|
- **Exportverklaring** (`ITSAppUsesNonExemptEncryption`). Deze app versleutelt een kluis, dus dat
|
|
antwoord is niet vanzelfsprekend "nee" zoals bij een app die alleen HTTPS gebruikt. De sleutel
|
|
staat bewust NIET in `Info.plist`: dan vraagt App Store Connect het bij elke inzending en
|
|
beantwoord je het bewust. Zie de toelichting in dat bestand.
|
|
- **Sign in with Apple** is NIET verplicht. Dat geldt alleen als je inloggen via Google of
|
|
Facebook aanbiedt; MijnBesluit doet e-mail met een code.
|
|
|
|
## De volgorde
|
|
|
|
1. D-U-N-S aanvragen voor de B.V. (kan weken duren, en Google Play wacht er ook op)
|
|
2. Apple Developer Program, als organisatie
|
|
3. Mac regelen, Xcode erop, Pair to Mac aan de praat
|
|
4. Bouwen en op een echt toestel zetten
|
|
5. Uitproberen: inloggen met een code, de socket, de kluis, het slot met Face ID
|
|
6. Meldingen via APNs
|
|
7. Inzenden
|