高级功能
版本 GroMore

简介

预加载(Preload)是一种广告优化策略,在应用启动或页面初始化时提前加载广告,以提升后续展示的响应速度和成功率。

为什么需要预加载

在实际应用中,广告加载通常需要1-3秒的网络请求时间。如果用户点击"观看广告"后才开始加载,会导致:

  • 用户等待时间长:1-3秒的加载时间影响体验
  • 加载失败率高:网络波动导致广告无法展示
  • 收益流失:用户等待期间可能放弃观看

使用预加载可以:

  • 秒开广告:提前加载完成,点击即可展示
  • 提升填充率:避免网络波动导致的加载失败
  • 优化体验:消除用户等待,提升满意度
  • 增加收益:更高的展示率带来更多收益

预加载特点

  • 批量配置:一次性配置多个广告类型和广告位
  • 并发控制:支持控制并发数,避免资源竞争
  • 间隔请求:支持设置请求间隔,平衡加载速度和资源消耗
  • 全平台支持:Android和iOS完全一致的行为

快速开始

最小示例(30秒可运行)

import 'package:gromore_ads/gromore_ads.dart';

// 预加载激励视频和插屏广告
await GromoreAds.preload(
  configs: [
    PreloadConfig.rewardVideo(['your_reward_video_ad_id']),
    PreloadConfig.interstitial(['your_interstitial_ad_id']),
  ],
);

完整示例(含常用配置)

import 'package:gromore_ads/gromore_ads.dart';

class AdPreloadManager {
  /// 在应用启动时调用
  static Future<void> preloadAdsOnAppStart() async {
    try {
      await GromoreAds.preload(
        configs: [
          // 激励视频广告 - 带奖励信息
          PreloadConfig.rewardVideo(
            ['reward_pos_id_1', 'reward_pos_id_2'],
            options: {
              'userId': 'user_123',
              'rewardName': '金币',
              'rewardAmount': 50,
              'mutedIfCan': true,
            },
          ),

          // 插屏广告 - 竖屏模式
          PreloadConfig.interstitial(
            ['interstitial_pos_id'],
            options: {
              'orientation': 1,  // 1=竖屏, 2=横屏
              'scenarioId': 'home_page',
            },
          ),

          // 信息流广告 - 指定宽高
          PreloadConfig.feed(
            ['feed_pos_id'],
            options: {
              'width': 320,   // 单位: px
              'height': 180,  // 单位: px
              'count': 3,     // 预加载3条
            },
          ),

          // Draw信息流广告
          PreloadConfig.drawFeed(['draw_pos_id']),

          // Banner横幅广告
          PreloadConfig.banner(
            ['banner_pos_id'],
            options: {
              'width': 600,
              'height': 100,
            },
          ),
        ],
        parallelNum: 2,        // 并发数: 同时加载2个广告
        requestIntervalS: 2,   // 请求间隔: 每个请求间隔2秒
      );

      print('✅ 广告预加载完成');
    } catch (e) {
      print('❌ 广告预加载失败: $e');
    }
  }
}

// 在应用启动时调用
void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 初始化GroMore SDK
  await GromoreAds.init(/* ... */);

  // 预加载广告
  await AdPreloadManager.preloadAdsOnAppStart();

  runApp(MyApp());
}

API参考

preload - 批量预加载广告

Future<bool> preload({
  required List<PreloadConfig> configs,
  int? parallelNum,
  int? requestIntervalS,
})

参数说明

参数名类型必填默认值说明平台支持
configsList<PreloadConfig>-预加载配置列表,不能为空全平台
parallelNumint?2并发加载数量,范围[1-20]全平台
requestIntervalSint?2请求间隔(秒),范围[1-10]全平台

返回值

返回Future<bool>,表示预加载请求是否成功提交。

并发控制说明

  • parallelNum: 控制同时进行的广告加载数量

    • 取值范围: [1-20]
    • 默认值: 2
    • 建议值: 2-3(平衡速度和资源)
    • 超出范围会自动调整到边界值
  • requestIntervalS: 控制每个广告请求的间隔时间

    • 取值范围: [1-10]秒
    • 默认值: 2秒
    • 建议值: 2-3秒(避免并发冲突)
    • 超出范围会自动调整到边界值

示例

