Jelajahi Sumber

remote config 默认值

guoziyun 4 bulan lalu
induk
melakukan
13e5df609e

+ 4 - 2
CHANGELOG.md

@@ -24,5 +24,7 @@
 - download优化,增加防抖;缓存文件写入优化, 先写入tmp文件,再重命名,保证是原子操作,避免写入“半截”文件的可能性
 - "下一关"按钮防抖和安全pop up优化(根据firebase报错的修改)
 - 内存分级, 低内存设备不展示banner广告
-- 启动优化, 启动main中所有堵塞性的await, 改为立即启动ui,后台并行初始化firebase,本地存储等await动作
-- 资源竞争优化: 关卡结束点击next, 立即pop up返回主页, 不再等待插屏广告结果再次回到play页面, 这样的好处是可以立即释放play界面资源,为插屏广告腾出内存空间。 用户体验也会更好,广告结束直接就在首页,不会闪
+- 启动优化, 启动main中所有堵塞性的await, 改为立即启动ui,后台并行初始化firebase,本地存储等await动作; 广告延迟加载,分散启动压力
+- 资源竞争优化: 关卡结束点击next, 立即pop up返回主页, 不再等待插屏广告结果再次回到play页面, 这样的可以立即释放play界面资源,为插屏广告腾出内存空间。 用户体验也会更好,广告结束直接就在首页,不会闪; 页面切换或退出, 手动销毁banner广告
+- 黑名单机制: hisense, itel, huawei y9 等高频ANR设备列入黑名单, 不展示广告。 (配合firebase remote config 使用支持以远程配置, 增加配置参数 ad_crash_prone_devices, 格式为逗号分隔的设备名称(如 "hisense,itel,huawei y9") )
+- 低端机的不启用自适应 Banner,因其渲染开销较大

+ 9 - 4
lib/ads/applovin_ads_controller.dart

@@ -32,8 +32,12 @@ class ApplovinAdsController {
   bool _isProblematicDevice = false;
   bool get isLowRamDevice => _isLowRamDevice;
 
-  // 🔥 关键:设备黑名单检测
-  static final Set<String> _crashProneDevices = {'hisense', 'itel', 'huawei y9' /*'samsung galaxy a50s'*/};
+  // 从 Remote Config 获取设备黑名单
+  Set<String> _getCrashProneDevices() {
+    final blacklistStr = RemoteConfig().adCrashProneDevices;
+    if (blacklistStr.isEmpty) return {};
+    return blacklistStr.split(',').map((e) => e.trim().toLowerCase()).toSet();
+  }
 
   bool _shouldSkipAds() {
     return _isLowRamDevice || _isProblematicDevice;
@@ -79,10 +83,11 @@ class ApplovinAdsController {
       // 低端机检测
       _isLowRamDevice = androidInfo.isLowRamDevice || (androidInfo.systemFeatures.contains('android.hardware.ram.low'));
 
-      // 问题设备检测
+      // 问题设备检测(从 Remote Config 读取黑名单)
       String manufacturer = androidInfo.manufacturer.toLowerCase();
       String model = androidInfo.model.toLowerCase();
-      _isProblematicDevice = _crashProneDevices.any((device) => manufacturer.contains(device) || model.contains(device));
+      final crashProneDevices = _getCrashProneDevices();
+      _isProblematicDevice = crashProneDevices.any((device) => manufacturer.contains(device) || model.contains(device));
 
       if (_isProblematicDevice) {
         _log.warning('🔥 Problematic device detected: $manufacturer $model');

+ 1 - 1
lib/homepage/home_screen.dart

@@ -467,7 +467,7 @@ class _HomeScreen extends AdsState<HomeScreen> with TickerProviderStateMixin {
         // 打印下当下的插屏广告状态
         _log.info('==================>interState =  $intersState');
 
-        if (intersState == AdState.ready) {
+        if (intersState == AdState.ready && shouldShowInterstitialAd("level_done", data.currentLevel - 1)) {
           // 这种情况表示有插屏广告在播放,需要等待广告关闭之后才能执行翻牌动画等逻辑
           interPending = true;
           _log.info('Interstitial ad is currently playing, will execute post-ad logic after dismissal.');

+ 18 - 13
lib/remote_config/remote_config.dart

@@ -3,13 +3,25 @@ import 'package:logging/logging.dart';
 
 ///firebase 远程参数配置封装
 class RemoteConfig {
-  ///配置参数
+  // 本地默认值常量
+  static const Map<String, dynamic> _defaults = {
+    "inters_free_levels": 3,
+    "enter_inters_free_duration": 5,
+    "quit_inters_free_duration": 3,
+    "rate_us_levels_count": 2,
+    "ad_revenue_threshold": 0.01,
+    "banner_free_duration": 10,
+    "ad_crash_prone_devices": "hisense,itel,huawei y9",
+  };
+
+  ///配置参数(带默认值回退)
   int get intersFreeLevels => _remoteConfig.getInt('inters_free_levels');
   int get enterIntersFreeDuration => _remoteConfig.getInt('enter_inters_free_duration');
   int get quitIntersFreeDuration => _remoteConfig.getInt('quit_inters_free_duration');
   int get rateUsLevelCount => _remoteConfig.getInt('rate_us_levels_count');
   double get adRevenueThreshold => _remoteConfig.getDouble('ad_revenue_threshold');
   int get bannerFreeDuration => _remoteConfig.getInt('banner_free_duration');
+  String get adCrashProneDevices => _remoteConfig.getString('ad_crash_prone_devices');
 
   static final _log = Logger('RemoteConfig');
   RemoteConfig._internal();
@@ -19,8 +31,11 @@ class RemoteConfig {
   final _remoteConfig = FirebaseRemoteConfig.instance;
 
   Future<void> initialize() async {
+    // 立即同步设置默认值
+    await _remoteConfig.setDefaults(_defaults);
+    
     try {
-      // 异步执行,不阻塞 initialize 方法的返回
+      // 异步执行远程获取,不阻塞
       _realInit();
     } catch (e) {
       _log.warning("RemoteConfig setup triggered error: $e");
@@ -31,21 +46,11 @@ class RemoteConfig {
   Future<void> _realInit() async {
     await _remoteConfig.setConfigSettings(
       RemoteConfigSettings(
-        fetchTimeout: const Duration(seconds: 10), // 建议缩短超时时间,1分钟太久了
+        fetchTimeout: const Duration(seconds: 10),
         minimumFetchInterval: const Duration(hours: 1),
       ),
     );
 
-    ///参数默认值
-    await _remoteConfig.setDefaults(const {
-      "inters_free_levels": 3, // 新手无插屏广告的levels数,超过此数即可显示插屏
-      "enter_inters_free_duration": 5, // 进入游戏插屏广告新手保护时长,单位分
-      "quit_inters_free_duration": 3, // 退出游戏插屏广告新手保护时长,单位分
-      "rate_us_levels_count": 2, // 用户完成多少个拼图后可以弹出评分框
-      "ad_revenue_threshold": 0.01, // 广告累计收益上报阈值,单位美元
-      "banner_free_duration": 10, // banner广告新手保护时长,单位分
-    });
-
     _remoteConfig.onConfigUpdated.listen((event) async {
       await _remoteConfig.activate();
       _log.info("remoteConfig update triggered");