🎯 广告类型
版本 GroMore
📰 信息流广告
信息流广告需要 先批量加载获取广告 ID,再结合 AdFeedWidget
在列表中渲染。
1. 加载与缓存 ID
import 'dart:collection';
class FeedAdRepository {
final String posId;
final Queue<int> _adIds = Queue<int>();
FeedAdRepository(this.posId);
Future<void> warmUp({int count = 3}) async {
final ids = await GromoreAds.loadFeedAd(
posId,
width: 375,
height: 300,
count: count,
);
_adIds.addAll(ids);
}
int? take() => _adIds.isNotEmpty ? _adIds.removeFirst() : null;
Future<void> clear() async {
if (_adIds.isEmpty) return;
await GromoreAds.clearFeedAd(_adIds.toList());
_adIds.clear();
}
}
🔁
loadFeedAd
返回的List<int>
为原生缓存广告的唯一 ID,后续 widget 渲染必须传入。
可选参数说明
loadFeedAd
支持透传常见的聚合配置,只有在显式传值时才会影响原生 SDK:
参数 | 类型 | 说明 |
---|---|---|
mutedIfCan | bool | 首次展示时优先静音(Android/iOS 均生效) |
volume | double | [Android] 自定义音量,范围 0.0~1.0 ,仅在 mutedIfCan 为 false 时生效 |
bidNotify | bool | 打开竞价结果回调,方便记录填充来源 |
scenarioId | String | 透传 GroMore 场景 ID,便于服务端报表归因 |
useSurfaceView | bool | Android 独有:强制使用 SurfaceView 渲染视频素材 |
extra | Map<String, dynamic> | 聚合额外参数,仅 Android 侧通过 MediationAdSlot#setExtraObject 生效;iOS 目前忽略 |
📌 未传递的字段会保留 GroMore SDK 默认值,避免出现“自以为是”的默认配置。
2. 在列表中渲染
class FeedListPage extends StatefulWidget {
const FeedListPage({super.key});
@override
State<FeedListPage> createState() => _FeedListPageState();
}
class _FeedListPageState extends State<FeedListPage> {
late final FeedAdRepository _repo;
final List<_FeedItem> _items = [];
@override
void initState() {
super.initState();
_repo = FeedAdRepository('feed_pos_id');
_loadData();
}
Future<void> _loadData() async {
await _repo.warmUp(count: 2);
const articles = [
'新品上市', '热门专题', '运营活动', '使用技巧', '会员权益',
];
for (var i = 0; i < articles.length; i++) {
_items.add(_FeedItem.text(articles[i]));
if ((i + 1) % 2 == 0) {
final adId = _repo.take();
if (adId != null) {
_items.add(_FeedItem.ad(adId));
}
}
}
setState(() {});
}
@override
void dispose() {
_repo.clear();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _items.length,
itemBuilder: (context, index) {
final item = _items[index];
return item.when(
text: (title) => ListTile(title: Text(title)),
ad: (adId) => SizedBox(
height: 300,
child: AdFeedWidget(
posId: _repo.posId,
adId: adId,
width: MediaQuery.of(context).size.width,
height: 300,
onAdError: (error) => debugPrint('feed ad error: $error'),
),
),
);
},
);
}
}
class _FeedItem {
final int? adId;
final String? title;
const _FeedItem._({this.adId, this.title});
static _FeedItem text(String title) => _FeedItem._(title: title);
static _FeedItem ad(int adId) => _FeedItem._(adId: adId);
T when<T>({required T Function(String) text, required T Function(int) ad}) {
return adId != null ? ad(adId!) : text(title!);
}
}
3. 清理
- 调用
GromoreAds.clearFeedAd(adIds)
释放已不需要的广告。 - 页面销毁时务必清理缓存的 ID,避免原生侧持有无效视图。
4. AdFeedWidget 参数
参数 | 类型 | 说明 |
---|---|---|
posId | String | 信息流广告位 ID |
adId | int | loadFeedAd 返回的广告 ID |
width / height | double | 期望的渲染尺寸(像素) |
isVisible | bool | 是否渲染,默认 true |
onAdLoaded 等回调 | 同步原生侧渲染状态 |
掌握上述步骤即可将原生信息流广告无缝嵌入列表内容中。