87 lines
2.5 KiB
Dart
87 lines
2.5 KiB
Dart
// 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<void> ensureConsentAndInitialize() async {
|
|
if (_ran) return;
|
|
_ran = true;
|
|
await _requestUmp();
|
|
await _requestAtt();
|
|
await _initializeAds();
|
|
}
|
|
|
|
Future<void> _requestUmp() async {
|
|
try {
|
|
final params = ConsentRequestParameters();
|
|
final completer = Completer<void>();
|
|
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<void> _loadAndShowFormIfRequired() async {
|
|
final completer = Completer<void>();
|
|
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<void> _requestAtt() async {
|
|
if (!Platform.isIOS) return;
|
|
try {
|
|
final status =
|
|
await AppTrackingTransparency.trackingAuthorizationStatus;
|
|
if (status == TrackingStatus.notDetermined) {
|
|
await AppTrackingTransparency.requestTrackingAuthorization();
|
|
}
|
|
} catch (_) {/* ATT optional */}
|
|
}
|
|
|
|
Future<void> _initializeAds() async {
|
|
try {
|
|
await MobileAds.instance.initialize();
|
|
_adService.onSdkReady();
|
|
} catch (e) {
|
|
debugPrint('MobileAds init failed: $e');
|
|
}
|
|
}
|
|
}
|