🧩 高级功能
版本 PanGrowth

💰 自定义广告完整指南

pangrowth_content插件支持在多个组件中接入自定义广告,让你可以灵活控制广告展示逻辑和样式,实现更高的广告变现收益。

✨ 功能概览

支持自定义广告的组件

组件名支持的广告类型说明
DramaPlayerNativeViewDraw广告、Banner广告短剧播放页自定义广告
DramaSwipeFlowNativeViewDraw广告、Banner广告短剧滑滑流自定义广告
StoryReaderNativeView章间广告、段间广告、Banner广告短故事阅读器自定义广告

自定义广告类型说明

1. Draw广告(竖版视频广告)

  • 位置: 插入在内容列表中
  • 形式: 全屏竖版视频广告
  • 适用场景: 短剧播放页、短剧滑滑流
  • 配置参数: drawAdPositions + customDrawAdViewId

2. Banner广告(横幅广告)

  • 位置: 底部横幅区域
  • 形式: 固定高度的横幅广告
  • 适用场景: 所有支持自定义广告的组件
  • 配置参数: customBannerAdViewId

3. 章间广告(页间广告)

  • 位置: 章节切换时显示
  • 形式: 全屏广告
  • 适用场景: 短故事阅读器
  • 配置参数: customMiddlePageAdViewId + middlePageInterval

4. 段间广告(行间广告)

  • 位置: 段落间插入
  • 形式: 行内广告
  • 适用场景: 短故事阅读器
  • 配置参数: customMiddleLineAdViewId + middleLineStartLine + middleLineInterval

🚀 使用示例

示例1: 短剧播放页自定义广告

import 'package:flutter/material.dart';
import 'package:pangrowth_content/pangrowth_content.dart';

class CustomAdDramaPlayerPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: DramaPlayerNativeView(
        config: DramaPlayerConfig(
          dramaId: 12345,
          episode: 1,
          // 配置Draw广告位置
          drawAdPositions: [3, 6, 9], // 在第3、6、9集插入Draw广告
          customDrawAdViewId: 'my_draw_ad', // 自定义Draw广告视图ID
          customBannerAdViewId: 'my_banner_ad', // 自定义Banner广告视图ID
        ),
        listener: DramaPlayerListener(
          onPlayerReady: (playerId) {
            print('播放器就绪: $playerId');
          },
        ),
      ),
    );
  }
}

说明:

  • drawAdPositions: 指定在哪些集数插入Draw广告
  • customDrawAdViewId: 自定义Draw广告视图的唯一标识
  • customBannerAdViewId: 自定义Banner广告视图的唯一标识
  • 原生层会根据viewId创建对应的广告视图并显示

示例2: 短剧滑滑流自定义广告

import 'package:flutter/material.dart';
import 'package:pangrowth_content/pangrowth_content.dart';

class CustomAdTheaterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: DramaSwipeFlowNativeView(
        config: DramaSwipeFlowConfig(
          channelType: 1,
          detailFree: 5,
          unlockCount: 1,
          // 配置自定义广告
          drawAdPositions: [5, 10, 15], // 每5个短剧插入一次Draw广告
          customDrawAdViewId: 'theater_draw_ad',
          customBannerAdViewId: 'theater_banner_ad',
        ),
        listener: DramaSwipeFlowListener(
          onSwipeFlowReady: (swipeFlowId) {
            print('滑滑流就绪: $swipeFlowId');
          },
        ),
      ),
    );
  }
}

示例3: 短故事阅读器自定义广告

import 'package:flutter/material.dart';
import 'package:pangrowth_content/pangrowth_content.dart';

class CustomAdStoryReaderPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StoryReaderNativeView(
        config: StoryReaderConfig(
          storyId: 67890,
          startChapter: 0,
          // 配置章间广告
          customMiddlePageAdViewId: 'story_page_ad',
          middlePageInterval: 5, // 每5章插入一次章间广告
          // 配置段间广告
          customMiddleLineAdViewId: 'story_line_ad',
          middleLineStartLine: 10, // 从第10行开始插入段间广告
          middleLineInterval: 20, // 每20行插入一次段间广告
          // 配置Banner广告
          customBannerAdViewId: 'story_banner_ad',
        ),
        listener: StoryReaderListener(
          onReaderReady: (readerId) {
            print('阅读器就绪: $readerId');
          },
          onMiddlePageAdShow: () {
            print('章间广告显示');
          },
          onMiddleLineAdShow: (lineNumber) {
            print('段间广告显示在第$lineNumber行');
          },
        ),
      ),
    );
  }
}

🎨 自定义广告Widget示例

原生层需要根据提供的viewId创建对应的广告视图。以下是几种常见广告Widget的示例:

Banner广告Widget

class MyBannerAdWidget extends StatelessWidget {
  const MyBannerAdWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 50,
      color: Colors.blue,
      child: Center(
        child: Text(
          '自定义Banner广告',
          style: TextStyle(color: Colors.white),
        ),
      ),
    );
  }
}

Draw广告Widget

