pangle_flutter 1.9.1 icon indicating copy to clipboard operation
pangle_flutter: ^1.9.1 copied to clipboard

A Flutter plugin that supports ByteDance Pangle SDK on Android and iOS. Such as Splash Ads, Rewarded Video Ads, etc.

Thanks for non-commercial open source development authorization by JetBrains.

穿山甲 Flutter SDK
#

`pangle_flutter`是一款集成了字节跳动穿山甲 Android 和 iOS SDK的 Flutter 插件。


目录 #

原生平台相关范例:

版本迁移 #

  1. 不再需要传入isExpress参数
  2. BannerView, FeedView, SplashView均需要包一层限制大小的Widget, 可选Container, SizeBox, AspectRatio, Expanded等
  3. BannerView, FeedView, SplashView的控制点击实现变动,可参考example进行更改。

SDK对应版本 #

  • 已经内部依赖相关sdk,无需额外导入。如需替换新的sdk,请自行fork本项目更改依赖。

[Android] 4.8+

[iOS] 4.8+

注:如果出现高版本不兼容问题,可联系我升级适配,或者使用上面指定版本。

官方文档(需要登陆) #

使用文档 #

范例截图 #

集成步骤 #

1. 添加yaml依赖 #

dependencies:
  # 添加依赖
  pangle_flutter: latest

2. Android和iOS额外配置 #

  • iOS版本依赖配置

    本项目默认集成Ads-CN, 如果你是国内APP,无需额外配置;如果你是海外APP,请参照如下配置:

    打开你flutter应用ios项目下的Podfile,在target 'Runner do上面添加如下代码即可(如果不熟悉Podfile,也可以参考本项目example/ios/Podfile里面的配置)。


# add code begin
  def flutter_install_plugin_pods(application_path = nil, relative_symlink_dir, platform)
    # defined_in_file is set by CocoaPods and is a Pathname to the Podfile.
    application_path ||= File.dirname(defined_in_file.realpath) if self.respond_to?(:defined_in_file)
    raise 'Could not find application path' unless application_path

    # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
    # referring to absolute paths on developers' machines.

    symlink_dir = File.expand_path(relative_symlink_dir, application_path)
    system('rm', '-rf', symlink_dir) # Avoid the complication of dependencies like FileUtils.

    symlink_plugins_dir = File.expand_path('plugins', symlink_dir)
    system('mkdir', '-p', symlink_plugins_dir)

    plugins_file = File.join(application_path, '..', '.flutter-plugins-dependencies')
    plugin_pods = flutter_parse_plugins_file(plugins_file, platform)
    plugin_pods.each do |plugin_hash|
      plugin_name = plugin_hash['name']
      plugin_path = plugin_hash['path']
      if (plugin_name && plugin_path)
        symlink = File.join(symlink_plugins_dir, plugin_name)
        File.symlink(plugin_path, symlink)

        pod plugin_name, :path => File.join('.symlinks', 'plugins', plugin_name, 'ios')
        if plugin_name == 'pangle_flutter'
          # cn表示国内,global表示海外
          pod 'pangle_flutter/global', :path => File.join('.symlinks', 'plugins', plugin_name, 'ios')
        end
      end
    end
  end
  # add code end
  • 使用说明

支持开屏广告、激励视频、全屏视频(新模板渲染插屏广告)、模板渲染信息流、模板渲染插屏、模板渲染Banner。(如有自渲染广告位请联系我,或提交Feature request)

1. 信息流广告 #

pangle_flutterpangle_flutter

2. iOS使用纯OC开发的项目导入该模块 #

  1. 创建一个Swift文件,名称随意
  2. 根据提示选择Create Bridging Header。如果没有提示,请自行搜索如何创建。
OC导入Swift模块

使用说明 #

1. 初始化 #

import 'package:pangle_flutter/pangle_flutter.dart';
/// 如果在runApp方法调用之前初始化,加入下面这句代码
WidgetsFlutterBinding.ensureInitialized();
/// 初始化,未列出所有参数
/// [kAppId] 申请穿山甲广告位后得到的appID
await pangle.init(
  iOS: IOSConfig(appId: kAppId),
  android: AndroidConfig(appId: kAppId),
);

