diff --git a/LMEMappeCatastaliApp.csproj b/LMEMappeCatastaliApp.csproj
index 5caf9d0..237af3a 100644
--- a/LMEMappeCatastaliApp.csproj
+++ b/LMEMappeCatastaliApp.csproj
@@ -29,8 +29,8 @@
it.liviomerola.lmemappecatastali.pro
- 1.0.14
- 114
+ 1.0.15
+ 115
$(ApplicationDisplayVersion)
diff --git a/scripts/build-android-play-store.ps1 b/scripts/build-android-play-store.ps1
new file mode 100644
index 0000000..fb9e92e
--- /dev/null
+++ b/scripts/build-android-play-store.ps1
@@ -0,0 +1,104 @@
+param(
+ [string]$Configuration = "Release"
+)
+
+$ErrorActionPreference = "Stop"
+$projectRoot = Split-Path -Parent $PSScriptRoot
+$dotnet = Join-Path $projectRoot "artifacts\tooling\dotnet10\dotnet.exe"
+$androidSdk = Join-Path $env:LOCALAPPDATA "Android\Sdk"
+$documentsDirectory = Split-Path -Parent (Split-Path -Parent $projectRoot)
+$privateDirectory = Join-Path $documentsDirectory "LMEMappeCatastali-Private\GooglePlay"
+$keyStore = Join-Path $privateDirectory "lme-mappe-catastali-pro-upload.jks"
+$recoveryFile = Join-Path $privateDirectory "UPLOAD-KEY-RECOVERY.txt"
+$outputDirectory = Join-Path $projectRoot "artifacts\play-store"
+$projectPath = Join-Path $projectRoot "LMEMappeCatastaliApp.csproj"
+
+foreach ($requiredPath in @($dotnet, $androidSdk, $keyStore, $recoveryFile, $projectPath)) {
+ if (-not (Test-Path -LiteralPath $requiredPath)) {
+ throw "Componente richiesto non trovato: $requiredPath"
+ }
+}
+
+[xml]$projectXml = Get-Content -Raw -LiteralPath $projectPath
+$propertyGroup = $projectXml.Project.PropertyGroup |
+ Where-Object { $_.ApplicationDisplayVersion -and $_.ApplicationVersion } |
+ Select-Object -First 1
+$displayVersion = [string]$propertyGroup.ApplicationDisplayVersion
+$versionCode = [string]$propertyGroup.ApplicationVersion
+if ([string]::IsNullOrWhiteSpace($displayVersion) -or [string]::IsNullOrWhiteSpace($versionCode)) {
+ throw "Versione applicazione non trovata nel progetto."
+}
+
+$recovery = Get-Content -LiteralPath $recoveryFile
+function Read-RecoveryValue([string]$label) {
+ $line = $recovery | Where-Object { $_ -like "${label}:*" } | Select-Object -First 1
+ if ([string]::IsNullOrWhiteSpace($line)) {
+ throw "Valore $label non trovato nel file di recupero."
+ }
+ return ($line -split ":", 2)[1].Trim()
+}
+
+$storePassword = Read-RecoveryValue "Store password"
+$keyPassword = Read-RecoveryValue "Key password"
+$env:LME_ANDROID_UPLOAD_STORE_PASS = $storePassword
+$env:LME_ANDROID_UPLOAD_KEY_PASS = $keyPassword
+$packages = [System.Collections.Generic.List[System.IO.FileInfo]]::new()
+
+New-Item -ItemType Directory -Force -Path $outputDirectory | Out-Null
+
+& $dotnet restore $projectPath `
+ -p:Configuration=$Configuration `
+ -p:TargetFrameworks=net10.0-android `
+ -p:AndroidSdkDirectory=$androidSdk `
+ -p:UseDefaultPublishRuntimeIdentifier=false
+if ($LASTEXITCODE -ne 0) {
+ throw "Ripristino delle dipendenze Android non riuscito."
+}
+
+try {
+ foreach ($format in @("aab", "apk")) {
+ & $dotnet publish $projectPath `
+ -f net10.0-android `
+ -c $Configuration `
+ --no-restore `
+ -p:AndroidSdkDirectory=$androidSdk `
+ -p:UseDefaultPublishRuntimeIdentifier=false `
+ -p:AndroidPackageFormat=$format `
+ -p:AndroidKeyStore=true `
+ -p:AndroidSigningKeyStore=$keyStore `
+ -p:AndroidSigningKeyAlias=lme-upload `
+ -p:AndroidSigningStorePass=env:LME_ANDROID_UPLOAD_STORE_PASS `
+ -p:AndroidSigningKeyPass=env:LME_ANDROID_UPLOAD_KEY_PASS
+ if ($LASTEXITCODE -ne 0) {
+ throw "Pubblicazione Android $format non riuscita."
+ }
+
+ $publishDirectory = Join-Path $projectRoot "bin\$Configuration\net10.0-android\publish"
+ $package = Get-ChildItem -LiteralPath $publishDirectory -Filter "*-Signed.$format" -File |
+ Sort-Object LastWriteTime -Descending |
+ Select-Object -First 1
+ if ($null -eq $package) {
+ throw "Nessun pacchetto $format firmato prodotto in $publishDirectory"
+ }
+
+ $destination = Join-Path $outputDirectory "LME-Mappe-Catastali-Pro-$displayVersion-$versionCode.$format"
+ Copy-Item -LiteralPath $package.FullName -Destination $destination -Force
+ $packages.Add((Get-Item -LiteralPath $destination))
+ }
+}
+finally {
+ Remove-Item Env:LME_ANDROID_UPLOAD_STORE_PASS -ErrorAction SilentlyContinue
+ Remove-Item Env:LME_ANDROID_UPLOAD_KEY_PASS -ErrorAction SilentlyContinue
+ $storePassword = $null
+ $keyPassword = $null
+}
+
+$hashLines = $packages | ForEach-Object {
+ $hash = Get-FileHash -Algorithm SHA256 -LiteralPath $_.FullName
+ "$($hash.Hash.ToLowerInvariant()) $($_.Name)"
+}
+$hashFile = Join-Path $outputDirectory "LME-Mappe-Catastali-Pro-$displayVersion-$versionCode-SHA256SUMS.txt"
+$hashLines | Set-Content -LiteralPath $hashFile
+
+$packages | Select-Object Name, Length, LastWriteTime
+Get-Item -LiteralPath $hashFile | Select-Object Name, Length, LastWriteTime