// 基础用法 - 使用默认并发参数
await GromoreAds.preload(
  configs: [
    PreloadConfig.rewardVideo(['reward_id']),
    PreloadConfig.interstitial(['interstitial_id']),
  ],
);

// 完整配置 - 自定义并发参数
await GromoreAds.preload(
  configs: [
    PreloadConfig.rewardVideo(['reward_id_1', 'reward_id_2']),
    PreloadConfig.interstitial(['interstitial_id']),
    PreloadConfig.feed(['feed_id']),
  ],
  parallelNum: 3,        // 同时加载3个
  requestIntervalS: 2,   // 间隔2秒
);

// 异常处理
try {
  await GromoreAds.preload(configs: []);
} catch (e) {
  // ❌ 抛出 ArgumentError: configs cannot be empty when calling preload
  print('configs不能为空: $e');
}

PreloadConfig - 预加载配置

class PreloadConfig {
  final String adType;
  final List<String> adIds;
  final Map<String, dynamic>? options;

  const PreloadConfig({
    required this.adType,
    required this.adIds,
    this.options,
  });
}

便捷构造方法

构造方法adType适用场景示例
PreloadConfig.rewardVideo([...])reward_video激励视频PreloadConfig.rewardVideo(['id1', 'id2'])
PreloadConfig.interstitial([...])interstitial插屏/全屏PreloadConfig.interstitial(['id1'])
PreloadConfig.feed([...])feed信息流PreloadConfig.feed(['id1'])
PreloadConfig.drawFeed([...])draw_feedDraw信息流PreloadConfig.drawFeed(['id1'])
PreloadConfig.banner([...])bannerBanner横幅PreloadConfig.banner(['id1'])

参数说明

参数名类型必填说明
adTypeString广告类型,使用便捷构造方法时自动设置
adIdsList<String>广告位ID列表,可传入多个广告位
optionsMap<String, dynamic>?广告加载参数,与正式加载API的参数保持一致

示例

// 基础用法 - 不带options
PreloadConfig.rewardVideo(['reward_id'])

// 带options - 预加载时配置参数
PreloadConfig.rewardVideo(
  ['reward_id'],
  options: {
    'userId': 'user_123',
    'rewardName': '金币',
    'rewardAmount': 50,
  },
)

// 多个广告位
PreloadConfig.feed(
  ['feed_id_1', 'feed_id_2', 'feed_id_3'],
  options: {
    'width': 320,
    'height': 180,
    'count': 2,
  },
)

// 扩展新类型(如果需要)
PreloadConfig(
  adType: 'custom_ad_type',
  adIds: ['custom_id'],
)

options - 广告加载参数

options字段用于配置预加载时的广告参数,必须与正式加载时的参数保持一致,否则无法命中缓存。

激励视频 (reward_video)

参数名类型说明示例值
userIdString?用户唯一标识'user_123'
customDataObject?服务端验证透传参数,支持Map或String{'order': '123'}
rewardNameString?奖励名称'金币'
rewardAmountint?奖励数量50
mutedIfCanbool?是否静音true
bidNotifybool?竞价结果通知true
scenarioIdString?场景ID'level_complete'
extraParamsMap?额外参数(Android){}
extraDataString?额外数据(iOS)''
PreloadConfig.rewardVideo(
  ['reward_id'],
  options: {
    'userId': 'player_001',
    'customData': {'stage': 5, 'level': 10},
    'rewardName': '金币',
    'rewardAmount': 100,
    'mutedIfCan': true,
    'scenarioId': 'game_reward',
  },
)

插屏广告 (interstitial)

参数名类型说明示例值
orientationint?屏幕方向: 1=竖屏, 2=横屏1
mutedIfCanbool?是否静音true
bidNotifybool?竞价结果通知true
scenarioIdString?场景ID'pause_page'
extraParamsMap?额外参数(Android){}
extraDataString?额外数据(iOS)''
PreloadConfig.interstitial(
  ['interstitial_id'],
  options: {
    'orientation': 1,  // 竖屏
    'mutedIfCan': false,
    'scenarioId': 'level_pause',
  },
)

信息流广告 (feed)

