// lib/services/consent_service.dart import 'dart:async'; import 'dart:io' show Platform; import 'package:app_tracking_transparency/app_tracking_transparency.dart'; import 'package:flutter/foundation.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; import 'ad_service.dart'; /// Runs the App-Review-mandated consent sequence exactly once per launch and /// in the required order: UMP consent form -> iOS ATT prompt -> MobileAds /// initialize. Each step is guarded; a failure in one never skips SDK init, /// because un-initialized ads would silently disable the whole monetization /// layer. Must be invoked AFTER the first frame (ATT needs the foreground). class ConsentService { ConsentService(this._adService); final AdService _adService; bool _ran = false; Future ensureConsentAndInitialize() async { if (_ran) return; _ran = true; await _requestUmp(); await _requestAtt(); await _initializeAds(); } Future _requestUmp() async { try { final params = ConsentRequestParameters(); final completer = Completer(); ConsentInformation.instance.requestConsentInfoUpdate( params, () async { try { if (await ConsentInformation.instance.isConsentFormAvailable()) { await _loadAndShowFormIfRequired(); } } finally { completer.complete(); } }, (_) => completer.complete(), ); await completer.future; } catch (_) {/* proceed without UMP */} } Future _loadAndShowFormIfRequired() async { final completer = Completer(); ConsentForm.loadConsentForm( (form) async { final status = await ConsentInformation.instance.getConsentStatus(); if (status == ConsentStatus.required) { form.show((_) => completer.complete()); } else { completer.complete(); } }, (_) => completer.complete(), ); await completer.future; } Future _requestAtt() async { if (!Platform.isIOS) return; try { final status = await AppTrackingTransparency.trackingAuthorizationStatus; if (status == TrackingStatus.notDetermined) { await AppTrackingTransparency.requestTrackingAuthorization(); } } catch (_) {/* ATT optional */} } Future _initializeAds() async { try { await MobileAds.instance.initialize(); _adService.onSdkReady(); } catch (e) { debugPrint('MobileAds init failed: $e'); } } }