字节跳动穿山甲广告 Flutter版本
简介
flutter_unionad 是一款集成了穿山甲 Android / iOS / 鸿蒙 SDK 的 Flutter 插件,采用**联邦插件(Federated Plugin)**架构:
| 包名 | 说明 |
|---|---|
flutter_unionad |
对外统一 API / Widget,统一调度 |
unionad_interface |
平台接口层 |
unionad_android |
Android 实现 |
unionad_ios |
iOS 实现 |
unionad_ohos |
OpenHarmony 实现 |
业务侧只需依赖并使用 flutter_unionad,无需关心各端实现细节。
可通过 GTAds 实现多广告平台接入、统一管理。
API 说明:
appId、广告位codeId已统一为单参数,由调用方按当前平台自行传入对应 id(不再区分androidAppId/iosAppId/ohosAppId等)。
官方文档
版本更新
注意事项
⚠️ 版本更新必看,不然可能广告加载可能会出现异常
插件更新调整
⚠️ 由于融合SDK与旧版部分api不兼容,2.0.0改动较大,更新后注意查看文档说明
⚠️ 用 gromore 来创建广告位,使用 gromore id 来展示广告
⚠️ 如需需要集成聚合其他广告SDK,需要根据当前插件使用的版本引入对应版本的 Adapter 库,离线SDK,根据官方文档进行配置
工程结构
flutter_unionad/ # 仓库根目录
├── flutter_unionad/ # 主插件(统一 API)
│ ├── lib/
│ └── example/ # 示例工程
├── unionad_interface/ # 平台接口
├── unionad_android/ # Android 实现
├── unionad_ios/ # iOS 实现
└── unionad_ohos/ # 鸿蒙实现
集成步骤
1、添加依赖
pub.dev(发布后):
dependencies:
flutter_unionad: ^latest
本地 path(联邦插件开发):
dependencies:
flutter_unionad:
path: ../flutter_unionad # 指向主包目录
引入:
import 'package:flutter_unionad/flutter_unionad.dart';
2、Android
SDK 已配置在 unionad_android 中,只需在应用 android/app/src/main/AndroidManifest.xml 配置:
<manifest ···
xmlns:tools="http://schemas.android.com/tools"
···>
<application
android:usesCleartextTraffic="true"
tools:replace="android:label">
3、iOS
SDK 已配置在 unionad_ios 中,其余按官方文档配置。因使用 PlatformView,在 Info.plist 加入:
<key>io.flutter.embedded_views_preview</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
4、鸿蒙(OpenHarmony)
将示例中的 .ohpmrc 拷贝到你的鸿蒙工程根目录。
鸿蒙侧需使用 OpenHarmony Flutter SDK 构建(含 OhosView)。
使用
以下示例中的
appId/codeId请替换为你在穿山甲后台申请的、当前平台对应的 id。
可参考示例工程按平台切换 id 的写法:flutter_unionad/example/lib/ad_config.dart
1、SDK 初始化
⚠️ 如果要修改个性化配置,重新调用初始化方法。
await FlutterUnionad.register(
// 穿山甲 appId(按当前平台自行传入)
appId: "5098580",
// appname 必填
appName: "unionad_test",
// 使用聚合功能一定要打开此开关,否则不会请求聚合广告,默认这个值为 false
// true 使用 GroMore 下的广告位
// false 使用广告变现下的广告位
useMediation: true,
// 是否为计费用户 选填
paid: false,
// 用户画像的关键词列表 选填
keywords: "",
// 是否允许 sdk 展示通知栏提示 选填
allowShowNotify: true,
// 是否显示 debug 日志
debug: true,
// 是否支持多进程 选填
supportMultiProcess: false,
// 主题模式 默认 FlutterUnionAdTheme.DAY,修改后需重新调用初始化
themeStatus: _themeStatus,
// 允许直接下载的网络状态集合 选填
directDownloadNetworkType: [
FlutterUnionadNetCode.NETWORK_STATE_2G,
FlutterUnionadNetCode.NETWORK_STATE_3G,
FlutterUnionadNetCode.NETWORK_STATE_4G,
FlutterUnionadNetCode.NETWORK_STATE_WIFI
],
androidPrivacy: AndroidPrivacy(
isCanUseLocation: false,
lat: 0.0,
lon: 0.0,
isCanUsePhoneState: false,
imei: "",
isCanUseWifiState: false,
macAddress: "",
isCanUseWriteExternal: false,
oaid: "b69cd3cf68900323",
alist: false,
isCanUseAndroidId: false,
androidId: "",
isCanUsePermissionRecordAudio: false,
isLimitPersonalAds: false,
isProgrammaticRecommend: false,
userPrivacyConfig: {
"mcod": "0",
"installUninstallListen": "0",
}),
iosPrivacy: IOSPrivacy(
limitPersonalAds: false,
limitProgrammaticAds: false,
forbiddenCAID: false,
),
userInfo: UnionadUserInfo(
userId: "unionad_123",
age: 19,
gender: 2,
channel: "flutter",
subChannel: "flutter_unionad",
userValueGroup: "QQ",
customInfos: {
"QQ": "123",
"WeChat": "456",
}),
// 配置拉取失败时导入本地配置 https://www.csjplatform.com/supportcenter/5885
// android 导入 /android/app/src/main/assets/,文件必须为 json,传入文件名
// ios 导入 /ios/,文件必须为 json,传入文件名
localConfig: "site_config_5098580",
);
按平台传入 appId 示例:
import 'package:flutter/foundation.dart';
String get appId {
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
return "你的iOS_AppId";
case TargetPlatform.android:
return "你的Android_AppId";
default:
return "你的鸿蒙_AppId";
}
}
await FlutterUnionad.register(appId: appId, appName: "unionad_test", ...);
2、获取 SDK 版本
await FlutterUnionad.getSDKVersion();
3、请求权限
FlutterUnionad.requestPermissionIfNecessary(
callBack: FlutterUnionadPermissionCallBack(
notDetermined: () {
print("权限未确定");
},
restricted: () {
print("权限限制");
},
denied: () {
print("权限拒绝");
},
authorized: () {
print("权限同意");
},
),
);
Android 获取定位、照片权限,只返回成功。
Android 相关权限为非必须权限,可选择在 AndroidManifest.xml 中声明。
iOS 14 及以上获取 ATT 权限,根据返回结果处理业务逻辑。
4、开屏广告
FlutterUnionadSplashAdView(
// 广告位 id(按当前平台自行传入)
codeId: "102729400",
supportDeepLink: true,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height - 100,
hideSkip: false,
timeout: 3000,
callBack: FlutterUnionadSplashCallBack(
onShow: () {
print("开屏广告显示");
},
onClick: () {
print("开屏广告点击");
},
onFail: (error) {
print("开屏广告失败 $error");
Navigator.pop(context);
},
onFinish: () {
print("开屏广告倒计时结束");
Navigator.pop(context);
},
onSkip: () {
print("开屏广告跳过");
Navigator.pop(context);
},
onTimeOut: () {
print("开屏广告超时");
},
),
)
5、Banner 广告
FlutterUnionadBannerView(
// 广告位 id(按当前平台自行传入)
codeId: "102735527",
width: 600.5,
height: 120.5,
callBack: FlutterUnionadBannerCallBack(
onShow: () {
print("banner广告加载完成");
},
onDislike: (message) {
print("banner不感兴趣 $message");
},
onFail: (error) {
print("banner广告加载失败 $error");
},
onClick: () {
print("banner广告点击");
},
),
)
6、信息流广告
FlutterUnionadNativeAdView(
// 广告位 id(按当前平台自行传入)
codeId: "102730271",
supportDeepLink: true,
width: 375.5,
height: 0,
callBack: FlutterUnionadNativeCallBack(
onShow: () {
print("信息流广告显示");
},
onFail: (error) {
print("信息流广告失败 $error");
},
onDislike: (message) {
print("信息流广告不感兴趣 $message");
},
onClick: () {
print("信息流广告点击");
},
),
)
7、激励视频广告
预加载:
FlutterUnionad.loadRewardVideoAd(
// 广告位 id(按当前平台自行传入)
codeId: "102733764",
rewardName: "200金币",
rewardAmount: 200,
userID: "123",
orientation: FlutterUnionadOrientation.VERTICAL,
mediaExtra: null,
);
展示:
await FlutterUnionad.showRewardVideoAd();
结果监听:
FlutterUnionadStream.initAdStream(
flutterUnionadRewardAdCallBack: FlutterUnionadRewardAdCallBack(
onShow: () {
print("激励广告显示");
},
onClick: () {
print("激励广告点击");
},
onFail: (error) {
print("激励广告失败 $error");
},
onClose: () {
print("激励广告关闭");
},
onSkip: () {
print("激励广告跳过");
},
onVerify: (rewardVerify, rewardAmount, rewardName) {
print("激励广告奖励 $rewardVerify $rewardAmount $rewardName");
},
onReady: () async {
print("激励广告预加载准备就绪");
await FlutterUnionad.showRewardVideoAd();
},
onCache: () async {
print("激励广告物料缓存成功。建议在这里进行广告展示,可保证播放流畅和展示流畅,用户体验更好。");
},
onUnReady: () {
print("激励广告预加载未准备就绪");
},
onRewardArrived: (rewardVerify, rewardType, rewardAmount, rewardName,
errorCode, error, propose) {
print(
"阶段激励广告奖励 验证结果=$rewardVerify 奖励类型=$rewardType 奖励=$rewardAmount "
"奖励名称$rewardName 错误码=$errorCode 错误$error 建议奖励$propose");
},
),
);
8、Draw 视频广告
FlutterUnionadDrawFeedAdView(
// 广告位 id(按当前平台自行传入)
codeId: "102734241",
width: 600.5,
height: 800.5,
callBack: FlutterUnionadDrawFeedCallBack(
onShow: () {
print("draw广告显示");
},
onFail: (error) {
print("draw广告加载失败 $error");
},
onClick: () {
print("draw广告点击");
},
onDislike: (message) {
print("draw点击不喜欢 $message");
},
onVideoPlay: () {
print("draw视频播放");
},
onVideoPause: () {
print("draw视频暂停");
},
onVideoStop: () {
print("draw视频结束");
},
),
)
9、新模板渲染插屏(全屏 / 插屏)
预加载:
FlutterUnionad.loadFullScreenVideoAdInteraction(
// 广告位 id(按当前平台自行传入)
codeId: "102735530",
orientation: FlutterUnionadOrientation.VERTICAL,
);
展示:
await FlutterUnionad.showFullScreenVideoAdInteraction();
结果监听:
FlutterUnionadStream.initAdStream(
flutterUnionadNewInteractionCallBack: FlutterUnionadNewInteractionCallBack(
onShow: () {
print("新模板渲染插屏广告显示");
},
onSkip: () {
print("新模板渲染插屏广告跳过");
},
onClick: () {
print("新模板渲染插屏广告点击");
},
onFinish: () {
print("新模板渲染插屏广告结束");
},
onFail: (error) {
print("新模板渲染插屏广告错误 $error");
},
onClose: () {
print("新模板渲染插屏广告关闭");
},
onReady: () async {
print("新模板渲染插屏广告预加载准备就绪");
await FlutterUnionad.showFullScreenVideoAdInteraction();
},
onUnReady: () {
print("新模板渲染插屏广告预加载未准备就绪");
},
),
);
10、日间 / 夜间模式
获取主题模式:
// 0 正常模式 1 夜间模式
_themeStatus = await FlutterUnionad.getThemeStatus();
切换主题:修改初始化中的 themeStatus,重新调用初始化。
11、ecpm 说明
/// [adnName] ADN的名称,与平台配置一致,自定义ADN时为ADN唯一标识
/// [customAdnName] 自定义ADN的名称,与平台配置一致,非自定义ADN为nil
/// [slotID] 代码位
/// [levelTag] 价格标签,多阶底价下有效
/// [ecpm] 返回价格,nil为无权限
/// [biddingType] 广告类型
/// [errorMsg] 额外错误信息,一般为空(扩展字段)
/// [requestID] adn提供的真实广告加载ID,可为空
/// [creativeID] adn提供的真实广告创意ID,可为空
/// [adRitType] 广告位类型
/// [segmentId] 流量分组ID
/// [abtestId] AB实验分组ID
/// [channel] 渠道名称
/// [subChannel] 子渠道名称
/// [scenarioId] 场景ID
/// [subRitType] 混用类型,banner/fullVideo/rewardVideo/feed/draw/interstitial
常见问题
插件链接
| 插件 | 地址 |
|---|---|
| 字节-穿山甲广告插件 | flutter_unionad |
| 腾讯-优量汇广告插件 | flutter_tencentad |
| 百度-百青藤广告插件 | baiduad |
| 字节-Gromore聚合广告 | gromore |
| Sigmob广告 | sigmobad |
| 聚合广告插件(迁移至GTAds) | flutter_universalad |
| GTAds聚合广告 | GTAds |
| 字节穿山甲内容合作插件 | flutter_pangrowth |
| 文档预览插件 | file_preview |
| 滤镜 | gpu_image |
开源不易,觉得有用的话可以请作者喝杯奶茶🧋
联系方式
-
Email: gstory0404@gmail.com
-
blog:https://www.gstory.cn/
