namespace Guru { using UnityEngine; using System; using Guru.Notification; public partial class GuruSDK { private const float CONSENT_FLOW_TIMEOUT = 10; // Consent Flow 超时时间(秒) private static AdsInitSpec _adInitSpec; /// /// 启动广告服务 /// public static void StartAds(AdsInitSpec spec = null) { _adInitSpec = spec; if (InitConfig.UseCustomConsent) { Debug.Log($"{Tag} --- Call StartAdsWithCustomConsent when you use custom consent, and pass the result (boolean) to the method."); return; } // 默认的启动顺序是先启动Consent后, 根据用户回调的结果来启动广告 Instance.StartConsentFlow(); } /// /// 是否已经购买了去广告 /// /// public static void StartAds(bool buyNoAds = false) { StartAds(AdsInitSpec.BuildWithNoAds()); // 按照默认的去广告来生成广告启动配置 } /// /// 使用自定义的Consent, 获取用户授权后, 调用此方法 /// /// /// Consent 引导的类型, 如果使用了 MAX 的 consent 请填写 max /// 广告启动配置 public static void StartAdsWithCustomConsent(bool userAllow = true, string consentName = "custom", AdsInitSpec spec = null) { #if UNITY_IOS _attType = consentName; InitAttStatus(); #endif if (userAllow) { #if UNITY_IOS Instance.CheckAttStatus(); #else StartAdService(spec); #endif } else { Debug.Log($"{Tag} --- User refuse to provide ads Id, Ads Service will be cancelled"); } } /// /// 使用自定义的Consent, 获取用户授权后, 调用此方法 /// /// 自定义 Consent 的用户授权结果 /// Consent引导名称 /// 是否已经购买了去广告 public static void StartAdsWithCustomConsent(bool userAllow = true, string consentName = "custom", bool buyNoAds = false) { StartAdsWithCustomConsent(userAllow, consentName, AdsInitSpec.BuildWithNoAds()); } #region Guru Consent private bool _hasConsentCalled = false; private bool _adServiceHasStarted = false; private string _notiStatue = ""; private bool _hasNotiGranted = false; /// /// 启动Consent流程 /// 因为之后规划广告流程会放在 Consent 初始化之后, 因此请求广告的时候会需要先请求 Consent /// private void StartConsentFlow() { LogI($"#4.5 --- StartConsentFlow ---"); float time = 1; if (!_adServiceHasStarted && _appServicesConfig != null) { time = _appServicesConfig.IsAdsCompliance() ? CONSENT_FLOW_TIMEOUT : 1f; // 启动合规判定后, 延迟最多 10 秒后启动广告 } Delay(time, AdServiceHandler); // 广告延迟启动 if (_hasConsentCalled) return; _hasConsentCalled = true; bool enableCountryCheck = false; string dmaMapRule = ""; if (_appServicesConfig != null && _appServicesConfig.parameters != null) { enableCountryCheck = _appServicesConfig.DMACountryCheck(); dmaMapRule = _appServicesConfig.DMAMapRule(); } #if UNITY_IOS InitAttStatus(); // Consent 启动前记录 ATT 初始值 #endif UnityEngine.Debug.Log($"{Tag} --- Call:StartConsentFlow ---"); GuruConsent.StartConsent(OnGuruConsentOver, dmaMapRule:dmaMapRule, enableCountryCheck:enableCountryCheck); } /// /// Guru Consent flow is Over /// /// private void OnGuruConsentOver(int code) { // 无论状态如何, 都在回调内启动广告初始化 AdServiceHandler(); // 调用回调 Callbacks.ConsentFlow.InvokeOnConsentResult(code); #if UNITY_IOS CheckAttStatus(); // [iOS] Consent 启动后检查 ATT 初始值 #elif UNITY_ANDROID CheckNotiPermission(); // Consent 回调后检查 Notification 权限 #endif // 内部处理后继逻辑 switch(code) { case GuruConsent.StatusCode.OBTAINED: case GuruConsent.StatusCode.NOT_AVAILABLE: // 已获取授权, 或者地区不可用, ATT 尚未启动 // TODO: 添加后继处理逻辑 break; } } /// /// 启动广告服务 /// private void AdServiceHandler() { if (_adServiceHasStarted) return; _adServiceHasStarted = true; StartAdService(_adInitSpec); } #endregion #region IOS ATT 广告授权流程 #if UNITY_IOS private static string _initialAttStatus; private static String _attType = "admob"; private static bool _autoReCallAtt = false; /// /// 显示系统的 ATT 弹窗 /// public void RequestAttDialog() { LogI($"RequestATTDialog"); ATTManager.RequestATTDailog(ReportAttStatus); } /// /// 初始化 ATT 状态 /// public static void InitAttStatus() { _attType = InitConfig.UseCustomConsent ? ATTManager.GUIDE_TYPE_CUSTOM : ATTManager.GUIDE_TYPE_ADMOB; // 点位属性确定 _initialAttStatus = ATTManager.GetStatus(); SetATTStatus(_initialAttStatus); // 上报一个初始的状态 } /// /// iOS 平台检查 ATT 状态 /// private void CheckAttStatus(bool autoReCall = false) { _autoReCallAtt = autoReCall; // Delay 1s to get the user choice Delay(1, () => ATTManager.CheckStatus(ReportAttStatus)); } private void ReportAttStatus(string status) { LogI($"{Tag} --- Get Att status:{status} att Type:{_attType} recall:{_autoReCallAtt}"); SetATTStatus(_initialAttStatus); // 上报一个初始的状态 // SetUserProperty(Analytics.ParameterATTStatus, status); // 当前的状态 if (!string.IsNullOrEmpty(status) && status != _initialAttStatus && status != ATTManager.ATT_STATUS_NOT_DETERMINED) { // 上报点位: SetATTStatus(_initialAttStatus); } switch(status) { case ATTManager.ATT_STATUS_NOT_DETERMINED: // ATT 状态未知, 请求弹窗 if(_autoReCallAtt) RequestAttDialog(); break; case ATTManager.ATT_STATUS_RESTRICTED: case ATTManager.ATT_STATUS_DENIED: // ATT 状态受限, 或者被拒绝 break; case ATTManager.ATT_STATUS_AUTHORIZED: // ATT 状态已授权 break; } CheckNotiPermission(); // Consent 回调后检查 Notification 权限 } #endif #endregion #region Notification Permission Check /// /// 初始化 Noti Service /// private void InitNotiPermission() { // bool hasNotiGranted = false; _notiStatue = "no_determined"; NotificationService.Initialize(); // 初始化 Noti 服务 Analytics.SetNotiPerm(NotificationService.GetStatus()); } /// /// 检查 Noti 状态 /// private void CheckNotiPermission() { var status = NotificationService.GetStatus(); // 如果未启用自动 Noti 授权,则直接上报状态 if (!_initConfig.AutoNotificationPermission) { Debug.LogWarning($"[SDK] ---- AutoNotificationPermission is OFF, Project should request permission own."); return; } bool isGranted = NotificationService.IsPermissionGranted(); Debug.Log($"[SDK] ---- Check Noti Permission: {isGranted}"); if (isGranted) { Debug.Log($"[SDK] ---- Set Notification Permission: {status}"); Analytics.SetNotiPerm(status); return; } RequestNotificationPermission(); // 请求授权 } /// /// 请求推送授权 /// /// public static void RequestNotificationPermission(Action callback = null) { FirebaseUtil.StartFetchFcmToken(); Debug.Log($"[SDK] ---- RequestNotificationPermission"); NotificationService.RequestPermission(status => { Debug.Log($"[SDK] ---- Set Notification Permission: {status}"); if(!string.IsNullOrEmpty(status)) Analytics.SetNotiPerm(status); callback?.Invoke(status); }); } /// /// 获取 Notification 状态值 /// /// public static string GetNotificationStatus() { return NotificationService.GetStatus(); } /// /// 用户是否已经获取了 Notification 授权了 /// /// public static bool IsNotificationPermissionGranted() { return NotificationService.IsPermissionGranted(); } #endregion #region Ad Services private static bool _initAdsCompleted = false; public static bool IsAdsReady => _initAdsCompleted; private static int _preBannerAction = 0; public static AdsInitSpec GetDefaultAdsSpec() { return AdsInitSpec.BuildDefault(InitConfig.AutoLoadWhenAdsReady, IsDebugMode); } /// /// 启动广告服务 /// private static void StartAdService(AdsInitSpec spec = null) { //---------- Using InitConfig ---------- if (InitConfig is { IsBuyNoAds: true }) SetBuyNoAds(true); LogI($"StartAdService"); if (spec == null) { spec = AdsInitSpec.BuildDefault(InitConfig.AutoLoadWhenAdsReady, IsDebugMode); if (ADService.Instance.IsBuyNoAds) { spec = AdsInitSpec.BuildWithNoAds(InitConfig.AutoLoadWhenAdsReady, IsDebugMode); } } if(InitConfig != null && !string.IsNullOrEmpty(InitConfig.BannerBackgroundColor)) spec.bannerColorHex = InitConfig.BannerBackgroundColor; //--------- Add Callbacks ----------- // BADS ADService.Instance.OnBannerStartLoad = OnBannerStartLoad; ADService.Instance.OnBannerLoaded = OnBannerLoaded; // IADS ADService.Instance.OnInterstitialStartLoad = OnInterstitialStartLoad; ADService.Instance.OnInterstitialLoaded = OnInterstitialLoaded; ADService.Instance.OnInterstitialFailed = OnInterstitialFailed; ADService.Instance.OnInterstitialClosed = OnInterstitialClosed; // RADS ADService.Instance.OnRewardedStartLoad = OnRewardStartLoad; ADService.Instance.OnRewardLoaded = OnRewardLoaded; ADService.Instance.OnRewardFailed = OnRewardFailed; ADService.Instance.OnRewardClosed = OnRewardClosed; // ---------- Start Services ---------- ADService.Instance.StartService(OnAdsInitComplete, spec); // ---------- Life Cycle ---------- Callbacks.App.OnAppPaused += OnAppPaused; } /// /// 生命周期回调 /// /// private static void OnAppPaused(bool paused) { if(ADService.Instance.IsInitialized) ADService.Instance.OnAppPaused(paused); } private static void OnBannerStartLoad(string adUnitId) => Callbacks.Ads.InvokeOnBannerADStartLoad(adUnitId); private static void OnBannerLoaded() => Callbacks.Ads.InvokeOnBannerADLoaded(); private static void OnInterstitialStartLoad(string adUnitId) => Callbacks.Ads.InvokeOnInterstitialADStartLoad(adUnitId); private static void OnInterstitialLoaded() => Callbacks.Ads.InvokeOnInterstitialADLoaded(); private static void OnInterstitialFailed() => Callbacks.Ads.InvokeOnInterstitialADFailed(); private static void OnInterstitialClosed() => Callbacks.Ads.InvokeOnInterstitialADClosed(); private static void OnRewardStartLoad(string adUnitId) => Callbacks.Ads.InvokeOnRewardedADStartLoad(adUnitId); private static void OnRewardLoaded() => Callbacks.Ads.InvokeOnRewardedADLoaded(); private static void OnRewardFailed() => Callbacks.Ads.InvokeOnRewardADFailed(); private static void OnRewardClosed() => Callbacks.Ads.InvokeOnRewardADClosed(); private static void OnAdsInitComplete() { _initAdsCompleted = true; if (_adInitSpec != null && _adInitSpec.loadBanner) { // 预制动作处理 if (_preBannerAction == 1) { _preBannerAction = 0; ShowBanner(); } else if (_preBannerAction == -1) { _preBannerAction = 0; HideBanner(); } } Callbacks.Ads.InvokeOnAdsInitComplete(); } private static bool CheckAdsReady() { if (!IsAdsReady) { LogW("[SDK] Ads is not ready. Call first."); return false; } return true; } /// /// 显示Banner广告 /// /// public static void ShowBanner(string placement = "") { if (!CheckAdsReady()) { _preBannerAction = 1; return; } ADService.Instance.ShowBanner(placement); } /// /// 设置 Banner 背景颜色 /// /// public static void SetBannerBackgroundColor(Color color) { // if (!CheckAdsReady()) return; ADService.Instance.SetBannerBackgroundColor(color); } public static void SetBannerAutoRefresh(bool value = true) { if (!CheckAdsReady()) return; ADService.Instance.SetBannerAutoRefresh(value); } /// /// 隐藏Banner广告 /// public static void HideBanner() { if (!CheckAdsReady()) { _preBannerAction = -1; return; } ADService.Instance.HideBanner(); } public static void LoadInterstitialAd() { if (!CheckAdsReady()) return; ADService.Instance.RequestInterstitialAD(); } public static bool IsInterstitialAdReady => ADService.Instance.IsInterstitialADReady(); /// /// 显示插屏广告 /// /// /// public static void ShowInterstitialAd(string placement = "", Action onDismissed = null) { if (!CheckAdsReady()) return; if (!ADService.Instance.IsInterstitialADReady()) { LogE("Interstitial is not ready. Call again."); LoadInterstitialAd(); return; } ADService.Instance.ShowInterstitialAD(placement, onDismissed); } public static void LoadRewardAd() { if (!CheckAdsReady()) return; ADService.Instance.RequestRewardedAD(); } public static bool IsRewardAdReady => ADService.Instance.IsRewardedADReady(); /// /// 显示激励视频广告 /// /// /// /// public static void ShowRewardAd(string placement = "", Action onRewarded = null, Action onFailed = null) { if (!CheckAdsReady()) return; if (!ADService.Instance.IsRewardedADReady()) { LogE("RewardAd is not ready. Call again."); LoadRewardAd(); return; } ADService.Instance.ShowRewardedAD(placement, onRewarded, onFailed); } #endregion #region MaxServices /// /// 显示Max调试菜单 /// public static void ShowMaxDebugPanel() { #if UNITY_EDITOR LogI($"Can not show Max Debug Panel in Editor, skipped."); return; #endif if (!ADService.Instance.IsInitialized) { LogI($"ADService is not initialized, call first."); return; } ADService.Instance.ShowMaxDebugPanel(); } #endregion } }