🎯 广告类型
版本 GroMore
📺 插屏广告
插屏广告(全屏视频/插页)建议采用“先缓存、后展示”的流程。
1. 基本流程
import 'package:gromore_ads/gromore_ads.dart';
class InterstitialController {
final String posId;
bool _isReady = false;
InterstitialController(this.posId);
/// 预加载广告
Future<void> preload() async {
try {
final ok = await GromoreAds.loadInterstitialAd(
posId,
orientation: vertical, // 或 horizontal
mutedIfCan: true,
);
_isReady = ok;
} catch (e) {
debugPrint('插屏广告加载失败: $e');
_isReady = false;
}
}
/// 展示广告(如未加载会先尝试加载)
Future<bool> show() async {
// 检查是否已加载
if (!_isReady) {
await preload();
}
// 加载失败,返回false
if (!_isReady) {
debugPrint('广告未就绪,无法展示');
return false;
}
try {
final ok = await GromoreAds.showInterstitialAd(posId);
if (ok) {
_isReady = false; // 展示后需重新加载
}
return ok;
} catch (e) {
debugPrint('插屏广告展示失败: $e');
_isReady = false;
return false;
}
}
}
🎯 要点:
showInterstitialAd
仅在已经加载成功的情况下才会返回true
- 必须使用 try-catch 处理加载和展示过程中的异常
- 展示成功后
_isReady
应重置为false
,避免重复展示
2. 参数配置详解
2.1 完整参数表
参数 | 类型 | 必需/可选 | 默认值 | 平台支持 | 说明 |
---|---|---|---|---|---|
posId | String | 必需 | - | 全平台 | 广告位ID |
orientation | int? | 可选 | vertical (1) | 全平台 | 方向(vertical =1, horizontal =2) |
mutedIfCan | bool? | 可选 | SDK默认 | 全平台 | 聚合SDK静音开关 |
volume | double? | 可选 | 1.0 | [Android] | 音量(0.0~1.0) |
bidNotify | bool? | 可选 | false | 全平台 | 是否回传竞价结果 |
scenarioId | String? | 可选 | null | 全平台 | 自定义场景ID |
useSurfaceView | bool? | 可选 | false | [Android] | 是否使用SurfaceView播放 |
showDirection | int? | 可选 | SDK默认 | [iOS] | 聚合额外方向配置 |
rewardName | String? | 可选 | null | [iOS] | 奖励名称(GDT渠道专用) |
rewardAmount | int? | 可选 | null | [iOS] | 奖励数量(GDT渠道专用) |
customData | String? | 可选 | null | 全平台 | 透传到原生的自定义数据(用于奖励校验) |
extraData | Map? | 可选 | null | 全平台 | Android渠道扩展字段 |
extraParams | Map? | 可选 | null | 全平台 | iOS渠道扩展字段 |
2.2 参数使用原则
⚠️ 重要:仅传递需要自定义的可选参数,其余保持
null
即可让 SDK 使用默认行为。
参数传递策略:
- ✅ 只传递显式需要的参数
- ✅ 未传递的参数会让SDK使用原生默认值
- ❌ 不要为所有参数设置默认值(会破坏SDK的原生行为)
3. 平台差异说明
3.1 Android专属参数
以下参数仅在 Android 平台生效,iOS 平台会自动忽略:
参数 | 类型 | 说明 | 使用场景 |
---|---|---|---|
volume | double? | 音量(0.0~1.0) | 需要精确控制音量时使用 |
useSurfaceView | bool? | 使用SurfaceView播放 | 解决部分设备渲染问题 |
示例:
// Android专属配置(iOS会忽略这些参数)
await GromoreAds.loadInterstitialAd(
posId,
volume: 0.5, // @android 仅Android支持
useSurfaceView: true, // @android 仅Android支持
);
3.2 iOS专属参数
以下参数仅在 iOS 平台生效,Android 平台会自动忽略:
参数 | 类型 | 说明 | 使用场景 |
---|---|---|---|
showDirection | int? | 聚合额外方向配置 | 需要特殊方向控制时使用 |
rewardName | String? | 奖励名称(GDT渠道) | 接入GDT渠道时使用 |
rewardAmount | int? | 奖励数量(GDT渠道) | 接入GDT渠道时使用 |
示例:
// iOS专属配置(Android会忽略这些参数)
await GromoreAds.loadInterstitialAd(
posId,
showDirection: 1, // @ios 仅iOS支持
rewardName: '金币', // @ios GDT渠道专用
rewardAmount: 100, // @ios GDT渠道专用
);
3.3 跨平台开发建议
方式1:统一配置(推荐)
// 直接传递所有参数,平台会自动忽略不支持的参数
await GromoreAds.loadInterstitialAd(
posId,
orientation: vertical,
mutedIfCan: true,
volume: 0.5, // Android使用,iOS忽略
showDirection: 1, // iOS使用,Android忽略
);
方式2:平台判断
import 'dart:io';
await GromoreAds.loadInterstitialAd(
posId,
orientation: vertical,
mutedIfCan: true,
volume: Platform.isAndroid ? 0.5 : null,
showDirection: Platform.isIOS ? 1 : null,
);
💡 推荐做法:使用方式1(统一配置),代码更简洁,平台会自动处理参数差异。
4. 典型使用场景
- 游戏关卡结束:关卡结束后调用
show()
,并在事件监听里根据interstitial_closed
继续游戏。 - 功能解锁:用户完成某个步骤后展示一次,事件
interstitial_clicked
可用于统计转化。 - 冷启动欢迎页:配合开屏广告预加载,减少等待时间。
5. 与事件结合
import 'package:gromore_ads/gromore_ads.dart';
class GameInterstitialListener extends OnAdEventListener {
@override
void onAdEvent(AdEvent event) {
switch (event.action) {
case 'interstitial_load_success':
debugPrint('插屏广告加载成功');
break;
case 'interstitial_load_fail':
debugPrint('插屏广告加载失败: ${event.extra}');
break;
case 'interstitial_show':
debugPrint('插屏广告开始展示');
break;
case 'interstitial_click':
debugPrint('插屏广告被点击');
break;
case 'interstitial_close':
debugPrint('插屏广告关闭');
_resumeGameplay();
break;
}
}
@override
void onAdError(AdErrorEvent event) {
debugPrint('插屏广告错误: ${event.message}');
}
void _resumeGameplay() {
// 恢复游戏逻辑
}
}
// 注册事件监听
AdEventSubscription? _subscription;
void initAds() {
_subscription = GromoreAds.onInterstitialEvents(
'your_interstitial_id',
onLoaded: (event) => _controller.markReady(),
onShowed: (event) => _controller.pauseGameplay(),
onClosed: (event) => _controller.resumeGameplay(),
onError: (event) => debugPrint('❌ 错误: ${event.message}'),
);
}
将事件监听与控制器组合,即可实现完整的插屏广告生命周期管理。
6. 常见问题与故障排查
6.1 广告未就绪无法展示
问题:调用 showInterstitialAd
返回 false
原因:
- 广告未加载完成就尝试展示
- 广告已展示过,需要重新加载
- 加载失败但未检查状态
解决方案:
class InterstitialController {
bool _isReady = false;
Future<bool> show() async {
// ✅ 正确:先检查是否就绪
if (!_isReady) {
debugPrint('广告未就绪,先加载');
await preload();
}
if (!_isReady) {
debugPrint('加载失败,无法展示');
return false;
}
final ok = await GromoreAds.showInterstitialAd(posId);
if (ok) {
_isReady = false; // ✅ 展示后重置状态
}
return ok;
}
}
6.2 广告加载失败
常见原因:
- 广告位ID错误:检查posId是否正确
- SDK未初始化:确保在调用前已初始化SDK
- 网络问题:检查设备网络连接
- 频次限制:广告请求过于频繁被限制
- 无广告填充:当前时段无可用广告
调试步骤:
// 1. 启用调试模式
await GromoreAds.initAd(
appId,
useMediation: true,
debugMode: true, // 开启调试
);
// 2. 监听加载事件
_subscription = GromoreAds.onInterstitialEvents(
'your_interstitial_id',
onLoaded: (event) {
debugPrint('✅ 插屏广告加载成功');
},
onError: (event) {
debugPrint('❌ 错误码: ${event.code}');
debugPrint('错误信息: ${event.message}');
debugPrint('广告位: ${event.posId}');
},
);
6.3 展示时机控制
问题:如何在合适的时机展示广告?
建议:
// ✅ 正确:预加载 + 延迟展示
class GameLevelController {
final _interstitial = InterstitialController(posId);
void onLevelStart() {
// 关卡开始时预加载广告
_interstitial.preload();
}
void onLevelComplete() {
// 关卡结束后展示广告
_interstitial.show();
}
}
// ❌ 错误:临时加载,用户等待时间长
void onLevelComplete() {
await GromoreAds.loadInterstitialAd(posId); // 用户需要等待
await GromoreAds.showInterstitialAd(posId);
}
6.4 如何避免重复展示
问题:同一个广告被展示多次
解决方案:
class InterstitialController {
bool _isShowing = false;
Future<bool> show() async {
// ✅ 防止重复展示
if (_isShowing) {
debugPrint('广告正在展示中');
return false;
}
_isShowing = true;
try {
final ok = await GromoreAds.showInterstitialAd(posId);
return ok;
} finally {
_isShowing = false;
}
}
}
6.5 调试建议
- 启用GroMore调试工具:
await GromoreAds.launchTestTools(); // 启动官方调试工具
- 查看详细日志:
await GromoreAds.initAd(
appId,
useMediation: true,
debugMode: true, // 输出详细日志
);
- 使用单元测试页面:
- 验证参数配置是否正确
- 测试平台差异处理
- 检查事件回调是否完整
💡 提示:遇到问题时,优先检查事件回调日志,大多数问题都能从事件中找到原因。