Compare commits

..
9 Commits
Author SHA1 Message Date
jf fc31949d84 Uitrol 10-11-2026 16:37 2026-11-10 16:39:27 +01:00
jf 95e496134b Uitrol 01-11-2026 13:32 2026-11-01 13:32:49 +01:00
jf 2b429cb36d App Store: iPhone-schermen 2026-11-01 12:53:51 +01:00
jfandClaude Sonnet 5.5 8eb0badd5d iOS: voorlopig alleen iPhone, bouwnummer 4
De iPad-weergave toont een lege pagina; iPad later weer toevoegen.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014MGLqt1uKfNARQHut9ifcx
2026-11-01 11:38:56 +00:00
jf 5b791d5244 Uitrol 31-10-2026 12:23 2026-10-31 12:23:34 +01:00
jf a0d36083e1 Uitrol 30-10-2026 08:39 2026-10-30 08:39:29 +01:00
jf a206bde3c5 Uitrol 30-10-2026 08:13 2026-10-30 08:13:30 +01:00
jfandClaude Sonnet 5.5 44064d2ea2 iOS: archief-optie voor een .ipa (App Store Connect) en stappen in docs
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014MGLqt1ukfnarqhut9ifcx
2026-10-30 05:18:33 +00:00
jfandClaude Sonnet 5.5 88a89bfa01 Changelog voor SideKick: view serverchangelog bovenop version_history
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014MGLqt1uKfNARQHut9ifcx
2026-10-23 14:01:19 +00:00
27 changed files with 364 additions and 9 deletions
+61
View File
@@ -0,0 +1,61 @@
-- MijnBesluit - de versiehistorie als changelog voor SideKick
--
-- SideKick toont op het tabblad Changelog de regels van een tabel of view met een vast formaat
-- (zie de SideKick-handleiding, sectie 5: Datum, Versie, Product, Soort, Onderwerp, Inhoud, Actief,
-- Aanmaakdatum, Updatedatum). MijnBesluit heeft geen tweede changelog: de versiehistorie
-- (version_history, onderhouden op de website onder Beheer > Versiehistorie) IS de changelog.
-- Deze view geeft haar in dat formaat. SideKick bewerkt niets; de agent op de server leest alleen.
--
-- Datum datum
-- Versie versie, leeg als het alleen de website betreft
-- Product vast: MijnBesluit (app en website samen)
-- Soort vast: Nieuw (de versiehistorie bevat alleen nieuwe of wezenlijk gewijzigde
-- functies, geen bugfixes)
-- Onderwerp de kop (per datum uniek, daar zorgt version_history voor)
-- Inhoud de uitleg, platte tekst
-- Actief zichtbaar (0 = verborgen)
-- Aanmaakdatum aangemaakt_op (UTC)
-- Updatedatum gewijzigd_op (UTC); de website zet hem bij elke wijziging opnieuw, ook bij
-- verbergen of tonen. Een verwijderde regel valt weg; SideKick merkt dat aan het
-- afwijkende aantal en leest dan alles opnieuw.
--
-- De view draait met de rechten van wie hem maakt (root, SQL SECURITY DEFINER). Wie hem leest hoeft
-- dus alleen SELECT op de view te hebben, niet op version_history.
--
-- Eenmalig te draaien als root, ná db\22_versiehistorie.sql:
-- mysql -u root -p mijnbesluit < db\handmatig\22c_serverchangelog_view.sql
--
-- Opnieuw draaien mag (CREATE OR REPLACE). Het staat in handmatig\ omdat het uitrolaccount wel
-- tabellen maar niet per se views mag maken, en geen rechten mag geven.
--
-- Daarna in SideKick bij de agent van MijnBesluit: "Changelog: tabel" = serverchangelog, met
-- DbNaam = mijnbesluit en een gebruiker die de view mag lezen (zie onderaan).
USE `mijnbesluit`;
CREATE OR REPLACE
SQL SECURITY DEFINER
VIEW `serverchangelog` AS
SELECT
`datum` AS `Datum`,
COALESCE(`versie`, '') AS `Versie`,
'MijnBesluit' AS `Product`,
'Nieuw' AS `Soort`,
`kop` AS `Onderwerp`,
`tekst` AS `Inhoud`,
`zichtbaar` AS `Actief`,
`aangemaakt_op` AS `Aanmaakdatum`,
`gewijzigd_op` AS `Updatedatum`
FROM `version_history`;
-- De gebruiker die de agent gebruikt om te lezen. Dit geeft de bestaande applicatiegebruiker leesrecht
-- op alleen de view. Liever een eigen leesgebruiker? Maak die zelf aan met een wachtwoord dat alleen
-- jij kent en geef hem hetzelfde recht, bijvoorbeeld:
-- CREATE USER 'mijnbesluit_changelog'@'localhost' IDENTIFIED BY '<kies-zelf-een-wachtwoord>';
-- GRANT SELECT ON `mijnbesluit`.`serverchangelog` TO 'mijnbesluit_changelog'@'localhost';
GRANT SELECT ON `mijnbesluit`.`serverchangelog` TO 'mijnbesluit_app'@'localhost';
FLUSH PRIVILEGES;
-- Controle: de regels van de versiehistorie, nieuwste bovenaan.
SELECT `Datum`, `Versie`, `Product`, `Soort`, `Onderwerp`, `Actief`, `Updatedatum`
FROM `serverchangelog` ORDER BY `Datum` DESC, `Aanmaakdatum` DESC LIMIT 20;
+18 -1
View File
@@ -31,9 +31,26 @@ geen tekstuele correcties, geen opmaak die is rechtgezet.
2. Als root: `mysql -u root -p < db\02_applicatiegebruiker.sql` (rechten voor `mijnbesluit_app`
op de nieuwe tabel) en `mysql -u root -p mijnbesluit < db\handmatig\22b_versiehistorie_startrijen.sql`
(de bestaande regels; `INSERT IGNORE`, dus opnieuw draaien is veilig).
3. Daarna pas de website en de SocketServer uitrollen. Andersom leest de nieuwe code een tabel
3. Voor de changelog in SideKick (optioneel, kan ook later): als root
`mysql -u root -p mijnbesluit < db\handmatig\22c_serverchangelog_view.sql` (zie hieronder).
4. Daarna pas de website en de SocketServer uitrollen. Andersom leest de nieuwe code een tabel
die er nog niet is, of waar de applicatiegebruiker nog niet bij mag.
## Changelog in SideKick
Het tabblad Changelog van SideKick leest een tabel of view `serverchangelog` met vaste kolommen. De
versiehistorie is de changelog van MijnBesluit, dus er is geen tweede lijst: de view
`serverchangelog` (script `db\handmatig\22c_serverchangelog_view.sql`, als root) geeft
`version_history` in dat formaat terug. `Product` is vast "MijnBesluit", `Soort` vast "Nieuw" (de
lijst bevat geen bugfixes), `Actief` is `zichtbaar` en `Updatedatum` is `gewijzigd_op`, dat de site
bij elke wijziging opnieuw zet. De agent leest de view alleen.
Instellen in SideKick bij de agent van MijnBesluit: "Changelog: tabel" = `serverchangelog`, `DbNaam` =
`mijnbesluit`, en een gebruiker met SELECT op de view (het script geeft dat aan `mijnbesluit_app`;
een aparte leesgebruiker kan ook, het voorbeeld staat in het script). Het wachtwoord alleen op de
server invullen. Voorwaarden: de agent kent de actie `ChangelogLezen` en het project staat op Weg hub.
De inhoud gaat naar het SideKick-scherm van de beheerder: geen persoonsgegevens in een regel.
## Oudere apps
De tekst van de versiehistorie zat tot en met appversie 1.1 (versiecode 3) in de app zelf. Die
+81
View File
@@ -0,0 +1,81 @@
APP STORE-VERMELDING - MijnBesluit (nl.mijnbesluit.app)
Taal: Nederlands (Nederland). Concept; in App Store Connect onder Distribution > de versie.
Afgeleid van docs\playstore\winkelvermelding.txt, met de limieten van Apple.
NAAM (max 30) - nu 11
MijnBesluit
ONDERTITEL (max 30) - nu 30
Wachtwoorden en wensen bewaard
PROMOTIETEKST (max 170, mag altijd worden aangepast zonder nieuwe versie) - nu 145
Wachtwoorden, wensen en berichten veilig bewaard, en pas vrij te geven wanneer jij dat wilt. Inloggen zonder wachtwoord, met een code per e-mail.
TREFWOORDEN (max 100, komma's zonder spaties; woorden uit de naam en ondertitel niet herhalen) - nu 99
kluis,wachtwoorden,nalatenschap,uitvaart,testament,berichten,familie,polissen,overlijden,documenten
BESCHRIJVING (max 4000) - nu 2689
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
WAT IS ER NIEUW (versie 1.1) - nu 117
Eerste versie voor iOS: je kluis, je mensen, momenten en je nalatenschap, net als in de Android-app en op de website.
ADRESSEN
Ondersteunings-URL: https://mijnbesluit.nl/ (moet een pagina zijn waar iemand hulp of contact vindt; nog te kiezen)
Marketing-URL: https://mijnbesluit.nl/ (mag leeg)
Privacybeleid-URL: https://mijnbesluit.nl/privacy
Copyright: 2026 Kwik-Bit Automatisering B.V.
CATEGORIE
Primair: Productiviteit (zoals in Google Play). Secundair: Levensstijl.
SCHERMAFBEELDINGEN (nog te maken, niet te hergebruiken van Android: 1180 x 2276 is geen toegestane maat)
- iPhone 6,9 inch: 1320 x 2868 (of 1290 x 2796); verplicht. De kleinere iPhone-maten schaalt App Store Connect hieruit af.
- iPad 13 inch: 2064 x 2752; verplicht zolang de app op iPad draait (Info.plist: UIDeviceFamily 1 en 2).
- 1 tot 10 per soort; zelfde vijf schermen als bij Google: overzicht, mensen, kluis, momenten, nalatenschap.
TOEGANG VOOR DE REVIEWER (App Review Information)
Inloggen gaat met e-mailadres en een code die per e-mail komt. Reviewaccount review@mijnbesluit.nl; de code komt in de reviewmailbox:
webmail https://oma.kwik-bit.nl:8443/webmail/ (zie MijnBesluit-playstore.md). Zet die uitleg en het mailboxwachtwoord in de velden van App Review.
Wachtwoord van de reviewmailbox pas na de review wijzigen.
LEEFTIJDSCLASSIFICATIE (door Jonathan te beantwoorden)
Doelgroep 18+ en "Contains ads" zoals bij Google; de vragenlijst van Apple over o.a. user-generated content, advertenties en
communicatie tussen gebruikers loopt anders dan bij Google, dus de antwoorden zelf doornemen.
APP PRIVACY (door Jonathan te beantwoorden; voorstel, controleren)
Verzameld en gekoppeld aan de gebruiker, niet voor tracking: e-mailadres, naam (profiel), foto's of video's (alleen wat de gebruiker zelf kiest),
gebruikersinhoud (kluisitems, berichten), gebruiks- en logboekgegevens voor beveiliging. Tracking: nee (geen advertentie-SDK; de advertentie komt van de
eigen server). Verwijderen van account en gegevens kan in de app en via mijnbesluit.nl.
Binary file not shown.

After

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

+36
View File
@@ -80,6 +80,42 @@ meldingen, en verder werkt alles. Dat komt erbij zodra het account er is, want h
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
+1 -1
View File
@@ -32,7 +32,7 @@
<ApplicationTitle>MijnBesluit</ApplicationTitle>
<ApplicationId>nl.mijnbesluit.app</ApplicationId>
<ApplicationDisplayVersion>1.1</ApplicationDisplayVersion>
<ApplicationVersion>3</ApplicationVersion>
<ApplicationVersion>4</ApplicationVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">24.0</SupportedOSPlatformVersion>
+3 -3
View File
@@ -7,10 +7,10 @@
<key>UIDeviceFamily</key>
<array>
<!-- 1 = iPhone, 2 = iPad. De schermen zijn gemaakt voor een telefoon, maar een iPad
weigeren levert alleen een gebruiker op die het niet snapt. -->
<!-- 1 = iPhone, 2 = iPad. Voorlopig alleen iPhone: de indeling op een iPad (simulator, 1 nov 2026)
toont een lege pagina met de onderbalk midden in beeld. Waarde 2 er pas weer bij als de
iPad-weergave klopt en er iPad-schermafbeeldingen zijn. -->
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
@@ -0,0 +1,48 @@
@inject IConfiguration Instellingen
@inject IWebHostEnvironment Omgeving
@* De "Download in de App Store" en "Ontdek het op Google Play"-knoppen.
Elke knop verschijnt pas als er twee dingen zijn: een adres in appsettings.json (Apps:AppStoreUrl
en Apps:GooglePlayUrl, leeg zolang de app daar niet staat) en het officiële plaatje van de winkel
in wwwroot/badges. De plaatjes tekenen we niet zelf na: Apple en Google leveren ze kant-en-klaar
aan en eisen dat ze onaangepast worden gebruikt. Zie wwwroot/badges/LEESMIJ.txt. *@
@if (_knoppen.Count > 0)
{
<div class="appknoppen">
@foreach (var knop in _knoppen)
{
<a href="@knop.Adres" target="_blank" rel="noopener" title="@knop.Titel">
<img src="@knop.Plaatje" alt="@knop.Titel" />
</a>
}
</div>
}
@code {
private readonly List<(string Adres, string Plaatje, string Titel)> _knoppen = new();
protected override void OnInitialized()
{
Voeg("Apps:AppStoreUrl", "app-store", "Download in de App Store");
Voeg("Apps:GooglePlayUrl", "google-play", "Ontdek het op Google Play");
}
private void Voeg(string instelling, string bestandsnaam, string titel)
{
var adres = Instellingen[instelling];
if (string.IsNullOrWhiteSpace(adres)) return;
// Het plaatje mag .svg of .png zijn, wat je van de winkel hebt gekregen.
foreach (var extensie in new[] { "svg", "png" })
{
var pad = $"badges/{bestandsnaam}.{extensie}";
if (Omgeving.WebRootFileProvider.GetFileInfo(pad).Exists)
{
_knoppen.Add((adres, "/" + pad, titel));
return;
}
}
}
}
@@ -216,6 +216,9 @@
</li>
</ul>
</div>
@* De knoppen voor de app in de winkels; zie AppDownload.razor. *@
<AppDownload />
</Authorized>
</AuthorizeView>
@@ -93,6 +93,8 @@
<p class="zacht"><a href="/wat-is-mijnbesluit">Wat is MijnBesluit?</a></p>
<p class="zacht"><a href="/registreren">Ik ben nieuw en wil een account aanmaken</a></p>
<p class="zacht"><a href="/adverteren">Ik wil adverteren op MijnBesluit</a></p>
<AppDownload />
</div>
@code {
@@ -15,5 +15,7 @@
<a class="knop rustig" href="/inloggen">Inloggen</a>
</p>
<AppDownload />
<p class="voet"><a href="/inloggen">Terug naar inloggen</a></p>
</div>
+4
View File
@@ -11,6 +11,10 @@
"Site": {
"Url": "https://localhost:7014"
},
"Apps": {
"GooglePlayUrl": "https://play.google.com/store/apps/details?id=nl.mijnbesluit.app",
"AppStoreUrl": "https://apps.apple.com/nl/app/id6828724812"
},
"Smtp": {
"Host": "localhost",
"Port": 587,
+11
View File
@@ -575,3 +575,14 @@ hr { border: none; border-top: 1px solid var(--rand); margin: 1.25rem 0; }
.voet { text-align: center; margin-top: 2rem; font-size: .9rem; }
.voet a { color: var(--inkt-zacht); }
/* Download-knoppen van de winkels (AppDownload.razor). De plaatjes zelf blijven onaangepast;
we bepalen alleen de hoogte en de ruimte eromheen. */
.appknoppen { display: flex; flex-wrap: wrap; align-items: center; gap: .75rem; margin-top: 1.25rem; }
.appknoppen a { display: inline-block; line-height: 0; }
.appknoppen img { height: 44px; width: auto; display: block; }
/* Het PNG van Google heeft een brede doorzichtige rand rondom de knop zelf (de knop is maar 241 van
de 572 pixels hoog). Daarom hier een grotere hoogte en een negatieve marge, zodat de zichtbare knop
net zo hoog wordt als die van Apple. Het plaatje zelf blijft onaangepast. Is het een bijgesneden
.svg, dan is dit niet nodig en geldt gewoon de 44px hierboven. */
.appknoppen img[src$="google-play.png"] { height: 104px; margin: -30px -6px; }
@@ -0,0 +1,11 @@
Hier horen de officiele knoppen van de winkels:
app-store.svg (of .png) "Download in de App Store" - Apple
google-play.svg (of .png) "Ontdek het op Google Play" - Google
Haal ze zelf op bij de winkels en pas ze niet aan (kleur, vorm, tekst):
Apple: developer.apple.com/app-store/marketing/guidelines (sectie "Download on the App Store", Nederlandse versie)
Google: play.google.com/intl/nl/badges (Nederlandse knop)
Een knop verschijnt op de inlogpagina pas als zijn bestand hier staat EN het adres in
appsettings.json is ingevuld (Apps:AppStoreUrl, Apps:GooglePlayUrl).
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/env python3
"""iPhone-schermafbeeldingen klaarmaken voor de App Store.
Per bestand in de invoermap:
- de statusbalk bovenin (tijd, 5G, batterij, opname- en microfoonindicator) wordt overgeschilderd met
de kleur van de kop van de app, zodat er geen tijd, netwerk of toestelinfo in staat;
- het plaatje wordt op 1290 x 2796 gebracht (iPhone 6,9 inch, toegestaan door de App Store).
Alleen de statusbalk wordt aangepast; de rest van het scherm blijft zoals het is.
Gebruik: python tools/appstore-schermen.py <invoermap> <uitvoermap>
Invoer: ORIGINELE iPhone-schermafbeeldingen (1179 x 2556 of 1290 x 2796, dezelfde beeldverhouding).
Een verkleind plaatje (bijvoorbeeld uit een chat) wordt onscherp zodra het naar 1290 x 2796 groeit.
Nodig: Pillow (pip install pillow).
"""
import sys, pathlib
from PIL import Image
DOEL = (1290, 2796)
STATUSBALK = 0.055 # aandeel van de hoogte dat de statusbalk beslaat (iPhone met Dynamic Island)
def verwerk(pad, uit):
im = Image.open(pad).convert("RGB")
b, h = im.size
if abs(b / h - DOEL[0] / DOEL[1]) > 0.01:
raise SystemExit(f"{pad.name}: beeldverhouding {b}x{h} past niet bij een iPhone-schermafbeelding")
rand = int(h * STATUSBALK)
kleur = im.getpixel((b // 2, rand + 4))
im.paste(kleur, (0, 0, b, rand))
im = im.resize(DOEL, Image.LANCZOS)
im.save(uit / (pad.stem + ".png"), optimize=True)
if __name__ == "__main__":
inv, uit = pathlib.Path(sys.argv[1]), pathlib.Path(sys.argv[2])
uit.mkdir(parents=True, exist_ok=True)
for f in sorted(inv.iterdir()):
if f.suffix.lower() in (".png", ".jpg", ".jpeg"):
verwerk(f, uit)
print("klaar:", f.name)
+45 -4
View File
@@ -3,7 +3,12 @@
#
# 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 ipad zoals 'simulator', maar in de iPad-simulator (voor App Store-schermen);
# andere simulator: IOS_SIMULATOR="iPad Pro 13-inch (M4)" tools/ios-bouwen.sh simulator
# tools/ios-bouwen.sh toestel bouwen en op een aangesloten iPhone zetten (Apple-ID / team nodig)
# tools/ios-bouwen.sh archief een .ipa voor App Store Connect / TestFlight maken
# (betaald Apple Developer Program, distributiecertificaat en
# App Store-profiel nodig; zie docs/iOS-app.md)
#
# Eerste keer: chmod +x tools/ios-bouwen.sh
set -euo pipefail
@@ -40,11 +45,21 @@ case "$MODUS" in
controle)
controle
;;
simulator)
simulator|ipad)
controle
[[ "$MODUS" == "ipad" && -z "${IOS_SIMULATOR:-}" ]] && IOS_SIMULATOR="iPad Pro 13-inch (M4)"
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
xcrun simctl list devices available | grep -iE 'iphone|ipad' | head -12 || true
APPARAAT=()
if [[ -n "${IOS_SIMULATOR:-}" ]]; then
UDID="$(xcrun simctl list devices available | grep -F " ${IOS_SIMULATOR} (" | head -1 | sed -E 's/.*\(([0-9A-F-]{36})\).*/\1/')"
[[ -n "$UDID" ]] || stop "simulator '${IOS_SIMULATOR}' niet gevonden; kies een naam uit de lijst hierboven (Xcode > Settings > Components voor extra simulators)."
echo "Simulator: ${IOS_SIMULATOR} ($UDID)"
xcrun simctl boot "$UDID" 2>/dev/null || true
open -a Simulator
APPARAAT=(-p:_DeviceName=":v2:udid=$UDID")
fi
# Eerst bouwen, daarna starten: met alleen -t:Run bouwt hij de app niet en weet hij niet wat
# hij moet starten. MetAndroid=false: op de Mac staat alleen de iOS-werkbelasting.
# CodesignKey=-: een eenvoudige lokale handtekening. De simulator wil geen certificaat, maar de
@@ -52,7 +67,9 @@ case "$MODUS" in
dotnet build "$PROJECT" -f "$TFM" -p:MetIos=true -p:MetAndroid=false \
-p:RuntimeIdentifier=iossimulator-arm64 -p:CodesignKey=-
dotnet build "$PROJECT" -f "$TFM" -p:MetIos=true -p:MetAndroid=false -t:Run \
-p:RuntimeIdentifier=iossimulator-arm64 -p:CodesignKey=-
-p:RuntimeIdentifier=iossimulator-arm64 -p:CodesignKey=- ${APPARAAT[@]+"${APPARAAT[@]}"}
echo
echo "Schermafdruk (zonder statusbalk-ruis, op ware grootte): xcrun simctl io booted screenshot ~/Desktop/ipad-1.png"
;;
toestel)
controle
@@ -70,7 +87,31 @@ case "$MODUS" in
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>"
;;
archief)
controle
# Namen, geen geheimen: de exacte naam van het distributiecertificaat en van het App Store-profiel.
# export IOS_SIGN_KEY="Apple Distribution: Kwik-Bit Automatisering B.V. (TEAMID)"
# export IOS_PROFILE="MijnBesluit App Store"
# Zie de lijst hieronder voor wat er op deze Mac staat.
stap "Distributiecertificaten op deze Mac"
security find-identity -v -p codesigning | grep -i 'Apple Distribution' \
|| echo "(geen 'Apple Distribution'-certificaat gevonden; maak er een in Xcode > Settings > Accounts > Manage Certificates)"
stap "Provisioning profiles op deze Mac"
ls "$HOME/Library/MobileDevice/Provisioning Profiles" 2>/dev/null || echo "(geen profielen gevonden)"
[[ -n "${IOS_SIGN_KEY:-}" ]] || stop "zet IOS_SIGN_KEY op de exacte naam van het 'Apple Distribution'-certificaat (zie de lijst hierboven)."
[[ -n "${IOS_PROFILE:-}" ]] || stop "zet IOS_PROFILE op de naam van het App Store-profiel voor nl.mijnbesluit.app."
stap "Archief maken (ios-arm64, Release)"
# Let op: ApplicationVersion (bouwnummer) moet bij elke upload hoger zijn dan de vorige.
dotnet publish "$PROJECT" -f "$TFM" -c Release -p:MetIos=true -p:MetAndroid=false \
-p:RuntimeIdentifier=ios-arm64 -p:ArchiveOnBuild=true \
-p:CodesignKey="$IOS_SIGN_KEY" -p:CodesignProvision="$IOS_PROFILE"
echo
echo "Klaar. De .ipa staat onder:"
find "$(dirname "$PROJECT")/bin/Release" -name '*.ipa' -print 2>/dev/null || true
echo "Uploaden: open de app Transporter (gratis, Mac App Store), log in met het Apple-account en"
echo "sleep de .ipa erin. Daarna staat de build na enkele minuten in App Store Connect > TestFlight."
;;
*)
stop "onbekende optie '$MODUS' (kies: controle, simulator of toestel)"
stop "onbekende optie '$MODUS' (kies: controle, simulator, ipad, toestel of archief)"
;;
esac