2. 开屏广告 #

/// 全屏类型
/// [kSplashId] 开屏广告ID, 对应Android的CodeId,对应iOS的slotID
await pangle.loadSplashAd(
  iOS: IOSSplashConfig(slotId: kSplashId, isExpress: false),
  android: AndroidSplashConfig(slotId: kSplashId, isExpress: false),
);


/// 自定义类型
/// Hybrid Composition支持
@override
void initState() {
  super.initState();
  // android 10以下对hybrid支持不太好
  SplashView.platform = AndroidSplashView(useHybridComposition: isAndroidAbove10);
}

/// 同Widget类用法
SplashView(
  iOS: IOSSplashConfig(slotId: kSplashId, isExpress: false),
  android: AndroidSplashConfig(slotId: kSplashId, isExpress: false),
  backgroundColor: Colors.white,
  /// 广告展示
  onShow: (){},
  /// 广告获取失败
  onError: (int code, String message){},
  /// 广告被点击
  onClick: (){},
  /// 广告已结束
  onClose: (){},
);

3. 激励视频广告 #

/// [kRewardedVideoId] 激励视频广告ID, 对应Android的CodeId,对应iOS的slotID
pangle.loadRewardVideoAd(
   iOS: IOSRewardedVideoConfig(slotId: kRewardedVideoId),
   android: AndroidRewardedVideoConfig(slotId: kRewardedVideoId),
 );

4. Banner广告 #

基本覆盖了原生回调事件,现在点击右上角关闭[ x ]按钮,需要开发者手动移除,不再自动移除Item。

/// Hybrid Composition支持
@override
void initState() {
  super.initState();
  // android 10以下对hybrid支持不太好
  BannerView.platform = AndroidBannerView(useHybridComposition: isAndroidAbove10);
}

/// Banner通过PlatformView实现,使用方法同Widget
/// [kBannerId] Banner广告ID, 对应Android的CodeId,对应iOS的slotID
BannerView(
  iOS: IOSBannerAdConfig(slotId: kBannerId),
  android: AndroidBannerAdConfig(slotId: kBannerId),
  // 还有其他回调,具体可导入查看
),


// 必须限定范围大小,可用Expaned,Container,SizeBox,AspectRatio等
Container(
  height: 260,
  child: BannerView(
    iOS: IOSBannerConfig(
      slotId: kBannerExpressId600x260,
      expressSize: PangleExpressSize(width: 600, height: 260),
    ),
    android: AndroidBannerConfig(
      slotId: kBannerExpressId600x260,
      expressSize: PangleExpressSize(width: 600, height: 260),
    ),
    onBannerViewCreated: (BannerViewController controller){
      // 传入[Rect.zero]与[]均为无额外点击区域
      controller.addTouchableBounds([Rect.zero]);
      // 清空额外点击区域
      controller.clearTouchableBounds();
    },
    onClick: () {},
  ),
),

5. 信息流广告 #

基本覆盖了原生回调事件,现在点击右上角关闭[ x ]按钮,需要开发者手动移除,不再自动移除Item。

  • 获取信息流数据
/// 信息流实现逻辑
/// 首先进行网络请求,得到信息流数据
///
/// PangleFeedAd相应字段: 
/// [code] 响应码,0成功,-1失败
/// [message] 错误时,调试信息
/// [count] 获得信息流数量,一般同上面传入的count,最终结果以此count为主
/// [data] (string list) 用于展示信息流广告的键id
 PangleFeedAd feedAd = await pangle.loadFeedAd(
   iOS: IOSFeedAdConfig(slotId: kFeedId, count: 2),
   android: AndroidFeedAdConfig(slotId: kFeedId, count: 2),
 );

  • 加载数据
/// Hybrid Composition支持
@override
void initState() {
  super.initState();
  // android 10以下对hybrid支持不太好
  FeedView.platform = AndroidFeedView(useHybridComposition: isAndroidAbove10);
}

