⚡ 高级功能
版本 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,
})
参数说明
参数名 | 类型 | 必填 | 默认值 | 说明 | 平台支持 |
---|---|---|---|---|---|
configs | List<PreloadConfig> | ✅ | - | 预加载配置列表,不能为空 | 全平台 |
parallelNum | int? | ❌ | 2 | 并发加载数量,范围[1-20] | 全平台 |
requestIntervalS | int? | ❌ | 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_feed | Draw信息流 | PreloadConfig.drawFeed(['id1']) |
PreloadConfig.banner([...]) | banner | Banner横幅 | PreloadConfig.banner(['id1']) |
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
adType | String | ✅ | 广告类型,使用便捷构造方法时自动设置 |
adIds | List<String> | ✅ | 广告位ID列表,可传入多个广告位 |
options | Map<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)
参数名 | 类型 | 说明 | 示例值 |
---|---|---|---|
userId | String? | 用户唯一标识 | 'user_123' |
customData | Object? | 服务端验证透传参数,支持Map或String | {'order': '123'} |
rewardName | String? | 奖励名称 | '金币' |
rewardAmount | int? | 奖励数量 | 50 |
mutedIfCan | bool? | 是否静音 | true |
bidNotify | bool? | 竞价结果通知 | true |
scenarioId | String? | 场景ID | 'level_complete' |
extraParams | Map? | 额外参数(Android) | {} |
extraData | String? | 额外数据(iOS) | '' |
PreloadConfig.rewardVideo(
['reward_id'],
options: {
'userId': 'player_001',
'customData': {'stage': 5, 'level': 10},
'rewardName': '金币',
'rewardAmount': 100,
'mutedIfCan': true,
'scenarioId': 'game_reward',
},
)
插屏广告 (interstitial)
参数名 | 类型 | 说明 | 示例值 |
---|---|---|---|
orientation | int? | 屏幕方向: 1=竖屏, 2=横屏 | 1 |
mutedIfCan | bool? | 是否静音 | true |
bidNotify | bool? | 竞价结果通知 | true |
scenarioId | String? | 场景ID | 'pause_page' |
extraParams | Map? | 额外参数(Android) | {} |
extraData | String? | 额外数据(iOS) | '' |
PreloadConfig.interstitial(
['interstitial_id'],
options: {
'orientation': 1, // 竖屏
'mutedIfCan': false,
'scenarioId': 'level_pause',
},
)
信息流广告 (feed)
参数名 | 类型 | 说明 | 示例值 |
---|---|---|---|
width | int? | 广告宽度(px) | 320 |
height | int? | 广告高度(px) | 180 |
count | int? | 预加载数量,最多3 | 3 |
mutedIfCan | bool? | 是否静音(视频广告) | true |
bidNotify | bool? | 竞价结果通知 | true |
scenarioId | String? | 场景ID | 'home_feed' |
extra | Map? | 额外参数 | {} |
PreloadConfig.feed(
['feed_id'],
options: {
'width': 320,
'height': 180,
'count': 3, // 预加载3条
'mutedIfCan': true,
'scenarioId': 'home_timeline',
},
)
Draw信息流广告 (draw_feed)
参数名 | 类型 | 说明 | 示例值 |
---|---|---|---|
width | int? | 广告宽度(px) | 360 |
height | int? | 广告高度(px) | 640 |
count | int? | 预加载数量,最多3 | 2 |
mutedIfCan | bool? | 是否静音 | true |
bidNotify | bool? | 竞价结果通知 | true |
scenarioId | String? | 场景ID | 'video_feed' |
extra | Map? | 额外参数 | {} |
PreloadConfig.drawFeed(
['draw_id'],
options: {
'width': 360,
'height': 640,
'count': 2,
'scenarioId': 'short_video',
},
)
Banner横幅广告 (banner)
参数名 | 类型 | 说明 | 示例值 |
---|---|---|---|
width | int? | Banner宽度(px) | 600 |
height | int? | Banner高度(px) | 100 |
bidNotify | bool? | 竞价结果通知 | true |
scenarioId | String? | 场景ID | 'article_bottom' |
extraParams | Map? | 额外参数(Android) | {} |
extraData | String? | 额外数据(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: 不会影响。预加载失败后:
- 正式调用
loadRewardVideoAd
等API时会重新加载 - 只是失去了"秒开"的优势
- 不会抛出异常影响应用运行
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: 不能。预加载只是请求广告,还需要:
- 监听
xxx_loaded
事件确认加载成功 - 调用对应的
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平台上均完整支持预加载功能:
广告类型 | Android | iOS | 说明 |
---|---|---|---|
激励视频 | ✅ | ✅ | 完整支持 |
插屏广告 | ✅ | ✅ | 完整支持 |
Feed信息流 | ✅ | ✅ | 完整支持 |
DrawFeed | ✅ | ✅ | 完整支持 |
Banner横幅 | ✅ | ✅ | 完整支持 |
并发控制参数
参数 | Android | iOS | 说明 |
---|---|---|---|
parallelNum | ✅ | ✅ | 取值范围[1-20],超出自动调整 |
requestIntervalS | ✅ | ✅ | 取值范围[1-10]秒,超出自动调整 |
💡 提示: 两端行为完全一致,无需编写平台特定代码。