InvestmentTrackerApp/PortfolioJournal/Services/AdMobService.swift

177 lines
5.0 KiB
Swift

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
}
}