短剧内容
短剧内容
此章节将演示如何请求在Flutter
环境下请求与展示短剧内容
短剧运行流程
引入组件
注意
使用短剧内容组件
加载时,需要确保 Android 的MainActivity
继承io.flutter.embedding.android.FlutterFragmentActivity
,Flutter会默认继承 io.flutter.embedding.android.FlutterActivity
。详见example/MainActivity
引入ZJTubeAdView
组件即可请求信息流广告
/// 短剧视图
class ZJTubeAdView extends StatefulWidget {
/// 广告位ID
final String posId;
/// 宽
final double width;
/// 高
final double height;
/// 配置
final ZJTubeAdConfig? config;
/// 回调
final Function(ZJEvent ret)? tubeAdListener;
/// 展示自定义短剧解锁对话框回调
final TubeAdShowCustomUnlockDialogCallback? showCustomUnlockDialogCallback;
/// 短剧解锁结果回调
final TubeAdUnlockCallback? unlockCallback;
/// 创建成功通知
final ZJTubeAdViewCreated onCreatedCallback;
const ZJTubeAdView(this.posId,
{Key? key,
required this.width,
required this.height,
this.config,
this.tubeAdListener,
this.showCustomUnlockDialogCallback,
this.unlockCallback,
required this.onCreatedCallback})
: super(key: key);
}
短剧配置说明
ZJTubeAdConfig.class
属性 | 类型 | 说明 | 默认值 |
---|---|---|---|
userId | String | 用户ID | "" |
freeEpisodeCount | int | 每个剧集前N集免费 | 3 |
unlockEpisodeCount | int | 每次解锁X集 | 2 |
isHideTitleBar | bool | 是否隐藏剧集主页的TitleBar | true |
isDisableUnlockTipDialog | bool | 是否关闭SDK的解锁提示对话框 | false |
isDisableShowTubePanelEntry | bool | 是否关闭短剧播放页的选集入口 | false |
isHideDetailTitleBar | bool | 是否隐藏播放页的titleBar | false |
isHideDetailBottomTitle | bool | 是否隐藏播放页底部的title文案 | false |
isHideDetailBottomDesc | bool | 是否隐藏播放页底部的内容描述文案 | false |
isHideDetailPlaySeekbar | bool | 是否隐藏播放页底部的进度条 | false |
lib/widget/zj_tube_ad_view.dart
/// 短剧配置
class ZJTubeAdConfig {
/// 用户ID
final String userId;
/// 每个剧集前N集免费,默认值3
final int freeEpisodeCount;
/// 每次解锁X集,默认值2
final int unlockEpisodeCount;
/// 是否隐藏剧集主页的TitleBar,默认值true
final bool isHideTitleBar;
/// 是否关闭SDK的解锁提示对话框,默认值false
final bool isDisableUnlockTipDialog;
/// 是否关闭短剧播放页的选集入口,默认值false
final bool isDisableShowTubePanelEntry;
/// 是否隐藏播放页的titleBar,默认值false
final bool isHideDetailTitleBar;
/// 是否隐藏播放页底部的title文案,默认值false
final bool isHideDetailBottomTitle;
/// 是否隐藏播放页底部的内容描述文案,默认值false
final bool isHideDetailBottomDesc;
/// 是否隐藏播放页底部的进度条,默认值false
final bool isHideDetailPlaySeekbar;
ZJTubeAdConfig(
{this.userId = "",
this.freeEpisodeCount = 3,
this.unlockEpisodeCount = 2,
this.isHideTitleBar = true,
this.isDisableUnlockTipDialog = false,
this.isDisableShowTubePanelEntry = false,
this.isHideDetailTitleBar = false,
this.isHideDetailBottomTitle = false,
this.isHideDetailBottomDesc = false,
this.isHideDetailPlaySeekbar = false});
}
短剧内容回调说明
广告加载展示回调
ret.action | 说明 |
---|---|
ZJEventAction.onAdError | 广告加载失败 ret.code:错误码,非错误事件为0 ret.msg:错误信息,非错误事件为空字符串 |
自定义短剧解锁对话框回调
当ZJTubeAdView
配置了isDisableUnlockTipDialog=true
时,需要配置TubeAdShowCustomUnlockDialogCallback
并根据返回的ZJTubeAdItem
对象展示解锁对话框,最后返回用户是否同意观看广告并解锁:
typedef Future<bool> TubeAdShowCustomUnlockDialogCallback(ZJTubeAdItem adItem);
ZJTubeAdItem
ZJTubeAdItem.class
属性 | 类型 | 说明 | 默认值 |
---|---|---|---|
id | String | 视频唯一ID | "" |
position | int | 当前位置,从0开始 | 0 |
videoDuration | int | 视频时长 | 0 |
authorId | String | 作者ID | "" |
authorName | String | 作者鸣潮 | "" |
tubeId | int | 剧场ID | 0 |
tubeName | String | 剧场鸣潮 | "" |
episodeNumber | int | 剧集序号 | 0 |
totalEpisodeCount | int | 总剧集数 | 0 |
playCount | int | 观看次数 | 0 |
coverUrl | String | 封面图 | "" |
isFinished | bool | 是否已完结 | false |
isLocked | bool | 是否锁定 | false |
freeEpisodeCount | int | 短剧前N集免费 | 0 |
unlockEpisodeCount | int | 每次解锁X集短剧 | 0 |
lib/widget/zj_tube_ad_view.dart
/// 短剧对象
class ZJTubeAdItem {
/// 视频唯一ID
String id = "";
/// 当前位置,从0开始
int position = 0;
/// 视频时长
int videoDuration = 0;
/// 作者ID
String authorId = "";
/// 作者鸣潮
String authorName = "";
/// 剧场ID
int tubeId = 0;
/// 剧场鸣潮
String tubeName = "";
/// 剧集序号
int episodeNumber = 0;
/// 总剧集数
int totalEpisodeCount = 0;
/// 观看次数
int playCount = 0;
/// 封面图
String coverUrl = "";
/// 是否已完结
bool isFinished = false;
/// 是否锁定
bool isLocked = false;
/// 短剧前N集免费
int freeEpisodeCount = 0;
/// 每次解锁X集短剧
int unlockEpisodeCount = 0;
}
短剧解锁结果回调
ZJTubeAdView
的unlockCallback
类型为TubeAdUnlockCallback
,会在解锁广告请求失败或解锁成功时回调,包含当次解锁的结果及错误时的错误信息:
typedef void TubeAdUnlockCallback(bool isSuccess, int errCode, String? errMsg);
创建成功通知
ZJTubeAdView
的onCreatedCallback
类型为ZJTubeAdViewCreated
,会在组件成功创建后返回一个ZJTubeAdViewController
对象,用于配置解锁短剧所需的广告位ID及控制组件的显示和隐藏。
typedef void ZJTubeAdViewCreated(ZJTubeAdViewController controller);
ZJTubeAdViewController
ZJTubeAdViewController
包含以下方法:
方法 | 说明 |
---|---|
hide() | 隐藏组件 |
show() | 显示组件 |
setUnlockAdPosId(String posId) | 配置解锁时的广告位ID,仅支持激励广告和插屏 |
onResume() | 通知SDK页面恢复 |
接入示例
example/lib/ad/tube_ad.dart
child: ZJTubeAdView(
posId,
width: double.infinity,
height: double.infinity,
config: ZJTubeAdConfig(
userId: TestPosId.testUserId, isHideTitleBar: true),
// 禁用SDK自带的解锁对话框时,需要展示自定义解锁对话框并返回用户是否同意的状态
showCustomUnlockDialogCallback: _showCustomUnlockDialog,
// 短剧解锁结果回调
unlockCallback: _onUnlockCallback,
onCreatedCallback: _onTubeAdViewCreated,
tubeAdListener: (ret) {
if (ret.action == ZJEventAction.onAdError) {
Fluttertoast.showToast(msg: "视频内容错误:${ret.msg}");
if (kDebugMode) {
print("${ret.action}:${ret.code}-${ret.msg}");
}
_reset();
}
},
)
/// 展示短剧组件到容器中
void _show() {
if (controller == null) {
setState(() {
showTubeView = true;
});
} else {
controller!.show();
}
}
/// 隐藏短剧组件
void _hide() {
if (controller == null) {
Fluttertoast.showToast(msg: "还未加载成功");
} else {
// 隐藏
controller!.hide();
}
}
/// 禁用SDK自带的解锁对话框时,需要展示自定义解锁对话框并返回用户是否同意的状态
Future<bool> _showCustomUnlockDialog(ZJTubeAdItem adItem) async {
Completer<bool> completer = Completer();
/// 在展示自定义解锁对话框后回调结果
completer.complete(Random().nextBool()); // 此处模拟用户随机同意/取消解锁
return completer.future;
}
/// 短剧解锁结果回调
/// 成功时code==0,msg==null
/// 失败时code!=0,msg!=null
/// 失败事件不一定触发,成功事件一定触发
void _onUnlockCallback(bool isSuccess, int errCode, String? errMsg) {
if (isSuccess) {
Fluttertoast.showToast(msg: "解锁成功");
} else {
Fluttertoast.showToast(msg: "解锁失败[$errCode-$errMsg]");
}
}
/// 以Widget加载时的组件控制器
void _onTubeAdViewCreated(ZJTubeAdViewController controller) {
this.controller = controller;
// 在创建视图成功后,需要配置解锁需要的广告位ID(仅支持激励广告和插全屏广告)
this.controller!.setUnlockAdPosId(Random().nextBool()
? TestPosId.rewardVideoPosId
: TestPosId.interstitialPosId);
}