<# Maakt een APK van de Android-app. Draaien vanaf je eigen pc: D:\MijnBesluit VS\MijnBesluit\tools\Apk-maken.ps1 # release-APK, ondertekend D:\MijnBesluit VS\MijnBesluit\tools\Apk-maken.ps1 -Snel # snel, met de debug-sleutel D:\MijnBesluit VS\MijnBesluit\tools\Apk-maken.ps1 -Aab # bundel voor de Play Store De eerste keer maakt het script een sleutelbestand aan (een "keystore"). Bewaar dat goed: zonder dat bestand kun je later geen nieuwe versie van de app meer uitbrengen die Android als dezelfde app herkent. Dat is niet te herstellen — net zo min als het sleutelbestand van de kluis. #> [CmdletBinding()] param( # Bouwt een debug-versie met de standaard debug-sleutel: meteen te installeren op je eigen # toestel. Heet bewust niet -Debug: die naam is van PowerShell zelf. [switch] $Snel, # Bouwt een AAB in plaats van een APK. Dat is wat de Play Store wil: een bundel waaruit # Google per toestel een APK maakt, zodat niemand de onderdelen voor andere toestellen # meedownloadt. Een AAB kun je niet zelf op een telefoon zetten - daarvoor blijf je de APK # gebruiken. Zelfde sleutelbestand, zelfde wachtwoord. [switch] $Aab, # Waar de APK terechtkomt. [string] $Uit = 'D:\publish\mijnbesluit-app', # Het sleutelbestand waarmee de app wordt ondertekend. [string] $Sleutelbestand = 'D:\MijnBesluit VS\MijnBesluitSleutels\mijnbesluit-app.keystore', [string] $Alias = 'mijnbesluit', # Alleen invullen als het script keytool.exe niet zelf kan vinden. [string] $Keytool ) $ErrorActionPreference = 'Stop' $project = Join-Path $PSScriptRoot '..\src\MijnBesluit.App\MijnBesluit.App.csproj' | Resolve-Path $doel = 'net10.0-android' New-Item -ItemType Directory -Path $Uit -Force | Out-Null if ($Snel) { Write-Host "APK bouwen (debug)..." -ForegroundColor Cyan # EmbedAssembliesIntoApk: bij Debug laat MAUI de .NET-assemblies normaal buiten het pakket, # omdat Visual Studio ze bij het debuggen los naar het toestel duwt. Een APK die je met de # hand installeert mist ze dan, en de app klapt bij het starten meteen dicht. dotnet build $project -f $doel -c Debug -p:EmbedAssembliesIntoApk=true if ($LASTEXITCODE -ne 0) { throw "Bouwen mislukt." } $apk = Get-ChildItem (Join-Path (Split-Path $project) "bin\Debug\$doel") -Filter '*-Signed.apk' | Sort-Object LastWriteTime -Descending | Select-Object -First 1 if (-not $apk) { throw "Geen APK gevonden. Staat de MAUI-werkbelasting geinstalleerd?" } Copy-Item $apk.FullName (Join-Path $Uit 'mijnbesluit-debug.apk') -Force Write-Host "Klaar: $Uit\mijnbesluit-debug.apk" -ForegroundColor Green return } # ------------------------------------------------------------------ keytool zoeken <# .SYNOPSIS Zoekt keytool.exe, dat bij de Java hoort die met de Android-werkbelasting meekomt. .DESCRIPTION Waar die Java staat hangt af van hoe Visual Studio is geinstalleerd - er zijn er een stuk of vijf in omloop. Daarom kijken we op alle bekende plekken in plaats van op een. #> function Vind-Keytool { if ($Keytool) { if (-not (Test-Path $Keytool)) { throw "Opgegeven keytool bestaat niet: $Keytool" } return $Keytool } $inPad = Get-Command keytool -ErrorAction SilentlyContinue if ($inPad) { return $inPad.Source } $plekken = @() if ($env:JAVA_HOME) { $plekken += (Join-Path $env:JAVA_HOME 'bin\keytool.exe') } $mappen = @( 'C:\Program Files\Microsoft\jdk-*', 'C:\Program Files\Android\openjdk\*', 'C:\Program Files\Android\jdk\*', 'C:\Program Files (x86)\Android\openjdk\*', 'C:\Program Files (x86)\Android\jdk\*', 'C:\Program Files\Eclipse Adoptium\jdk-*', 'C:\Program Files\Java\jdk-*', "$env:LOCALAPPDATA\Android\jdk\*" ) foreach ($map in $mappen) { Get-ChildItem $map -Directory -ErrorAction SilentlyContinue | Sort-Object Name -Descending | ForEach-Object { $plekken += (Join-Path $_.FullName 'bin\keytool.exe') } } # Android Studio brengt zijn eigen Java mee. $plekken += 'C:\Program Files\Android\Android Studio\jbr\bin\keytool.exe' foreach ($pad in $plekken) { if (Test-Path $pad) { return $pad } } throw @" keytool.exe is nergens gevonden. Dat hoort bij de Java die met de Android-werkbelasting meekomt. Gezocht in: $($plekken -join "`n") Zoek hem zelf met: Get-ChildItem 'C:\Program Files','C:\Program Files (x86)' -Recurse -Filter keytool.exe -ErrorAction SilentlyContinue | Select-Object -First 5 FullName Zet de map met keytool.exe daarna in JAVA_HOME, of geef het pad mee met -Keytool. Wil je alleen op je eigen toestel testen, gebruik dan -Snel: een debug-APK heeft dit niet nodig. "@ } # ------------------------------------------------------------------ release if (-not (Test-Path $Sleutelbestand)) { Write-Host "Er is nog geen sleutelbestand. Ik maak er een aan." -ForegroundColor Yellow Write-Host "Kies een wachtwoord dat je NIET kwijtraakt." -ForegroundColor Yellow $keytool = Vind-Keytool New-Item -ItemType Directory -Path (Split-Path $Sleutelbestand) -Force | Out-Null & $keytool -genkeypair -v ` -keystore $Sleutelbestand -alias $Alias ` -keyalg RSA -keysize 2048 -validity 10000 if ($LASTEXITCODE -ne 0) { throw "Sleutelbestand aanmaken mislukt." } Write-Host "" Write-Host "MAAK HIER NU EEN BACK-UP VAN: $Sleutelbestand" -ForegroundColor Red Write-Host "Zonder dit bestand is er later geen nieuwe versie van de app meer uit te brengen." -ForegroundColor Red Write-Host "" } # Het wachtwoord van het sleutelbestand. Drie wegen, in deze volgorde: # # 1. De omgevingsvariabele MIJNBESLUIT_KEYSTORE_WACHTWOORD. Zet je die als gebruikersvariabele # in Windows, dan kan het uitrolvenster ook een ondertekende APK bouwen. Hij staat dan wel # op je machine; dat is een afweging die jij maakt en niet dit script. # 2. Zelf intypen, als je dit script in een PowerShell-venster draait. # 3. Draait dit vanuit het uitrolvenster zonder die variabele, dan houdt het hier op MET een # melding. Dat is met opzet: zo'n venster heeft geen invoer, dus Read-Host zou daar blijven # wachten op iets wat nooit komt - en dan staat er een build "nog bezig" die nooit afloopt. if ($env:MIJNBESLUIT_KEYSTORE_WACHTWOORD) { $plat = $env:MIJNBESLUIT_KEYSTORE_WACHTWOORD } elseif ($env:MIJNBESLUIT_UITROLVENSTER) { throw @" Het sleutelbestand vraagt om een wachtwoord, en dit venster kan daar niet om vragen. Twee manieren om verder te komen: * Draai dit script zelf in PowerShell: D:\MijnBesluit VS\MijnBesluit\tools\Apk-maken.ps1 * Of zet het wachtwoord eenmalig in een gebruikersvariabele, dan kan het venster het ook: [Environment]::SetEnvironmentVariable('MIJNBESLUIT_KEYSTORE_WACHTWOORD', '', 'User') Daarna het uitrolvenster opnieuw starten, anders kent het die variabele nog niet. "@ } else { $wachtwoord = Read-Host "Wachtwoord van het sleutelbestand" -AsSecureString $plat = [Runtime.InteropServices.Marshal]::PtrToStringAuto( [Runtime.InteropServices.Marshal]::SecureStringToBSTR($wachtwoord)) } # Leeg is geen wachtwoord. Dit is de val die een kwartier kost: in een proces zonder invoer geeft # Read-Host geen fout maar een lege tekst, en dan bouwt hij eerst honderd assemblies om pas bij # het ondertekenen om te vallen met "java.exe exited with code 2" - een melding waar niets in # staat over een wachtwoord. Beter hier stoppen, voordat er iets gebouwd is. if ([string]::IsNullOrWhiteSpace($plat)) { throw @" Er is geen wachtwoord voor het sleutelbestand opgegeven. Krijg je dit terwijl je het net hebt ingetypt, dan draait dit script in een venster zonder invoer. Draai hem dan zelf in PowerShell, of zet het wachtwoord eenmalig in een gebruikersvariabele: [Environment]::SetEnvironmentVariable('MIJNBESLUIT_KEYSTORE_WACHTWOORD', '', 'User') "@ } $formaat = if ($Aab) { 'aab' } else { 'apk' } Write-Host "$($formaat.ToUpper()) bouwen (release)..." -ForegroundColor Cyan dotnet publish $project -f $doel -c Release ` -p:AndroidPackageFormat=$formaat ` -p:AndroidKeyStore=true ` -p:AndroidSigningKeyStore=$Sleutelbestand ` -p:AndroidSigningKeyAlias=$Alias ` -p:AndroidSigningStorePass=$plat ` -p:AndroidSigningKeyPass=$plat ` -o $Uit if ($LASTEXITCODE -ne 0) { throw "Bouwen mislukt." } # De ondertekende bundel heet meestal -Signed.aab, maar niet elke versie van de # werkbelasting hangt er "-Signed" achter. Eerst de nette naam, en anders wat er ligt. $pakket = Get-ChildItem $Uit -Filter "*-Signed.$formaat" | Sort-Object LastWriteTime -Descending | Select-Object -First 1 if (-not $pakket) { $pakket = Get-ChildItem $Uit -Filter "*.$formaat" | Sort-Object LastWriteTime -Descending | Select-Object -First 1 } if (-not $pakket) { throw "Geen ondertekende $($formaat.ToUpper()) gevonden in $Uit." } Write-Host "" Write-Host "Klaar: $($pakket.FullName)" -ForegroundColor Green if ($Aab) { Write-Host "" Write-Host "Dit bestand gaat naar de Play Console. Op een telefoon zetten kan er niet mee;" -ForegroundColor Yellow Write-Host "bouw daarvoor zonder -Aab een gewone APK." -ForegroundColor Yellow } else { Write-Host "Voor de Play Store heb je geen APK nodig maar een AAB: draai dit script met -Aab." }