import Foundation import SwiftUI import Combine import GoogleMobileAds import AppTrackingTransparency import AdSupport @MainActor class AdMobService: ObservableObject { // MARK: - Published Properties @Published var isConsentObtained = false @Published var canShowAds = false @Published var isLoading = false // MARK: - Ad Unit IDs // Test Ad Unit IDs - Replace with production IDs before release #if DEBUG static let bannerAdUnitID = "ca-app-pub-3940256099942544/2934735716" #else static let bannerAdUnitID = "ca-app-pub-XXXXXXXXXXXXXXXX/YYYYYYYYYY" // Replace with your Ad Unit ID #endif // MARK: - Initialization init() { checkConsentStatus() } // MARK: - Consent Management func checkConsentStatus() { // Check if we already have consent let consentStatus = UserDefaults.standard.bool(forKey: "adConsentObtained") isConsentObtained = consentStatus canShowAds = consentStatus } func requestConsent() async { if #available(iOS 14.5, *) { let status = await ATTrackingManager.requestTrackingAuthorization() switch status { case .authorized: isConsentObtained = true canShowAds = true case .denied, .restricted: // Can still show non-personalized ads isConsentObtained = true canShowAds = true case .notDetermined: // Will be asked again later break @unknown default: break } } else { // iOS 14.4 and earlier - consent assumed isConsentObtained = true canShowAds = true } UserDefaults.standard.set(isConsentObtained, forKey: "adConsentObtained") } // MARK: - GDPR Consent (UMP SDK) func requestGDPRConsent() async { // Implement UMP SDK consent flow if targeting EU users // This is a simplified version - full implementation requires UMP SDK let isEUUser = isUserInEU() if isEUUser { // Show GDPR consent dialog // For now, assume consent if user continues isConsentObtained = true canShowAds = true } else { isConsentObtained = true canShowAds = true } UserDefaults.standard.set(isConsentObtained, forKey: "adConsentObtained") } private func isUserInEU() -> Bool { let euCountries = [ "AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR", "DE", "GR", "HU", "IE", "IT", "LV", "LT", "LU", "MT", "NL", "PL", "PT", "RO", "SK", "SI", "ES", "SE", "GB", "IS", "LI", "NO", "CH" ] let countryCode = Locale.current.region?.identifier ?? "" return euCountries.contains(countryCode) } // MARK: - Analytics func logAdImpression() { FirebaseService.shared.logAdImpression(adType: "banner") } func logAdClick() { FirebaseService.shared.logAdClick(adType: "banner") } } // MARK: - Banner Ad Coordinator class BannerAdCoordinator: NSObject, BannerViewDelegate { weak var adMobService: AdMobService? func bannerViewDidReceiveAd(_ bannerView: BannerView) { print("Banner ad received") adMobService?.logAdImpression() } func bannerView(_ bannerView: BannerView, didFailToReceiveAdWithError error: Error) { print("Banner ad failed to load: \(error.localizedDescription)") } func bannerViewDidRecordImpression(_ bannerView: BannerView) { // Impression recorded } func bannerViewDidRecordClick(_ bannerView: BannerView) { adMobService?.logAdClick() } func bannerViewWillPresentScreen(_ bannerView: BannerView) { // Ad will present full screen } func bannerViewWillDismissScreen(_ bannerView: BannerView) { // Ad will dismiss } func bannerViewDidDismissScreen(_ bannerView: BannerView) { // Ad dismissed } } // MARK: - UIKit Banner View Wrapper struct BannerAdView: UIViewRepresentable { @EnvironmentObject var adMobService: AdMobService func makeUIView(context: Context) -> BannerView { let bannerView = BannerView(adSize: AdSizeBanner) bannerView.adUnitID = AdMobService.bannerAdUnitID // Get root view controller if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let rootViewController = windowScene.windows.first?.rootViewController { bannerView.rootViewController = rootViewController } bannerView.delegate = context.coordinator bannerView.load(Request()) return bannerView } func updateUIView(_ uiView: BannerView, context: Context) { // Banner updates automatically } func makeCoordinator() -> BannerAdCoordinator { let coordinator = BannerAdCoordinator() coordinator.adMobService = adMobService return coordinator } }