参数名类型说明示例值
widthint?广告宽度(px)320
heightint?广告高度(px)180
countint?预加载数量,最多33
mutedIfCanbool?是否静音(视频广告)true
bidNotifybool?竞价结果通知true
scenarioIdString?场景ID'home_feed'
extraMap?额外参数{}
PreloadConfig.feed(
  ['feed_id'],
  options: {
    'width': 320,
    'height': 180,
    'count': 3,  // 预加载3条
    'mutedIfCan': true,
    'scenarioId': 'home_timeline',
  },
)

Draw信息流广告 (draw_feed)

参数名类型说明示例值
widthint?广告宽度(px)360
heightint?广告高度(px)640
countint?预加载数量,最多32
mutedIfCanbool?是否静音true
bidNotifybool?竞价结果通知true
scenarioIdString?场景ID'video_feed'
extraMap?额外参数{}
PreloadConfig.drawFeed(
  ['draw_id'],
  options: {
    'width': 360,
    'height': 640,
    'count': 2,
    'scenarioId': 'short_video',
  },
)

Banner横幅广告 (banner)

参数名类型说明示例值
widthint?Banner宽度(px)600
heightint?Banner高度(px)100
bidNotifybool?竞价结果通知true
scenarioIdString?场景ID'article_bottom'
extraParamsMap?额外参数(Android){}
extraDataString?额外数据(iOS)''
PreloadConfig.banner(
  ['banner_id'],
  options: {
    'width': 600,
    'height': 100,
    'scenarioId': 'content_footer',
  },
)

重要说明

⚠️ 缓存命中要求: options中的参数必须与正式加载时的参数完全一致,否则无法命中预加载缓存,SDK会重新发起请求。

ℹ️ customData支持: customData参数支持直接传入Map对象,插件会自动序列化为JSON字符串传递给原生SDK。

实战场景示例

场景1: 游戏应用 - 分阶段预加载

游戏中不同场景需要不同类型的广告,根据用户进度动态调整预加载策略。

class GameAdManager {
  /// 应用启动时 - 预加载高频广告
  static Future<void> preloadOnAppStart() async {
    await GromoreAds.preload(
      configs: [
        // 激励视频 - 复活、奖励等高频场景
        PreloadConfig.rewardVideo(
          ['reward_revive', 'reward_coin'],
          options: {
            'userId': 'player_${getCurrentUserId()}',
            'mutedIfCan': false,  // 保持声音增强吸引力
          },
        ),

        // Banner - 主界面底部常驻
        PreloadConfig.banner(
          ['banner_main'],
          options: {
            'width': 600,
            'height': 100,
          },
        ),
      ],
      parallelNum: 2,
      requestIntervalS: 2,
    );
    print('✅ 游戏启动预加载完成');
  }

  /// 关卡开始前 - 预加载关卡相关广告
  static Future<void> preloadOnLevelStart() async {
    await GromoreAds.preload(
      configs: [
        // 插屏广告 - 关卡暂停、失败时展示
        PreloadConfig.interstitial(
          ['interstitial_pause', 'interstitial_fail'],
          options: {
            'orientation': 1,  // 竖屏游戏
            'scenarioId': 'level_${getCurrentLevel()}',
          },
        ),

        // 激励视频 - 跳过关卡、额外道具
        PreloadConfig.rewardVideo(
          ['reward_skip', 'reward_power_up'],
          options: {
            'userId': 'player_${getCurrentUserId()}',
            'rewardName': '金币',
            'rewardAmount': 50,
            'scenarioId': 'level_reward',
          },
        ),
      ],
      parallelNum: 2,
      requestIntervalS: 1,  // 关卡间歇快速加载
    );
  }

  /// 长时间游戏后 - 刷新广告缓存
  static Future<void> refreshAds() async {
    // 先清理过期的信息流广告
    await GromoreAds.clearFeedAd();

    // 重新预加载
    await preloadOnAppStart();
  }
}

// 使用示例
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await GromoreAds.init(/* ... */);

  // 应用启动时预加载
  await GameAdManager.preloadOnAppStart();

  runApp(MyGameApp());
}

// 关卡开始时
void onLevelStart() {
  GameAdManager.preloadOnLevelStart();
}

// 每30分钟刷新一次广告
Timer.periodic(Duration(minutes: 30), (_) {
  GameAdManager.refreshAds();
});

