fix(iap): address code review defects in freemium/IAP change
Fixes 9 of 10 review findings (10th requires a manual Play Console step, no code change): 1. app.dart/banner_anuncio_superior.dart: move the top SafeArea inside BannerAnuncioSuperior so it only reserves status-bar height when an ad actually renders, restoring edge-to-edge layout for premium and free-unloaded users. 2. servicio_anuncios.dart: bound every interstitial await (load, presentation, and the injected implementation itself) with injectable timeouts so a callback that never fires can no longer hang a caller. 3. estado_entitlement.dart/hoja_premium.dart: expose a typed resultadoUsuario signal for purchase/restore failures and restore-found-nothing, with dedicated localized messages (compraError, restauracionSinCompras) across all 13 locales -- never the raw developer/exception string. 4. main.dart/servicio_consentimiento.dart: add a GDPR/UMP consent flow (ConsentInformation/ConsentForm) that gates Mobile Ads SDK init on canRequestAds(); premium users never see a consent form; failures degrade to no ads instead of crashing or blocking startup. 6. servicio_anuncios.dart: track real ad presentation (onAdShowedFullScreenContent) so a failed-to-show interstitial no longer consumes a session cap slot. 7. banner_anuncio_superior.dart: add an explicit load-attempted guard so repeated didChangeDependencies (e.g. entitlement notifyListeners during a purchase) can only ever trigger one banner load attempt. 8. servicio_anuncios.dart: make esPremium a required constructor parameter, matching the hardened contract already applied to EstadoAlarmas/EstadoGrabacion/EstadoRadio. 9. hoja_premium.dart: add a dedicated premiumActivo localized string instead of reusing the equalizer's equalizerActive translation, across all 13 locales. All fixes implemented RED-first (failing test before production code). Full suite: 1261 passed, 2 pre-existing skips, 0 failures. flutter analyze: 5 pre-existing issues only, 0 new. [version set]
This commit is contained in:
+27
-1
@@ -8,12 +8,14 @@ import 'package:flutter/services.dart';
|
||||
import 'package:google_mobile_ads/google_mobile_ads.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'app.dart';
|
||||
import 'estado/estado_entitlement.dart';
|
||||
import 'servicios/arranque_audio.dart';
|
||||
import 'servicios/musica_local_auto.dart';
|
||||
import 'servicios/navegacion_auto.dart';
|
||||
import 'servicios/servicio_audio.dart';
|
||||
import 'servicios/servicio_audio_session.dart';
|
||||
import 'servicios/servicio_compras.dart';
|
||||
import 'servicios/servicio_consentimiento.dart';
|
||||
import 'servicios/servicio_presets_personalizados.dart';
|
||||
import 'tema/pluriwave_tokens.dart';
|
||||
|
||||
@@ -110,7 +112,31 @@ Future<void> main() async {
|
||||
// stream subscription and an ad-SDK warm-up are both safe to finish late
|
||||
// (mirrors `aplicarPoliticaOrientacion`'s "cosmetic, never gates startup"
|
||||
// rule immediately above).
|
||||
unawaited(MobileAds.instance.initialize());
|
||||
//
|
||||
// FIX 4 (code review): the Mobile Ads SDK is only initialized AFTER the
|
||||
// GDPR/UMP consent flow resolves that ads may actually be requested
|
||||
// (`ConsentInformation.canRequestAds()`) — serving personalized ads to
|
||||
// EEA/UK users with no CMP violates Google's EU User Consent Policy.
|
||||
// Premium users never even reach the consent form (`resolverConsentimientoAnuncios`
|
||||
// short-circuits for them — they get zero ads regardless). This whole
|
||||
// chain is deliberately `unawaited`: consent/ads are exactly as
|
||||
// "cosmetic, never gates startup" as `aplicarPoliticaOrientacion` above,
|
||||
// and any failure inside it degrades to "no ads", never a crash or a
|
||||
// blocked UI.
|
||||
unawaited(
|
||||
esPremiumPersistido()
|
||||
.then(
|
||||
(premium) => resolverConsentimientoAnuncios(
|
||||
esPremium: premium,
|
||||
consentimiento: ServicioConsentimientoUmp(),
|
||||
),
|
||||
)
|
||||
.then((puedeSolicitarAnuncios) async {
|
||||
if (puedeSolicitarAnuncios) {
|
||||
await MobileAds.instance.initialize();
|
||||
}
|
||||
}),
|
||||
);
|
||||
final compras = ServicioComprasPlayBilling();
|
||||
|
||||
// S3-R4: single SharedPreferences instance resolved once at startup and
|
||||
|
||||
Reference in New Issue
Block a user