/// 使用方法
/// 你的数据模型
class Item {
  /// 添加字段
  final String feedId;
}
final items = <Item>[];
final feedAdDatas = feedAd.data;
final items = Item(feedId: feedAdDatas[0]);
items.insert(Random().nextInt(items.length), item);
/// Widget使用
FeedView(
  id: item.feedId,
  onRemove: () {
    setState(() {
      items.removeAt(index);
    });
  },
)
  • 清除缓存
 AspectRatio(
   aspectRatio: 375 / 284.0,
   child: FeedView(
     id: item.feedId,
     onDislike: (option) {
       // 1.移除FeedView两步
       
       // 可在dispose方法处移除所有(此处可选)
       pangle.removeFeedAd([item.feedId]);
       // 移除界面上的显示
       setState(() {
         items.removeAt(index);
       });
     },
   ),
 )

// 可选,点击不喜欢即右上角叉时清除
pangle.removeFeedAd([item.feedId]);

// 必须
@override
void dispose() {
  /// 不关心返回值
  pangle.removeFeedAd(feedIds);
  /// 关心返回值
  /// _removeFeedAd();
  super.dispose();
}

/// 移除广告
_removeFeedAd() async {
  /// 返回移除个数
  int count = await pangle.removeFeedAd(feedIds);
  print('Feed Ad Removed: $count');
}

6. 插屏广告 #

 final result = await pangle.loadInterstitialAd(
   iOS: IOSInterstitialAdConfig(
     slotId: kInterstitialId

     /// 该宽高为你申请的广告位宽高,请根据实际情况赋值
     expressSize: PangleExpressSize(width: width, height: height),
   ),
   android: AndroidInterstitialAdConfig(
     slotId: kInterstitialId,
   ),
 );
print(jsonEncode(result));

7. 点击穿透 #

本方案适用于SplashViewFeedViewBannerView

当我们点击覆盖在广告View上方的Widget时,最优先响应该事件的View是用来渲染被原生广告遮挡的Widget layer 的FlutterOverlayView,而FlutterOverlayView在初始化时被禁用了用户交互响应userInteractionEnabled=NO,所以点击事件就会在广告View上被响应。因采用方案Flutter原生广告优化处理了点击穿透问题,广告可点击区域存在屏蔽过度的情况,故增加方法添加额外点击区域。

  • 添加可点击区域(此处使用FeedView作为范例)
// 1.广告不可点击区域key
final _otherKey = GlobalKey();
// 2.可能覆盖在FeedView上的button
FloatingActionButton(
  key: _otherKey,
),
// 3. 获取FeedViewController并添加点击范围
 AspectRatio(
   aspectRatio: 375 / 284.0,
   child: FeedView(
     id: item.feedId,
     onFeedViewCreated: (controller) {
       // 限制FeedView点击范围
       _initConstraintBounds(controller);
     },
   ),
 )

_initConstraintBounds(FeedViewController controller) {
  if (!Platform.isIOS) {
    return;
  }

  RenderBox otherBox = _otherKey.currentContext.findRenderObject();
  final otherBound = PangleHelper.fromRenderBox(otherBox);
  final targetBound = Rect.fromLTWH(
    0,
    otherBound.top,
    kPangleScreenWidth - otherBound.width,
    otherBound.height,
  );
  controller.addTouchableBound(targetBound);
}

8. 其他广告 #

另外已实现全屏视频广告、新模板渲染插屏,使用方式大同小异。

贡献 #

  • 有任何更好的实现方式或增加额外的功能,提交PR
  • 有任何使用上的问题,提交 issue

交流 #

提交issue即可。

感谢赞助 #

BokAugust

26
likes
125
pub points
69%
popularity

Publisher

verified publisher iconcoool.dev

A Flutter plugin that supports ByteDance Pangle SDK on Android and iOS. Such as Splash Ads, Rewarded Video Ads, etc.

Homepage

Documentation

API reference

License

Icon for licenses.MIT (LICENSE)

Dependencies

flutter

More

Packages that depend on pangle_flutter