场景2: 内容应用 - 分页场景预加载

新闻、视频类应用根据用户浏览的页面预加载对应的广告。

class ContentAdManager {
  /// 首页 - 预加载信息流和Banner
  static Future<void> preloadForHomePage() async {
    await GromoreAds.preload(
      configs: [
        // 信息流广告 - 插入文章列表中
        PreloadConfig.feed(
          ['feed_home_1', 'feed_home_2'],
          options: {
            'width': 320,
            'height': 180,
            'count': 3,  // 每个广告位预加载3条
            'mutedIfCan': true,  // 自动播放视频时静音
            'scenarioId': 'home_timeline',
          },
        ),

        // Banner广告 - 底部固定
        PreloadConfig.banner(
          ['banner_home'],
          options: {
            'width': 600,
            'height': 100,
            'scenarioId': 'home_page',
          },
        ),
      ],
      parallelNum: 2,
      requestIntervalS: 2,
    );
  }

  /// 视频页 - 预加载Draw信息流和激励视频
  static Future<void> preloadForVideoPage() async {
    await GromoreAds.preload(
      configs: [
        // Draw信息流 - 短视频列表
        PreloadConfig.drawFeed(
          ['draw_video'],
          options: {
            'width': 360,
            'height': 640,
            'count': 2,
            'mutedIfCan': false,  // 视频页允许声音
            'scenarioId': 'video_feed',
          },
        ),

        // 激励视频 - 解锁高清、去广告
        PreloadConfig.rewardVideo(
          ['reward_hd', 'reward_no_ads'],
          options: {
            'userId': 'user_${getCurrentUserId()}',
            'rewardName': 'VIP时长',
            'rewardAmount': 60,  // 60分钟
            'scenarioId': 'video_reward',
          },
        ),
      ],
      parallelNum: 2,
      requestIntervalS: 2,
    );
  }

  /// 文章详情页 - 预加载插屏和Banner
  static Future<void> preloadForArticlePage() async {
    await GromoreAds.preload(
      configs: [
        // 插屏广告 - 阅读完成后展示
        PreloadConfig.interstitial(
          ['interstitial_article_end'],
          options: {
            'orientation': 1,
            'scenarioId': 'article_complete',
          },
        ),

        // Banner广告 - 文章底部
        PreloadConfig.banner(
          ['banner_article'],
          options: {
            'width': 600,
            'height': 100,
            'scenarioId': 'article_footer',
          },
        ),
      ],
      parallelNum: 2,
      requestIntervalS: 2,
    );
  }
}

// 页面路由监听
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorObservers: [AdPreloadNavigatorObserver()],
      home: HomePage(),
    );
  }
}

// 路由切换时自动预加载对应广告
class AdPreloadNavigatorObserver extends NavigatorObserver {
  @override
  void didPush(Route route, Route? previousRoute) {
    super.didPush(route, previousRoute);
    _preloadForRoute(route.settings.name);
  }

  void _preloadForRoute(String? routeName) {
    switch (routeName) {
      case '/home':
        ContentAdManager.preloadForHomePage();
        break;
      case '/video':
        ContentAdManager.preloadForVideoPage();
        break;
      case '/article':
        ContentAdManager.preloadForArticlePage();
        break;
    }
  }
}

场景3: 工具应用 - 用户行为驱动预加载

根据用户的使用频率和偏好动态调整预加载策略。

class SmartAdPreloadManager {
  /// 根据用户行为数据决定预加载策略
  static Future<void> preloadBasedOnUserBehavior() async {
    final userProfile = await getUserProfile();
    final configs = <PreloadConfig>[];

    // 高频用户 - 预加载全部广告类型
    if (userProfile.dailyUsageMinutes > 60) {
      configs.addAll([
        PreloadConfig.rewardVideo(
          ['reward_main'],
          options: {
            'userId': userProfile.userId,
            'rewardName': '会员时长',
            'rewardAmount': 30,
          },
        ),
        PreloadConfig.interstitial(['interstitial_main']),
        PreloadConfig.banner(['banner_main']),
      ]);
    }
    // 中频用户 - 只预加载激励视频和Banner
    else if (userProfile.dailyUsageMinutes > 20) {
      configs.addAll([
        PreloadConfig.rewardVideo(['reward_main']),
        PreloadConfig.banner(['banner_main']),
      ]);
    }
    // 低频用户 - 只预加载Banner(不影响体验)
    else {
      configs.add(PreloadConfig.banner(['banner_main']));
    }

    // 如果用户最近点击过激励视频,增加激励视频的预加载
    if (userProfile.recentRewardVideoClicks > 0) {
      configs.add(
        PreloadConfig.rewardVideo(
          ['reward_extra_1', 'reward_extra_2'],
          options: {
            'userId': userProfile.userId,
            'mutedIfCan': false,
          },
        ),
      );
    }

    if (configs.isEmpty) return;

    await GromoreAds.preload(
      configs: configs,
      parallelNum: configs.length > 3 ? 3 : 2,
      requestIntervalS: 2,
    );
  }

