📺 短剧聚合页
短剧聚合页提供短剧聚合浏览、分类筛选、置顶推荐、播放解锁和商业化能力。插件同时支持 NativeView 组件(推荐)与 API 控制 两种接入方式,可根据业务形态灵活选择。
🚪 接入方式概览
方式 | 推荐场景 | 实现特点 |
---|---|---|
NativeView 组件(推荐) | Flutter 页面内嵌短剧内容,追求最快集成 | DramaHomeNativeView 自动管理创建/销毁,Flutter 布局友好 |
API 调用 | 需要在原生 Activity / ViewController 中展示,或兼容历史流程 | createDramaHome / showDramaHome / destroyDramaHome 主动控制生命周期 |
✅ 方式一:使用 DramaHomeNativeView
(推荐)
DramaHomeNativeView
通过 PlatformView 内嵌原生聚合页,Flutter 端仅需像普通 Widget 一样使用。
基础用法
import 'package:flutter/material.dart';
import 'package:pangrowth_content/pangrowth_content.dart';
class DramaHomePage extends StatelessWidget {
const DramaHomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('短剧推荐')),
body: DramaHomeNativeView(
config: const DramaHomeConfig(
showBackBtn: false, // 已有 AppBar,不需要原生返回按钮
freeEpisodesCount: 3, // 默认提供 3 集免费内容
unlockEpisodesCountUsingAd: 2, // 激励广告解锁 2 集
),
),
);
}
}
监听聚合页生命周期
通过 DramaHomeListener
获取组件创建、销毁及错误信息,便于埋点或自定义 UI:
class DramaHomeWithListenerPage extends StatefulWidget {
const DramaHomeWithListenerPage({super.key});
@override
State<DramaHomeWithListenerPage> createState() => _DramaHomeWithListenerPageState();
}
class _DramaHomeWithListenerPageState extends State<DramaHomeWithListenerPage> {
String? _viewId;
bool _isLoading = true;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('短剧推荐')),
body: Stack(
children: [
DramaHomeNativeView(
config: const DramaHomeConfig(
showBackBtn: false,
freeEpisodesCount: 3,
unlockEpisodesCountUsingAd: 2,
),
listener: DramaHomeListener(
onHomeReady: (viewId) {
setState(() {
_viewId = viewId;
_isLoading = false;
});
debugPrint('✅ 聚合页就绪: $viewId');
},
onHomeDisposed: () {
debugPrint('🗑️ 聚合页已释放');
},
onHomeError: (error) {
setState(() {
_isLoading = false;
});
debugPrint('❌ 聚合页加载失败: $error');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('聚合页加载失败,请稍后重试')),
);
},
),
),
if (_isLoading)
const Center(
child: CircularProgressIndicator(),
),
],
),
);
}
}
TabBar 场景示例
在 TabBar 中使用短剧聚合页,配合其他内容页面:
class MainTabPage extends StatelessWidget {
const MainTabPage({super.key});
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
title: const Text('首页'),
bottom: const TabBar(
tabs: [
Tab(icon: Icon(Icons.home), text: '推荐'),
Tab(icon: Icon(Icons.video_library), text: '短剧'),
Tab(icon: Icon(Icons.person), text: '我的'),
],
),
),
body: TabBarView(
children: [
const Center(child: Text('推荐页面')),
// 短剧聚合页
DramaHomeNativeView(
config: const DramaHomeConfig(
showBackBtn: false, // TabBar中不需要返回按钮
freeEpisodesCount: 5,
unlockEpisodesCountUsingAd: 2,
),
),
const Center(child: Text('我的页面')),
],
),
),
);
}
}
自定义置顶短剧
通过 topDramaId
或 topDramaIds
参数指定置顶推荐的短剧:
// 单个置顶短剧
DramaHomeNativeView(
config: const DramaHomeConfig(
topDramaId: 1008, // 置顶短剧ID
freeEpisodesCount: 3,
),
)
// 多个置顶短剧
DramaHomeNativeView(
config: const DramaHomeConfig(
topDramaIds: ['1008', '1009', '1010'], // 多个置顶短剧ID
freeEpisodesCount: 3,
),
)
自定义播放详情页 UI
通过各种 hide*
参数控制播放详情页的 UI 元素显示:
// 简洁模式:隐藏大部分UI元素
DramaHomeNativeView(
config: const DramaHomeConfig(
freeEpisodesCount: 3,
// 隐藏播放详情页的各种UI元素
hideTopInfo: true, // 隐藏顶部信息区
hideBottomInfo: false, // 保留底部交互按钮
hideBack: true, // 隐藏返回按钮(使用Flutter返回)
hideMore: true, // 隐藏更多按钮
hideLikeIcon: false, // 保留点赞按钮
hideFavorIcon: false, // 保留收藏按钮
hideRewardDialog: false, // 使用SDK默认解锁弹窗
),
)
自定义解锁弹窗
隐藏 SDK 默认解锁弹窗,使用 Flutter 自定义弹窗:
DramaHomeNativeView(
config: const DramaHomeConfig(
freeEpisodesCount: 3,
unlockEpisodesCountUsingAd: 2,
hideRewardDialog: true, // ⚠️ 隐藏SDK默认弹窗,使用自定义弹窗
),
listener: DramaHomeListener(
onHomeReady: (viewId) {
debugPrint('聚合页就绪: $viewId');
},
// 监听短剧点击、搜索等事件...
),
)
生命周期管理
DramaHomeNativeView
自动管理聚合页生命周期:
- 创建: Widget
initState
时自动创建原生视图 - 显示: Widget
build
时自动显示 - 销毁: Widget
dispose
时自动销毁原生视图
生命周期约束:
- 单实例约束:插件内部限制同一时刻仅允许存在一个聚合页实例,创建新的
DramaHomeNativeView
前需确保旧实例已被销毁 - 平台视图限制:PlatformView 由原生渲染,避免在其上方叠加
Positioned
/Stack
等复杂布局 - 销毁策略:
DramaHomeNativeView
在dispose
阶段会自动调用PangrowthContent.destroyDramaHome
,如果在外层缓存了viewId
,可在自定义流程中重复调用(幂等)
🧭 方式二:使用 API 控制聚合页
API 方式用于历史项目兼容或需要原生容器承载的场景。插件内部已将 createDramaHome
/ showDramaHome
标记为 @Deprecated
,如无特殊需求,仍建议优先选择 NativeView 方案。
调用流程
createDramaHome(config: ...)
创建聚合页,获得widgetId
showDramaHome(widgetId)
打开原生聚合页页面(Android 启动 Activity,iOS 推入控制器)- 页面结束时调用
destroyDramaHome(widgetId)
释放资源
参考实现
class DramaHomeLauncher {
String? _widgetId;
Future<void> openDramaHome() async {
final result = await PangrowthContent.createDramaHome(
config: const DramaHomeConfig(
showBackBtn: true,
freeEpisodesCount: 3,
unlockEpisodesCountUsingAd: 2,
),
);
if (result['success'] != true) {
debugPrint('创建聚合页失败: $result');
return;
}
_widgetId = result['widgetId'] as String;
debugPrint('✅ 创建聚合页成功: $_widgetId');
await PangrowthContent.showDramaHome(_widgetId!);
debugPrint('✅ 显示聚合页成功');
}
Future<void> dispose() async {
if (_widgetId != null) {
await PangrowthContent.destroyDramaHome(_widgetId!);
debugPrint('✅ 销毁聚合页成功');
_widgetId = null;
}
}
}
// 使用示例
final launcher = DramaHomeLauncher();
// 打开聚合页
await launcher.openDramaHome();
// 页面退出时销毁
await launcher.dispose();
destroyDramaHome
为幂等调用,即使聚合页已关闭再次调用也不会抛出异常。
🧩 配置参数详解(DramaHomeConfig
)
以下参数两种接入方式均可使用,未显式赋值时会使用 SDK 默认值。
聚合页界面配置
参数 | 类型 | 平台支持 | 说明 | 默认值 |
---|---|---|---|---|
showChangeBtn | bool? | 🤖 Android | 是否展示热门推荐区域的"换一换"按钮 | null(SDK默认) |
showPageTitle | bool? | 🤖 Android | 是否展示页面标题栏(iOS 使用系统导航栏) | null(SDK默认) |
showBackBtn | bool? | ✅ 双端 | 是否展示聚合页返回按钮,Flutter 层会自动映射到 iOS 导航栏 | null(SDK默认) |
topOffset | int? | 🤖 Android | 调整聚合页顶部内容偏移量(dp),适配自定义标题栏 | null |
内容配置
参数 | 类型 | 平台支持 | 说明 | 默认值 |
---|---|---|---|---|
topDramaId | int? | ✅ 双端 | 指定单个置顶短剧 ID,展示在热门推荐最左侧 | null |
topDramaIds | List<String>? | ✅ 双端 | 指定多个置顶短剧 ID,优先级高于 topDramaId | null |
播放控制
参数 | 类型 | 平台支持 | 说明 | 约束 | 默认值 |
---|---|---|---|---|---|
freeEpisodesCount | int? | ✅ 双端 | 免费连看集数 | ≤20 集且不超过总集数的 20%(取其中较大值) | null(SDK默认) |
unlockEpisodesCountUsingAd | int? | ✅ 双端 | 激励广告解锁的集数 | 单个激励视频最多解锁 10 集 | null(SDK默认) |
播放详情页 UI 控制
参数 | 类型 | 平台支持 | 说明 | 默认值 |
---|---|---|---|---|
hideTopInfo | bool? | ✅ 双端 | 隐藏播放详情页顶部信息区 | null(SDK默认) |
hideBottomInfo | bool? | ✅ 双端 | 隐藏播放详情页底部交互按钮区 | null(SDK默认) |
hideBack | bool? | ✅ 双端 | 隐藏播放详情页内部的返回按钮 | null(SDK默认) |
hideMore | bool? | ✅ 双端 | 隐藏"更多"按钮(举报等入口) | null(SDK默认) |
hideLikeIcon | bool? | ✅ 双端 | 隐藏点赞按钮 | null(SDK默认) |
hideFavorIcon | bool? | ✅ 双端 | 隐藏收藏按钮 | null(SDK默认) |
hideRewardDialog | bool? | ✅ 双端 | 隐藏 SDK 内置激励解锁弹窗,便于自定义 UI | null(SDK默认) |
enableInfiniteScroll | bool? | ✅ 双端 | 开启后自动轮播下一部短剧(iOS 内部取反处理) | null(SDK默认) |
iOS 导航栏配置
参数 | 类型 | 平台支持 | 说明 | 默认值 |
---|---|---|---|---|
isShowNavigationItemBackButton | bool? | 🍎 iOS | 控制导航栏返回按钮显示,showBackBtn 会自动映射到此参数 | null(SDK默认) |
isShowNavigationItemTitle | bool? | 🍎 iOS | 控制导航栏标题显示 | null(SDK默认) |
其他配置
参数 | 类型 | 平台支持 | 说明 | 默认值 |
---|---|---|---|---|
extra | Map<String, dynamic>? | ✅ 双端 | 自定义扩展字段,将在事件回调中透传 | null |
📡 事件监听
组件级事件(DramaHomeListener
)
通过 DramaHomeListener
获取组件的生命周期事件,适合更新 Flutter UI 状态:
DramaHomeNativeView(
config: const DramaHomeConfig(freeEpisodesCount: 3),
listener: DramaHomeListener(
onHomeReady: (viewId) {
debugPrint('✅ 聚合页就绪: $viewId');
// 可在此处执行埋点上报等操作
},
onHomeDisposed: () {
debugPrint('🗑️ 聚合页已释放');
},
onHomeError: (error) {
debugPrint('❌ 聚合页加载失败: $error');
// 显示错误提示
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('聚合页加载失败,请稍后重试')),
);
},
),
)
可用回调:
onHomeReady(String viewId)
- 聚合页创建完成onHomeDisposed()
- 聚合页已销毁onHomeError(String error)
- 聚合页加载失败onItemClick(DramaInfo drama)
- 用户点击短剧卡片onSearch(String keyword)
- 触发搜索onCategorySwitch(String category)
- 分类标签切换
💡 使用场景与实践
场景1:首页短剧推荐
在首页展示短剧聚合页,作为主要内容入口:
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('首页'),
actions: [
IconButton(
icon: const Icon(Icons.search),
onPressed: () {
// 跳转到搜索页
},
),
],
),
body: DramaHomeNativeView(
config: const DramaHomeConfig(
showBackBtn: false, // 首页不需要返回按钮
freeEpisodesCount: 5,
unlockEpisodesCountUsingAd: 2,
),
),
);
}
}
场景2:VIP专区
为 VIP 用户提供更多免费集数和无限轮播:
class VipDramaPage extends StatelessWidget {
const VipDramaPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('VIP专区')),
body: DramaHomeNativeView(
config: const DramaHomeConfig(
showBackBtn: false,
freeEpisodesCount: 999, // VIP用户无限免费
unlockEpisodesCountUsingAd: 0, // 不需要广告解锁
enableInfiniteScroll: true, // 自动轮播下一部短剧
),
),
);
}
}
场景3:活动推广页
指定置顶推荐的短剧,用于活动推广:
class PromotionDramaPage extends StatelessWidget {
const PromotionDramaPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('热门推荐')),
body: DramaHomeNativeView(
config: const DramaHomeConfig(
showBackBtn: false,
topDramaIds: [
'1008', // 推广短剧1
'1009', // 推广短剧2
'1010', // 推广短剧3
],
freeEpisodesCount: 3,
showChangeBtn: false, // Android: 隐藏"换一换"按钮
),
),
);
}
}
场景4:自定义标题栏(Android)
使用自定义标题栏,调整聚合页的顶部偏移:
class CustomHeaderDramaPage extends StatelessWidget {
const CustomHeaderDramaPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
// 自定义标题栏(高度 56dp)
Container(
height: 56,
color: Colors.blue,
child: const SafeArea(
bottom: false,
child: Center(
child: Text(
'短剧推荐',
style: TextStyle(color: Colors.white, fontSize: 18),
),
),
),
),
// 短剧聚合页
Expanded(
child: DramaHomeNativeView(
config: const DramaHomeConfig(
showBackBtn: false,
showPageTitle: false, // Android: 隐藏SDK默认标题栏
topOffset: 56, // Android: 顶部偏移56dp
freeEpisodesCount: 3,
),
),
),
],
),
);
}
}
🛠️ 故障排查
问题1:聚合页无法创建或显示空白
可能原因:
- 未完成插件初始化,确保调用了
PangrowthContent.start()
- 穿山甲SDK配置不正确,检查
appId
和appName
是否正确 - 单实例约束:已存在一个聚合页实例未销毁
解决方法:
// 1. 确保在使用聚合页前完成初始化
await PangrowthContent.start(
startDrama: true, // 启动短剧功能
);
// 2. 验证配置是否正确
DramaHomeNativeView(
config: const DramaHomeConfig(
freeEpisodesCount: 3, // 提供基础配置
),
);
// 3. 监听错误事件
DramaHomeListener(
onHomeError: (error) {
debugPrint('❌ 聚合页错误: $error');
// 根据错误类型进行处理
if (error.contains('SDK_NOT_READY')) {
// 提示用户 SDK 未初始化
} else if (error.contains('INSTANCE_EXISTS')) {
// 提示用户已存在聚合页实例
}
},
)
问题2:单实例冲突
原因:同一时刻只能存在一个聚合页实例,尝试创建新实例时旧实例未销毁
解决方法:
// 方式1: 使用 Navigator 管理页面栈,确保页面退出时自动销毁
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DramaHomePage(),
),
);
// 方式2: 在 TabBar 中使用时,确保只有一个 Tab 包含聚合页
TabBarView(
children: [
const Center(child: Text('其他页面')),
DramaHomeNativeView( // 只在一个 Tab 中使用
config: const DramaHomeConfig(freeEpisodesCount: 3),
),
const Center(child: Text('其他页面')),
],
)
// 方式3: API 方式需要手动销毁
final launcher = DramaHomeLauncher();
await launcher.openDramaHome();
// ... 使用完毕后
await launcher.dispose(); // 必须手动销毁
问题3:聚合页内存泄漏
原因:未正确销毁聚合页实例
解决方法:
@override
void dispose() {
// 方式1: NativeView 会自动销毁,无需手动处理
// (除非缓存了 viewId 并手动管理生命周期)
// 方式2: API 方式必须手动销毁
if (_widgetId != null) {
PangrowthContent.destroyDramaHome(_widgetId!);
}
super.dispose();
}
问题4:播放详情页UI显示异常
原因:配置参数设置不正确
解决方法:
// 检查各项配置参数是否符合预期
DramaHomeNativeView(
config: const DramaHomeConfig(
freeEpisodesCount: 3,
// 确认UI控制参数设置正确
hideTopInfo: false, // false=显示,true=隐藏
hideBottomInfo: false,
hideBack: false, // 根据需求设置
hideLikeIcon: false,
hideFavorIcon: false,
),
)
问题5:置顶短剧不生效
原因:置顶短剧ID格式错误或短剧不存在
解决方法:
// 方式1: 单个置顶短剧(使用 int 类型)
DramaHomeNativeView(
config: const DramaHomeConfig(
topDramaId: 1008, // 确保短剧ID存在且格式正确
),
)
// 方式2: 多个置顶短剧(使用 String 数组)
DramaHomeNativeView(
config: const DramaHomeConfig(
topDramaIds: ['1008', '1009', '1010'], // String 数组格式
),
)
// 注意: topDramaIds 优先级高于 topDramaId
调试建议
- 开启日志输出:在代码中使用
debugPrint
查看详细信息 - 确认SDK版本:确保SDK版本和文档版本匹配
- 检查网络连接:聚合页需要网络加载内容
- 验证配置参数:检查
PangrowthContent.initialize()
和start()
的配置 - 测试基础功能:先使用最简配置进行测试,再逐步添加自定义配置
🌍 平台差异说明
参数映射
以下通用参数在 Flutter 层已自动处理平台差异,可直接使用:
showBackBtn
(双端通用)- Android:直接控制返回按钮显示
- iOS:自动映射到
isShowNavigationItemBackButton
参数
enableInfiniteScroll
(双端通用)- Android:直接使用
- iOS:内部会取反处理(iOS SDK 语义相反)
iOS 导航栏
iOS 平台默认展示系统导航栏,如需使用 Flutter 自定义标题栏,可同时设置:
DramaHomeNativeView(
config: const DramaHomeConfig(
showPageTitle: false, // Android: 隐藏标题栏
isShowNavigationItemTitle: false, // iOS: 隐藏导航栏标题
isShowNavigationItemBackButton: false, // iOS: 隐藏导航栏返回按钮
),
)
Android 顶部偏移
topOffset
参数仅在 Android 平台有效,适合配合自定义 AppBar 使用:
DramaHomeNativeView(
config: const DramaHomeConfig(
showPageTitle: false, // Android: 隐藏SDK默认标题栏
topOffset: 56, // Android: 顶部偏移56dp(自定义标题栏高度)
),
)
单位为 dp,iOS 会忽略此参数。
平台支持总结
特性 | Android | iOS | 说明 |
---|---|---|---|
短剧聚合页 | ✅ 完整支持 | ✅ 完整支持 | 双端均支持 |
NativeView组件 | ✅ 可用 | ✅ 可用 | 双端均通过 PlatformView 实现 |
API方式 | ✅ 可用 | ✅ 可用 | 双端均支持 create/show/destroy API |
showChangeBtn | ✅ 支持 | - | 仅Android,iOS无此UI元素 |
showPageTitle | ✅ 支持 | - | 仅Android,iOS使用系统导航栏 |
topOffset | ✅ 支持 | - | 仅Android,iOS无此参数 |
iOS导航栏配置 | - | ✅ 支持 | 仅iOS,通过 isShowNavigationItem* 参数控制 |
📚 相关文档
- 短剧播放页 - 短剧播放器详细配置和使用
- 短剧滑滑流 - 短剧滑动播放体验
- 短剧卡片 - 短剧卡片组件
- Widget组件总览 - 所有组件导航
💡 提示: 短剧聚合页功能需要有效的内容源和网络连接。建议在正式使用前先进行测试,确保内容加载正常。