diff --git a/LMEMappeCatastaliApp.csproj b/LMEMappeCatastaliApp.csproj
index 8aaea34..e58d34a 100644
--- a/LMEMappeCatastaliApp.csproj
+++ b/LMEMappeCatastaliApp.csproj
@@ -28,8 +28,8 @@
it.liviomerola.lmemappecatastali.pro
- 1.0.7
- 107
+ 1.0.8
+ 108
$(ApplicationDisplayVersion)
diff --git a/PLAY_STORE_PRO_CHECKLIST.md b/PLAY_STORE_PRO_CHECKLIST.md
index 0a2fd46..00c34fa 100644
--- a/PLAY_STORE_PRO_CHECKLIST.md
+++ b/PLAY_STORE_PRO_CHECKLIST.md
@@ -4,7 +4,7 @@
- Nome: LME Mappe Catastali Pro.
- Package name Android: `it.liviomerola.lmemappecatastali.pro`.
-- Versione corrente da pubblicare: `1.0.7` / version code `107`.
+- Versione corrente da pubblicare: `1.0.8` / version code `108`.
- Formato Release Android: Android App Bundle (`.aab`).
- Target SDK Release: Android 16 / API 36.
diff --git a/Platforms/Android/AndroidPlayBillingService.cs b/Platforms/Android/AndroidPlayBillingService.cs
index 48e34bb..cf7bc97 100644
--- a/Platforms/Android/AndroidPlayBillingService.cs
+++ b/Platforms/Android/AndroidPlayBillingService.cs
@@ -9,6 +9,7 @@ public sealed class AndroidPlayBillingService : Java.Lang.Object, IPlayBillingSe
private readonly SemaphoreSlim _connectionLock = new(1, 1);
private readonly BillingClient _client;
private TaskCompletionSource? _purchaseCompletion;
+ private string? _lastCatalogFailure;
public AndroidPlayBillingService()
{
@@ -31,7 +32,12 @@ public sealed class AndroidPlayBillingService : Java.Lang.Object, IPlayBillingSe
{
var details = await GetProductDetailsAsync(cancellationToken);
return details?.GetSubscriptionOfferDetails()?
- .Where(item => string.IsNullOrEmpty(item.OfferId))
+ .Where(item => !string.IsNullOrWhiteSpace(item.BasePlanId)
+ && !string.IsNullOrWhiteSpace(item.OfferToken))
+ .GroupBy(item => item.BasePlanId, StringComparer.Ordinal)
+ .Select(group => group
+ .OrderBy(item => string.IsNullOrEmpty(item.OfferId) ? 0 : 1)
+ .First())
.Select(item =>
{
var phase = item.PricingPhases.PricingPhaseList.LastOrDefault();
@@ -99,13 +105,25 @@ public sealed class AndroidPlayBillingService : Java.Lang.Object, IPlayBillingSe
var details = await GetProductDetailsAsync(cancellationToken);
var offer = details?.GetSubscriptionOfferDetails()?
- .FirstOrDefault(item => item.BasePlanId == basePlanId
- && string.IsNullOrEmpty(item.OfferId)
- && !string.IsNullOrWhiteSpace(item.OfferToken));
- if (details is null || offer is null)
+ .Where(item => item.BasePlanId == basePlanId
+ && !string.IsNullOrWhiteSpace(item.OfferToken))
+ .OrderBy(item => string.IsNullOrEmpty(item.OfferId) ? 0 : 1)
+ .FirstOrDefault();
+ if (details is null)
{
- return PlayBillingResult.Failed(
- $"Piano {basePlanId} non disponibile su Google Play. Verifica che l'abbonamento lme_pro e il piano siano attivi per il tuo Paese.");
+ return PlayBillingResult.Failed(_lastCatalogFailure
+ ?? "Google Play non ha restituito l'abbonamento lme_pro.");
+ }
+
+ if (offer is null)
+ {
+ var availablePlans = string.Join(", ", details.GetSubscriptionOfferDetails()?
+ .Select(item => item.BasePlanId)
+ .Where(item => !string.IsNullOrWhiteSpace(item))
+ .Distinct(StringComparer.Ordinal) ?? []);
+ return PlayBillingResult.Failed(string.IsNullOrWhiteSpace(availablePlans)
+ ? $"Google Play ha restituito lme_pro senza offerte acquistabili per il piano {basePlanId}."
+ : $"Piano {basePlanId} non restituito da Google Play. Piani ricevuti: {availablePlans}.");
}
var productParams = BillingFlowParams.ProductDetailsParams.NewBuilder()
@@ -191,7 +209,18 @@ public sealed class AndroidPlayBillingService : Java.Lang.Object, IPlayBillingSe
throw new InvalidOperationException(ToMessage(result.Result));
}
- return result.ProductDetailsList?.FirstOrDefault();
+ var details = result.ProductDetailsList?.FirstOrDefault();
+ if (details is not null)
+ {
+ _lastCatalogFailure = null;
+ return details;
+ }
+
+ var unfetched = result.UnfetchedProductList?.FirstOrDefault();
+ _lastCatalogFailure = unfetched is null
+ ? "Google Play ha restituito un catalogo vuoto per lme_pro. Verifica account Play Store, adesione al test e origine dell'installazione."
+ : $"Google Play non ha caricato lme_pro (codice catalogo {unfetched.StatusCodeValue}).";
+ return null;
}
private async Task EnsureConnectedAsync(CancellationToken cancellationToken)
diff --git a/README.md b/README.md
index 258dc45..df06fb0 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,11 @@ App .NET MAUI Blazor Hybrid per Android, iOS, Mac Catalyst e Windows, pensata pe
Informativa privacy: [PRIVACY_POLICY.md](PRIVACY_POLICY.md).
+## Versione Pro 1.0.8 test
+
+- Google Play Billing accetta tutte le offerte idonee restituite per i piani `monthly` e `yearly`, preferendo il piano base quando disponibile.
+- In caso di catalogo vuoto o prodotto non caricato, il messaggio mostra una diagnostica specifica restituita da Google Play.
+
## Versione Pro 1.0.7 test
- I messaggi informativi su telefono vengono mostrati sopra i controlli zoom e possono occupare fino a tre righe senza sovrapporsi.