  /// 网络状态变化时调整策略
  static Future<void> preloadOnNetworkChange(ConnectivityResult connectivity) async {
    switch (connectivity) {
      case ConnectivityResult.wifi:
        // WiFi环境 - 预加载所有类型,提高并发
        await GromoreAds.preload(
          configs: [
            PreloadConfig.rewardVideo(['reward_1', 'reward_2']),
            PreloadConfig.interstitial(['interstitial_1']),
            PreloadConfig.feed(['feed_1']),
            PreloadConfig.banner(['banner_1']),
          ],
          parallelNum: 4,  // WiFi下可以提高并发
          requestIntervalS: 1,
        );
        break;

      case ConnectivityResult.mobile:
        // 移动网络 - 只预加载小文件广告
        await GromoreAds.preload(
          configs: [
            PreloadConfig.banner(['banner_1']),
            PreloadConfig.interstitial(['interstitial_1']),
          ],
          parallelNum: 2,
          requestIntervalS: 3,  // 移动网络延长间隔
        );
        break;

      default:
        // 无网络 - 不预加载
        break;
    }
  }
}

// 应用启动时根据用户行为预加载
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await GromoreAds.init(/* ... */);

  // 智能预加载
  await SmartAdPreloadManager.preloadBasedOnUserBehavior();

  // 监听网络变化
  Connectivity().onConnectivityChanged.listen((result) {
    SmartAdPreloadManager.preloadOnNetworkChange(result);
  });

  runApp(MyApp());
}

最佳实践

1. 选择合适的预加载时机

// ✅ 推荐: 应用启动后预加载
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await GromoreAds.init(/* ... */);

  // 在用户看到首页前完成预加载
  await GromoreAds.preload(configs: [/* ... */]);

  runApp(MyApp());
}

// ✅ 推荐: 页面初始化时预加载
@override
void initState() {
  super.initState();
  _preloadAds();
}

// ❌ 不推荐: 用户点击时才预加载(失去了预加载的意义)
void onButtonClick() {
  await GromoreAds.preload(configs: [/* ... */]);  // 太晚了!
  await GromoreAds.showRewardVideoAd('reward_id');
}

2. 合理设置并发参数

// ✅ 推荐: 少量广告用默认值
await GromoreAds.preload(
  configs: [
    PreloadConfig.rewardVideo(['id1']),
    PreloadConfig.banner(['id2']),
  ],
  // 不传parallelNum和requestIntervalS,使用默认值(2, 2)
);

// ✅ 推荐: 多个广告适当提高并发
await GromoreAds.preload(
  configs: [
    PreloadConfig.rewardVideo(['id1', 'id2']),
    PreloadConfig.interstitial(['id3']),
    PreloadConfig.feed(['id4']),
    PreloadConfig.banner(['id5']),
  ],
  parallelNum: 3,        // 提高到3
  requestIntervalS: 2,
);

// ❌ 不推荐: 并发过高导致资源竞争
await GromoreAds.preload(
  configs: [/* 很多广告位 */],
  parallelNum: 20,       // 太高!会导致部分请求失败
  requestIntervalS: 0,   // 无间隔!会被SDK限流
);

3. 确保options参数一致

// ✅ 正确: 预加载和正式加载的参数一致
// 预加载时
await GromoreAds.preload(
  configs: [
    PreloadConfig.rewardVideo(
      ['reward_id'],
      options: {
        'userId': 'user_123',
        'rewardName': '金币',
        'rewardAmount': 50,
      },
    ),
  ],
);

