Uitrol 16-10-2026 15:41

This commit is contained in:
jf
2026-10-16 15:41:06 +02:00
parent e9fcd0a10c
commit bf56d8e025
15 changed files with 295 additions and 5 deletions
+23 -1
View File
@@ -14,11 +14,33 @@ Dit document gaat over dat verschil, en over wat Apple wil.
Dat moet wel zo: staat de iOS-doelomgeving er onvoorwaardelijk in, dan wil ook een build van 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 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. APK over iets wat er niets mee te maken heeft.
- `Platforms/iOS/` heeft `AppDelegate.cs`, `Program.cs` en `Info.plist`. - `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 - `Toestelslot` heeft een iOS-tak: Face ID of Touch ID via LocalAuthentication, met de code van
de telefoon als terugval. de telefoon als terugval.
- De gebruikstoelichtingen staan in `Info.plist`. - 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`).
## Wat er nog moet ## Wat er nog moet
**Een Mac.** Apple's bouwgereedschap draait alleen op macOS. Visual Studio op Windows verbindt **Een Mac.** Apple's bouwgereedschap draait alleen op macOS. Visual Studio op Windows verbindt
Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 683 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 765 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

+48
View File
@@ -0,0 +1,48 @@
PLAY STORE-VERMELDING - MijnBesluit (nl.mijnbesluit.app)
Taal: Nederlands (Nederland)
APP-NAAM (max 30 tekens)
MijnBesluit
KORTE BESCHRIJVING (max 80 tekens, nu 77)
Wachtwoorden, wensen en berichten veilig bewaard, vrij te geven als jij wilt.
VOLLEDIGE BESCHRIJVING (max 4000 tekens, nu 2690)
Er zit van alles in je hoofd waar niemand anders bij kan. Het wachtwoord van je e-mail, waar de polissen liggen, hoe je je uitvaart voor je ziet, en de dingen die je nog tegen iemand had willen zeggen. Zolang alles goed gaat maakt dat niet uit. Gaat het niet goed, dan staan de mensen die van je houden met lege handen, op het slechtst denkbare moment.
MijnBesluit is de plek waar dat wél ergens staat. Veilig opgeborgen zolang het van jou alleen is, en beschikbaar op het moment dat jij hebt bepaald.
WAT KUN JE ERMEE?
Je kluis
Bewaar wachtwoorden voor websites en apparaten, de pincode van je telefoon, je sociale media, polissen, documenten en je uitvaartwensen. Alles wordt versleuteld opgeslagen. Per onderdeel kies je zelf of het alleen voor jou is, pas na je overlijden vrijkomt, of op een datum die jij bepaalt.
Je mensen
Maak profielen aan voor de familie en vrienden die erbij horen en nodig ze uit. Zodra iemand de uitnodiging accepteert, is het profiel van hem of haar en vult die persoon zijn of haar eigen MijnBesluit in.
Momenten
Zet een bericht of video klaar voor iemand, om te bezorgen op een datum die jij kiest, of pas wanneer jij er niet meer bent. Een achttiende verjaardag, een huwelijk, of gewoon iets wat je nog wilde zeggen. Je kunt ook berichten ontvangen die een ander voor jou heeft klaargezet.
Je nalatenschap
Bepaal wie straks mag regelen wat er geregeld moet worden. Die persoon krijgt niet zomaar toegang: meerdere mensen moeten onafhankelijk van elkaar melden dat je bent overleden, waaronder iemand die jij zelf hebt aangewezen. Daarna heb jij nog een termijn om te laten weten dat je er gewoon nog bent. Pas als die voorbij is, gaat het open.
HOE VEILIG IS HET?
- Alles wordt versleuteld opgeslagen, ook bijlagen zoals een foto van je polis.
- Je hebt geen wachtwoord nodig: je logt in met je e-mailadres en een code die een kwartier geldig is en maar één keer werkt. Er is dus niets te onthouden, te raden of te hergebruiken.
- Wat je op "alleen voor mijzelf" zet, blijft dat. Je nalatenschapsbeheerder krijgt alleen wat jij hebt vrijgegeven, en pas op het moment dat jij hebt bepaald.
- Er wordt bijgehouden wie wat opent, wijzigt of vrijgeeft.
Volledige zekerheid bestaat niet, en dat beweren we ook niet. Wat we wel doen is elke keuze zo maken dat een fout of een inbraak zo min mogelijk oplevert.
JOUW GEGEVENS, JOUW KEUZE
Een eigen MijnBesluit is gratis. Je kunt alles wat je hebt ingevoerd altijd zelf wijzigen of verwijderen, en je kunt je account en bijbehorende gegevens in de app of via mijnbesluit.nl laten verwijderen.
MijnBesluit is een product van Kwik-Bit Automatisering B.V.
Privacyverklaring: https://mijnbesluit.nl/privacy
GRAFISCHE ELEMENTEN
- App-icoon: icoon-512.png (512 x 512, PNG)
- Featuregraphic: banner-1024x500.png (1024 x 500)
- Schermafbeeldingen: minimaal 2 (telefoon), zie de aanwijzingen in de chat.
+9 -1
View File
@@ -29,7 +29,7 @@
<ApplicationTitle>MijnBesluit</ApplicationTitle> <ApplicationTitle>MijnBesluit</ApplicationTitle>
<ApplicationId>nl.mijnbesluit.app</ApplicationId> <ApplicationId>nl.mijnbesluit.app</ApplicationId>
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion> <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion> <ApplicationVersion>2</ApplicationVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">24.0</SupportedOSPlatformVersion> <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">24.0</SupportedOSPlatformVersion>
@@ -38,6 +38,10 @@
iPhone 6s en nieuwer - toestellen uit 2015. Lager gaan levert je een handvol toestellen iPhone 6s en nieuwer - toestellen uit 2015. Lager gaan levert je een handvol toestellen
op en een soort fouten dat je niet kunt nabootsen. --> op en een soort fouten dat je niet kunt nabootsen. -->
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion> <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
<!-- Alleen voor iOS: Keychain-toegang voor SecureStorage (zie Platforms\iOS\Entitlements.plist).
De Remove+Include hieronder werkt of MAUI het privacybestand nu al vanzelf oppakt of niet. -->
<CodesignEntitlements Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">Platforms\iOS\Entitlements.plist</CodesignEntitlements>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -49,6 +53,10 @@
<MauiIcon Include="Resources\AppIcon\appicon.png" Color="#C1D13F" /> <MauiIcon Include="Resources\AppIcon\appicon.png" Color="#C1D13F" />
<MauiSplashScreen Include="Resources\Splash\splash.png" Color="#faf7f2" BaseSize="128,128" /> <MauiSplashScreen Include="Resources\Splash\splash.png" Color="#faf7f2" BaseSize="128,128" />
<MauiFont Include="Resources\Fonts\*" /> <MauiFont Include="Resources\Fonts\*" />
<!-- Privacyverklaring voor Apple; wordt in de iOS-app gebundeld. -->
<BundleResource Remove="Platforms\iOS\PrivacyInfo.xcprivacy" Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'" />
<BundleResource Include="Platforms\iOS\PrivacyInfo.xcprivacy" LogicalName="PrivacyInfo.xcprivacy" Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -22,6 +22,9 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Camera en galerij, voor foto's bij een kluisitem en video's bij een moment. <!-- Camera en galerij, voor foto's bij een kluisitem en video's bij een moment.
Voor de galerij is geen recht nodig: de app gebruikt de fotokiezer van Android en leest
alleen wat de gebruiker zelf aanwijst. READ_MEDIA_IMAGES/VIDEO horen er daarom niet bij
(Google Play keurt die alleen goed voor apps die de hele galerij nodig hebben).
Hier stond eerder bewust niets: hoe minder rechten, hoe minder er mis kan gaan. Maar Hier stond eerder bewust niets: hoe minder rechten, hoe minder er mis kan gaan. Maar
zonder CAMERA meldt Android dat het toestel niet kan opnemen, en verdwijnt de knop zonder CAMERA meldt Android dat het toestel niet kan opnemen, en verdwijnt de knop
"Video opnemen" uit de app zonder dat er iets misgaat of iets over te zien is. "Video opnemen" uit de app zonder dat er iets misgaat of iets over te zien is.
@@ -29,10 +32,8 @@
Wat er NIET bij staat en ook niet bij hoort: locatie, contacten, en het schrijven naar Wat er NIET bij staat en ook niet bij hoort: locatie, contacten, en het schrijven naar
de opslag van de telefoon. We lezen alleen wat de gebruiker zelf aanwijst. --> de opslag van de telefoon. We lezen alleen wat de gebruiker zelf aanwijst. -->
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<!-- Voor Android 12 en ouder; vanaf 13 doen de twee regels hierboven het werk. --> <!-- Voor Android 12 en ouder. Vanaf Android 13 is dit niet nodig. -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" /> android:maxSdkVersion="32" />
@@ -0,0 +1,18 @@
<?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>
<!-- Zonder dit kan SecureStorage (hier wordt de inlogsleutel in bewaard) in de simulator
niets wegschrijven: de Keychain geeft dan een fout, en de app lijkt bij elke start
uitgelogd. Op een echt toestel komt de toegangsgroep uit het provisioning profile.
$(AppIdentifierPrefix) en $(CFBundleIdentifier) vult de build zelf in. -->
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)$(CFBundleIdentifier)</string>
</array>
<!-- Meldingen (APNs) komen hier later bij, samen met het Developer-account:
<key>aps-environment</key><string>development</string>
Nu NIET toevoegen: zonder betaald account weigert Xcode dan te ondertekenen. -->
</dict>
</plist>
@@ -0,0 +1,92 @@
<?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>
<!-- Privacyverklaring van de app zelf (sinds mei 2024 verplicht voor nieuwe inzendingen).
Apple leest dit bestand uit de app en vergelijkt het met wat je invult bij "App Privacy"
in App Store Connect. Wijkt het af, dan komt er een afwijzing of een waarschuwingsmail.
Pas dit dus aan in dezelfde wijziging als een wijziging in Privacytekst.razor. -->
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array/>
<!-- Gegevens die de app verzamelt. Allemaal gekoppeld aan de gebruiker, nooit voor
tracking, alleen voor de werking van de app. -->
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeEmailAddress</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypePhotosorVideos</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeOtherUserContent</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
</array>
<!-- "Required reason"-API's. Apple wil per categorie weten waarom de app (of het .NET-
laag eronder) ze aanroept. Zonder deze lijst volgt een waarschuwing bij de inzending.
CA92.1 UserDefaults: de app leest en schrijft eigen instellingen (Preferences)
C617.1 bestandstijden: bestanden in de eigen app-container
E174.1 vrije schijfruimte: controle voor het schrijven van bestanden
35F9.1 opstarttijd: tijdmetingen binnen de app (.NET-runtime) -->
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array><string>CA92.1</string></array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array><string>C617.1</string></array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array><string>E174.1</string></array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array><string>35F9.1</string></array>
</dict>
</array>
</dict>
</plist>
+31
View File
@@ -0,0 +1,31 @@
<#
.SYNOPSIS
Start MijnBesluit.Web lokaal (dotnet run) voor de knoppen "W-testen" en "WM-testen" van SideKick.
.DESCRIPTION
SideKick roept dit script verborgen aan en stuurt de uitvoer door naar het eigen venster. Zodra Kestrel
"Now listening on: ..." meldt, opent SideKick zelf de browser (met ?email=... en ?weergave=...).
#>
[CmdletBinding()]
param()
$ErrorActionPreference = 'Stop'
$Project = Split-Path $PSScriptRoot -Parent
$Csproj = Join-Path $Project 'src\MijnBesluit.Web\MijnBesluit.Web.csproj'
if (-not (Test-Path $Csproj)) { throw "MijnBesluit.Web is niet gevonden: $Csproj" }
if (-not (Get-Command dotnet -ErrorAction SilentlyContinue)) {
throw 'dotnet is niet gevonden. Installeer de .NET SDK of open een venster waarin hij in het PATH staat.'
}
$env:ASPNETCORE_ENVIRONMENT = 'Development'
$env:DOTNET_ENVIRONMENT = 'Development'
Write-Host ''
Write-Host 'MijnBesluit lokaal testen' -ForegroundColor Cyan
Write-Host " Project : $Csproj"
Write-Host ''
# Geen --no-build en de uitvoer rechtstreeks naar de console: anders komt "Now listening on" te laat bij SideKick aan.
dotnet run --project $Csproj
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/env bash
# Bouwt (en start) de iOS-app op een Mac.
#
# tools/ios-bouwen.sh controle alleen kijken of de Mac er klaar voor is
# tools/ios-bouwen.sh simulator bouwen en starten in de iPhone-simulator (geen account nodig)
# tools/ios-bouwen.sh toestel bouwen en op een aangesloten iPhone zetten (Apple-ID / team nodig)
#
# Eerste keer: chmod +x tools/ios-bouwen.sh
set -euo pipefail
cd "$(dirname "$0")/.."
PROJECT="src/MijnBesluit.App/MijnBesluit.App.csproj"
TFM="net10.0-ios"
MODUS="${1:-controle}"
stap() { printf '\n==> %s\n' "$*"; }
stop() { printf '\nMISLUKT: %s\n' "$*" >&2; exit 1; }
controle() {
stap "Controle van de Mac"
[[ "$(uname)" == "Darwin" ]] || stop "dit script draait alleen op macOS."
command -v xcodebuild >/dev/null || stop "Xcode ontbreekt. Installeer Xcode uit de App Store."
xcodebuild -version
xcodebuild -checkFirstLaunchStatus >/dev/null 2>&1 \
|| stop "Open Xcode één keer met de hand en accepteer de licentie (of: sudo xcodebuild -runFirstLaunch)."
command -v dotnet >/dev/null || stop ".NET SDK ontbreekt. Installeer .NET 10 van https://dotnet.microsoft.com/download"
dotnet --version
if ! dotnet workload list 2>/dev/null | grep -q '^maui-ios\|^maui '; then
stap "MAUI-werkbelasting voor iOS ontbreekt; installeren"
dotnet workload install maui-ios
fi
dotnet workload list
echo; echo "Mac is klaar."
}
case "$MODUS" in
controle)
controle
;;
simulator)
controle
stap "Bouwen en starten in de simulator"
# Eerst de lijst met simulators tonen, zodat je ziet welke je kunt kiezen.
xcrun simctl list devices available | grep -i iphone | head -5 || true
dotnet build "$PROJECT" -f "$TFM" -p:MetIos=true -t:Run \
-p:RuntimeIdentifier=iossimulator-arm64
;;
toestel)
controle
stap "Aangesloten toestellen"
xcrun devicectl list devices || true
echo
echo "Voor een echt toestel moet in Xcode een team gekozen zijn (Settings > Accounts, Apple-ID"
echo "toevoegen) en moet het toestel in Ontwikkelaarsmodus staan"
echo "(Instellingen > Privacy en beveiliging > Ontwikkelaarsmodus)."
echo "Zonder betaald account werkt dit 7 dagen per installatie, en zonder meldingen."
stap "Bouwen voor het toestel"
dotnet build "$PROJECT" -f "$TFM" -p:MetIos=true \
-p:RuntimeIdentifier=ios-arm64 -p:CodesignKey="Apple Development"
echo
echo "Gebouwd. Installeren gaat het makkelijkst via Visual Studio (Pair to Mac) of"
echo "Xcode > Window > Devices and Simulators, of: dotnet build -t:Run -p:_DeviceName=<UDID>"
;;
*)
stop "onbekende optie '$MODUS' (kies: controle, simulator of toestel)"
;;
esac