class MyDrawAdWidget extends StatelessWidget {
  const MyDrawAdWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.black,
      child: Stack(
        children: [
          // 广告视频播放器
          Center(
            child: AspectRatio(
              aspectRatio: 9 / 16,
              child: Container(
                color: Colors.grey[800],
                child: Icon(
                  Icons.play_circle_outline,
                  size: 64,
                  color: Colors.white,
                ),
              ),
            ),
          ),
          // 跳过按钮
          Positioned(
            top: 40,
            right: 20,
            child: TextButton(
              onPressed: () {
                // 跳过广告逻辑
              },
              style: TextButton.styleFrom(
                backgroundColor: Colors.black54,
              ),
              child: Text(
                '跳过 5s',
                style: TextStyle(color: Colors.white),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

章间广告Widget

class MyMiddlePageAdWidget extends StatelessWidget {
  final VoidCallback? onClose;

  const MyMiddlePageAdWidget({Key? key, this.onClose}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: Stack(
        children: [
          // 广告内容
          Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Icon(Icons.ad_units, size: 100, color: Colors.blue),
                SizedBox(height: 20),
                Text(
                  '章间广告',
                  style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
                ),
                SizedBox(height: 10),
                Text('查看广告可解锁更多内容'),
              ],
            ),
          ),
          // 关闭按钮
          Positioned(
            top: 40,
            right: 20,
            child: IconButton(
              icon: Icon(Icons.close, color: Colors.black),
              onPressed: onClose,
            ),
          ),
        ],
      ),
    );
  }
}

💡 最佳实践

1. 广告位置优化

Draw广告插入位置:

// ✅ 推荐:合理间隔,避免影响用户体验
drawAdPositions: [5, 10, 15, 20]

// ❌ 不推荐:过于频繁
drawAdPositions: [1, 2, 3, 4, 5]

章间广告间隔:

// ✅ 推荐:每3-5章插入一次
middlePageInterval: 5

// ❌ 不推荐:每章都插入
middlePageInterval: 1

2. 广告加载优化

  • 预加载广告数据,减少等待时间
  • 使用占位符避免布局闪烁
  • 失败时优雅降级,不影响内容浏览

3. 用户体验优化

  • 提供"跳过广告"按钮
  • 明确显示广告剩余时间
  • 避免强制观看过长的广告
  • 提供广告反馈入口

4. 性能优化

// 使用Controller管理广告生命周期
class MyAdPage extends StatefulWidget {
  @override
  _MyAdPageState createState() => _MyAdPageState();
}

class _MyAdPageState extends State<MyAdPage> {
  final _controller = DramaPlayerController();

  @override
  void dispose() {
    // ✅ 重要:销毁时释放资源
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return DramaPlayerNativeView(
      controller: _controller,
      config: DramaPlayerConfig(
        dramaId: 12345,
        episode: 1,
        customBannerAdViewId: 'my_ad',
      ),
    );
  }
}

⚠️ 注意事项

1. ViewID唯一性

  • 每个自定义广告视图必须使用唯一的viewId
  • 不同组件的广告可以使用不同的viewId
  • 建议使用描述性命名,如 'drama_player_banner''story_reader_page_ad'

2. 原生层实现

  • 自定义广告需要在原生层(Android/iOS)实现对应的广告Provider
  • 原生层会根据viewId查找并创建对应的广告视图
  • 具体实现请参考原生层文档

3. 广告视图生命周期

  • 广告视图随NativeView一起创建和销毁
  • 确保广告资源在dispose时正确释放
  • 避免内存泄漏

4. 平台差异

  • 某些配置参数可能仅在特定平台生效
  • Android和iOS的广告Provider接口可能略有差异
  • 测试时需要覆盖两个平台

❓ 常见问题

Q: 自定义广告不显示怎么办?

A: 检查以下几点:

  1. 确认viewId已正确配置
  2. 检查原生层是否实现了对应的AdProvider
  3. 查看日志是否有错误信息
  4. 确认SDK已正确初始化

Q: 可以同时使用SDK广告和自定义广告吗?

A: 可以。如果不配置自定义广告参数,组件会使用SDK默认广告。你可以只自定义部分广告类型,其他使用SDK默认。

Q: 如何统计自定义广告的曝光和点击?

A: 使用Listener监听广告事件:

StoryReaderListener(
  onMiddlePageAdShow: () {
    // 统计章间广告曝光
    Analytics.logEvent('ad_show', {'type': 'middle_page'});
  },
  onMiddlePageAdClick: () {
    // 统计章间广告点击
    Analytics.logEvent('ad_click', {'type': 'middle_page'});
  },
)

Q: 原生层如何获取自定义广告视图?

A: 原生层通过实现对应的AdProvider接口,根据Flutter传递的viewId创建广告视图:

  • Android: 实现 IDJXDramaAdCustomProviderINovMiddlePageAdProvider 等接口
  • iOS: 实现相应的Delegate协议

详细的原生层实现请参考Flutter插件开发文档。


🔗 相关文档


需要进一步协助?

与 LightCore 技术顾问沟通,获取商业化策略与集成支持。