// 正式展示时 - 参数完全一致
await GromoreAds.loadRewardVideoAd(
  'reward_id',
  userId: 'user_123',        // ✅ 一致
  rewardName: '金币',        // ✅ 一致
  rewardAmount: 50,          // ✅ 一致
);

// ❌ 错误: 参数不一致导致无法命中缓存
await GromoreAds.preload(
  configs: [
    PreloadConfig.rewardVideo(
      ['reward_id'],
      options: {
        'userId': 'user_123',
        'rewardAmount': 50,    // 预加载时是50
      },
    ),
  ],
);

// 正式加载时参数不同
await GromoreAds.loadRewardVideoAd(
  'reward_id',
  userId: 'user_456',        // ❌ userId不同
  rewardAmount: 100,         // ❌ rewardAmount不同
);
// 结果: 无法命中预加载缓存,SDK会重新请求

4. 定期刷新广告缓存

class AdCacheManager {
  Timer? _refreshTimer;

  /// 启动自动刷新
  void startAutoRefresh() {
    // 每30分钟刷新一次广告
    _refreshTimer = Timer.periodic(Duration(minutes: 30), (_) async {
      print('🔄 开始刷新广告缓存');

      // 清理过期的信息流广告
      await GromoreAds.clearFeedAd();
      await GromoreAds.clearDrawFeedAd();

      // 重新预加载
      await GromoreAds.preload(
        configs: [
          PreloadConfig.rewardVideo(['reward_id']),
          PreloadConfig.feed(['feed_id']),
        ],
      );

      print('✅ 广告缓存刷新完成');
    });
  }

  /// 停止自动刷新
  void stopAutoRefresh() {
    _refreshTimer?.cancel();
    _refreshTimer = null;
  }
}

// 应用使用
final adCacheManager = AdCacheManager();

@override
void initState() {
  super.initState();
  adCacheManager.startAutoRefresh();
}

@override
void dispose() {
  adCacheManager.stopAutoRefresh();
  super.dispose();
}

5. 分场景配置预加载策略

class AdPreloadStrategy {
  /// 首页场景 - 预加载高频广告
  static Future<void> preloadForHomePage() async {
    await GromoreAds.preload(
      configs: [
        PreloadConfig.rewardVideo(['reward_main']),
        PreloadConfig.banner(['banner_main']),
      ],
      parallelNum: 2,
      requestIntervalS: 2,
    );
  }

  /// 游戏场景 - 预加载激励视频和插屏
  static Future<void> preloadForGamePage() async {
    await GromoreAds.preload(
      configs: [
        PreloadConfig.rewardVideo(['reward_revive', 'reward_coin']),
        PreloadConfig.interstitial(['interstitial_pause']),
      ],
      parallelNum: 3,
      requestIntervalS: 1,  // 游戏场景加快间隔
    );
  }

  /// 内容场景 - 预加载信息流
  static Future<void> preloadForContentPage() async {
    await GromoreAds.preload(
      configs: [
        PreloadConfig.feed(['feed_article']),
        PreloadConfig.banner(['banner_article']),
      ],
      parallelNum: 2,
      requestIntervalS: 2,
    );
  }
}

6. 错误处理和降级方案

class SafeAdPreloader {
  static Future<void> preloadWithFallback() async {
    try {
      // 尝试预加载
      await GromoreAds.preload(
        configs: [
          PreloadConfig.rewardVideo(['reward_id']),
          PreloadConfig.banner(['banner_id']),
        ],
      ).timeout(Duration(seconds: 10));

      print('✅ 预加载成功');

    } on TimeoutException {
      print('⚠️ 预加载超时,将在展示时实时加载');

    } catch (e) {
      print('❌ 预加载失败: $e');
      print('⚠️ 将在展示时实时加载');

      // 可选: 记录到监控系统
      // analytics.logError('preload_failed', error: e);
    }
  }
}

常见问题

Q1: 预加载后多久会过期?

A: 广告的有效期由GroMore平台和各广告平台(ADN)决定:

  • 激励视频/插屏: 通常有效期30-60分钟
  • 信息流/Banner: 通常有效期10-30分钟
  • 建议: 每30分钟刷新一次广告缓存

