234 lines
8.4 KiB
Dart
234 lines
8.4 KiB
Dart
// Author: fengshengxiong
|
||
// Date: 2024/6/25
|
||
// Description: 插页广告
|
||
|
||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||
import 'package:get/get.dart';
|
||
import 'package:google_mobile_ads/google_mobile_ads.dart';
|
||
import 'package:tone_snap/data/enum/ad_scenes.dart';
|
||
import 'package:tone_snap/data/models/ad_config_model.dart';
|
||
import 'package:tone_snap/data/storage/music_box.dart';
|
||
import 'package:tone_snap/firebase/firebase_analytics_manager.dart';
|
||
import 'package:tone_snap/modules/launch/launch_controller.dart';
|
||
import 'package:tone_snap/utils/log_util.dart';
|
||
import 'package:tone_snap/utils/obj_util.dart';
|
||
|
||
class InterstitialAdManager {
|
||
InterstitialAdManager._();
|
||
|
||
static final InterstitialAdManager _instance = InterstitialAdManager._();
|
||
|
||
factory InterstitialAdManager() => _instance;
|
||
|
||
/// 广告对象Map
|
||
final Map<String, InterstitialAd?> _interstitialAdMap = {};
|
||
|
||
/// 加载和显示广告之间允许的最长持续时间
|
||
final Duration _maxCacheDuration = const Duration(minutes: 50);
|
||
|
||
/// 跟踪加载时间,这样我们就不会显示过期的广告
|
||
final Map<String, DateTime?> _appOpenLoadTimeMap = {};
|
||
|
||
/// 记录关闭时的时间,用于下一次展示时计算时间差
|
||
DateTime? _closeDateTime;
|
||
|
||
/// 是否显示
|
||
bool isShowingAd = false;
|
||
|
||
/// 加载所有插页广告位
|
||
void loadAdAll() {
|
||
AdConfigModel adConfigModel = MusicBox().getAdConfig();
|
||
_loadSingleAd(adConfigModel.coldLoading, AdScenes.coldLoading.name);
|
||
_loadSingleAd(adConfigModel.hotLoading, AdScenes.hotLoading.name);
|
||
_loadSingleAd(adConfigModel.play, AdScenes.play.name);
|
||
_loadSingleAd(adConfigModel.download, AdScenes.download.name);
|
||
_loadSingleAd(adConfigModel.list, AdScenes.list.name);
|
||
_loadSingleAd(adConfigModel.playCut, AdScenes.playCut.name);
|
||
_loadSingleAd(adConfigModel.search, AdScenes.search.name);
|
||
}
|
||
|
||
/// 加载单个广告位
|
||
void _loadSingleAd(List<AdModel>? adList, String adScenes) {
|
||
if (adList != null && adList.isNotEmpty) {
|
||
var adModel = adList.reduce((value, element) => element.level! < value.level! ? element : value);
|
||
loadAd(adModel.identifier, adScenes);
|
||
}
|
||
}
|
||
|
||
/// 加载广告
|
||
void loadAd(String? adUnitId, String adScenes) async {
|
||
final List<ConnectivityResult> connectivityResult = await (Connectivity().checkConnectivity());
|
||
if (connectivityResult.contains(ConnectivityResult.none)) {
|
||
LogUtil.d('当前无网络,不加载广告');
|
||
return;
|
||
}
|
||
if (ObjUtil.isEmpty(adUnitId)) {
|
||
return;
|
||
}
|
||
InterstitialAd.load(
|
||
adUnitId: adUnitId!,
|
||
request: const AdRequest(),
|
||
adLoadCallback: InterstitialAdLoadCallback(
|
||
onAdLoaded: (ad) {
|
||
LogUtil.d('$adScenes:${ad.adUnitId}插页广告加载完成');
|
||
_interstitialAdMap[adScenes] = ad;
|
||
_appOpenLoadTimeMap[adScenes] = DateTime.now();
|
||
if (adScenes == AdScenes.coldLoading.name) {
|
||
if (Get.isRegistered<LaunchController>()) {
|
||
LaunchController.to.editChangeValue();
|
||
}
|
||
}
|
||
},
|
||
onAdFailedToLoad: (LoadAdError error) {
|
||
LogUtil.d('$adScenes:$adUnitId插页广告加载失败: $error');
|
||
_loadFailHandle(adUnitId, adScenes);
|
||
FirebaseAnalyticsManager.logPlayAdsLoadFailure(error.message);
|
||
},
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 加载失败处理
|
||
void _loadFailHandle(String adUnitId, String adScenes) {
|
||
AdConfigModel adConfigModel = MusicBox().getAdConfig();
|
||
var adList = _getAdList(adScenes);
|
||
if (adList != null) {
|
||
var currentItem = adList.firstWhereOrNull((e) => e.identifier == adUnitId);
|
||
if (currentItem != null) {
|
||
var nextItem = adList.firstWhereOrNull((e) => e.level == currentItem.level! + 1);
|
||
if (nextItem != null) {
|
||
// 当前id加载失败,加载下一个id
|
||
loadAd(nextItem.identifier, adScenes);
|
||
} else {
|
||
// 对应场景id都加载失败,加载全局id
|
||
_loadSingleAd(adConfigModel.backup, adScenes);
|
||
}
|
||
} else {
|
||
var currentItem = adConfigModel.backup?.firstWhereOrNull((e) => e.identifier == adUnitId);
|
||
if (currentItem != null) {
|
||
var nextItem = adConfigModel.backup?.firstWhereOrNull((e) => e.level == currentItem.level! + 1);
|
||
if (nextItem != null) {
|
||
loadAd(nextItem.identifier, adScenes);
|
||
} else {
|
||
if (adList.isNotEmpty) {
|
||
_loadSingleAd(adList, adScenes);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
List<AdModel>? _getAdList(String adScenes) {
|
||
AdConfigModel adConfigModel = MusicBox().getAdConfig();
|
||
if (adScenes == AdScenes.coldLoading.name) {
|
||
return adConfigModel.coldLoading;
|
||
} else if (adScenes == AdScenes.hotLoading.name) {
|
||
return adConfigModel.hotLoading;
|
||
} else if (adScenes == AdScenes.play.name) {
|
||
return adConfigModel.play;
|
||
} else if (adScenes == AdScenes.download.name) {
|
||
return adConfigModel.download;
|
||
} else if (adScenes == AdScenes.list.name) {
|
||
return adConfigModel.list;
|
||
} else if (adScenes == AdScenes.playCut.name) {
|
||
return adConfigModel.playCut;
|
||
} else if (adScenes == AdScenes.search.name) {
|
||
return adConfigModel.search;
|
||
} else if (adScenes == AdScenes.backup.name) {
|
||
return adConfigModel.backup;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/// 是否可以播放广告
|
||
bool isAdAvailable(String adScenes) {
|
||
return _interstitialAdMap[adScenes] != null;
|
||
}
|
||
|
||
/// 显示广告(如果存在且尚未显示)
|
||
/// 如果先前缓存的广告已过期,则只加载并缓存新广告
|
||
void showAdIfAvailable(String adScenes, {Function()? onTap}) {
|
||
if (!isAdAvailable(adScenes)) {
|
||
LogUtil.d('尝试在可用之前显示广告');
|
||
|
||
if(onTap != null) onTap();
|
||
return;
|
||
}
|
||
if (isShowingAd) {
|
||
LogUtil.d('尝试在已显示广告的情况下显示广告');
|
||
|
||
if(onTap != null) onTap();
|
||
return;
|
||
}
|
||
if (DateTime.now().subtract(_maxCacheDuration).isAfter(_appOpenLoadTimeMap[adScenes]!)) {
|
||
LogUtil.d('超过了最大缓存持续时间。正在加载另一个广告');
|
||
_interstitialAdMap[adScenes]!.dispose();
|
||
loadAd(_interstitialAdMap[adScenes]?.adUnitId, adScenes);
|
||
_interstitialAdMap[adScenes] = null;
|
||
_interstitialAdMap.remove(adScenes);
|
||
|
||
if(onTap != null) onTap();
|
||
return;
|
||
}
|
||
if (_closeDateTime != null) {
|
||
// 计算时间差
|
||
Duration timeDifference = DateTime.now().difference(_closeDateTime!);
|
||
|
||
int seconds;
|
||
if (adScenes == AdScenes.hotLoading.name) {
|
||
seconds = MusicBox().getOpenAppEventDuration();
|
||
} else {
|
||
seconds = MusicBox().getInterstitialEventDuration();
|
||
}
|
||
if (timeDifference < Duration(seconds: seconds)) {
|
||
LogUtil.d('距离上次广告展示未达到插页广告事件间隔时长');
|
||
|
||
if(onTap != null) onTap();
|
||
return;
|
||
}
|
||
}
|
||
|
||
FirebaseAnalyticsManager.logPlayAdsChanceAction();
|
||
|
||
// 设置 fullScreenContentCallback 并显示广告
|
||
_interstitialAdMap[adScenes]!.fullScreenContentCallback = FullScreenContentCallback(
|
||
// 暂停应用程序中的活动或记录广告展示的时间
|
||
onAdShowedFullScreenContent: (ad) {
|
||
LogUtil.d('$ad onAdShowedFullScreenContent');
|
||
isShowingAd = true;
|
||
},
|
||
// 更适合用于跟踪广告展示的次数和效果,以及执行与广告展示相关的操作
|
||
onAdImpression: (ad) {
|
||
LogUtil.d('$ad onAdImpression');
|
||
FirebaseAnalyticsManager.logPlayAdsShowSuccess(ad);
|
||
},
|
||
onAdFailedToShowFullScreenContent: (ad, error) {
|
||
LogUtil.d('$ad onAdFailedToShowFullScreenContent: $error');
|
||
isShowingAd = false;
|
||
ad.dispose();
|
||
loadAd(_interstitialAdMap[adScenes]?.adUnitId, adScenes);
|
||
_interstitialAdMap[adScenes] = null;
|
||
_interstitialAdMap.remove(adScenes);
|
||
FirebaseAnalyticsManager.logPlayAdsLoadFailure(error.message);
|
||
|
||
if(onTap != null) onTap();
|
||
},
|
||
onAdDismissedFullScreenContent: (ad) {
|
||
LogUtil.d('$ad onAdDismissedFullScreenContent');
|
||
isShowingAd = false;
|
||
_closeDateTime = DateTime.now();
|
||
ad.dispose();
|
||
loadAd(_interstitialAdMap[adScenes]?.adUnitId, adScenes);
|
||
_interstitialAdMap[adScenes] = null;
|
||
_interstitialAdMap.remove(adScenes);
|
||
|
||
if(onTap != null) onTap();
|
||
},
|
||
onAdClicked: (ad) {
|
||
LogUtil.d('$ad onAdClicked');
|
||
},
|
||
);
|
||
_interstitialAdMap[adScenes]!.show();
|
||
}
|
||
} |