Q2: 如何判断预加载是否成功?

A: 可以通过监听广告事件来判断:

_subscription = GromoreAds.onRewardVideoEvents(
  'reward_video_pos_id',
  onLoaded: (event) {
    print('✅ 激励视频预加载成功: ${event.posId}');
  },
  onError: (event) {
    print('❌ 激励视频预加载失败: ${event.posId}');
    print('错误信息: ${event.message} (${event.code})');
  },
);

Q3: parallelNum设置为多少最合适?

A: 建议根据广告数量调整:

  • 1-3个广告位: parallelNum = 2(默认值)
  • 4-6个广告位: parallelNum = 3
  • 7个以上广告位: parallelNum = 3-4

不建议超过5,因为:

  • 并发过高会导致网络拥塞
  • 可能触发广告平台的请求限流
  • 资源竞争导致部分请求失败

Q4: 预加载会增加多少流量消耗?

A: 流量消耗取决于广告类型:

  • Banner: 约50-200KB/个
  • 插屏: 约200-500KB/个
  • 激励视频: 约2-10MB/个
  • 信息流: 约100-500KB/条

优化建议:

  • WiFi环境下预加载视频广告
  • 移动网络下只预加载图片类广告
  • 使用count参数控制信息流预加载数量

Q5: 预加载失败会影响正式加载吗?

A: 不会影响。预加载失败后:

  1. 正式调用loadRewardVideoAd等API时会重新加载
  2. 只是失去了"秒开"的优势
  3. 不会抛出异常影响应用运行

Q6: 同一个广告位预加载多次会怎样?

A:

  • 第二次预加载会覆盖第一次的缓存
  • 建议避免频繁预加载同一个广告位
  • 如需刷新,先调用clearXxxAd清理旧缓存
// ❌ 不推荐: 短时间内重复预加载
await GromoreAds.preload(configs: [PreloadConfig.rewardVideo(['id'])]);
await Future.delayed(Duration(seconds: 5));
await GromoreAds.preload(configs: [PreloadConfig.rewardVideo(['id'])]);  // 浪费

// ✅ 推荐: 合理的刷新策略
await GromoreAds.preload(configs: [PreloadConfig.rewardVideo(['id'])]);
// ... 30分钟后
await GromoreAds.preload(configs: [PreloadConfig.rewardVideo(['id'])]);  // 刷新

Q7: 预加载后可以立即展示吗?

A: 不能。预加载只是请求广告,还需要:

  1. 监听xxx_loaded事件确认加载成功
  2. 调用对应的showXxxAd方法展示
bool _isRewardLoaded = false;

// 1. 预加载
await GromoreAds.preload(
  configs: [PreloadConfig.rewardVideo(['reward_id'])],
);

// 2. 监听加载成功事件
_subscription = GromoreAds.onRewardVideoEvents(
  'reward_id',
  onLoaded: (event) {
    _isRewardLoaded = true;
    print('✅ 广告加载成功');
  },
);

// 3. 展示前检查
if (_isRewardLoaded) {
  await GromoreAds.showRewardVideoAd('reward_id');
} else {
  print('⚠️ 广告尚未加载完成');
}

Q8: 预加载会影响应用启动速度吗?

A: 影响很小,因为:

  • 预加载是异步操作,不会阻塞主线程
  • 可以在用户看到首页后再预加载
  • 预加载失败不影响应用正常运行
// ✅ 推荐: 不阻塞应用启动
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await GromoreAds.init(/* ... */);

  // 先启动应用
  runApp(MyApp());

  // 后台预加载(不await)
  GromoreAds.preload(configs: [/* ... */]);
}

平台支持说明

全平台支持

所有广告类型在Android和iOS平台上均完整支持预加载功能:

广告类型AndroidiOS说明
激励视频完整支持
插屏广告完整支持
Feed信息流完整支持
DrawFeed完整支持
Banner横幅完整支持

并发控制参数

参数AndroidiOS说明
parallelNum取值范围[1-20],超出自动调整
requestIntervalS取值范围[1-10]秒,超出自动调整

💡 提示: 两端行为完全一致,无需编写平台特定代码。

相关文档

需要进一步协助?

与 LightCore 技术顾问沟通,获取商业化策略与集成支持。