diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 7f68b6e..2a5bca8 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -7,21 +7,21 @@ - - - - - - - - - - - - - - - - + + + + + + + diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/PluginDelegate.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/PluginDelegate.kt index 82aaaa3..119bb24 100644 --- a/android/src/main/kotlin/com/example/union_ad_ssgf/PluginDelegate.kt +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/PluginDelegate.kt @@ -2,8 +2,10 @@ package com.example.union_ad_ssgf import android.annotation.SuppressLint import android.app.Activity +import android.content.Intent import android.util.Log import com.example.union_ad_ssgf.config.UnionADConfig +import com.example.union_ad_ssgf.page.AdSplashActivity import com.qq.e.comm.managers.GDTAdSdk import com.qq.e.comm.managers.setting.GlobalSetting.setPersonalizedState import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding @@ -135,14 +137,13 @@ class PluginDelegate(var activity: Activity, pluginBinding: FlutterPluginBinding private fun showSplashAd(call: MethodCall, result: MethodChannel.Result) { val posId: String? = call.argument(UnionADConfig.KEY_POSID) val logo: String? = call.argument(UnionADConfig.KEY_LOGO) - val fetchDelay: Double = call.argument(UnionADConfig.KEY_FETCH_DELAY)!! -// val intent = Intent(activity, AdSplashActivity::class.java) -// intent.putExtra(UnionADConfig.KEY_POSID, posId) -// intent.putExtra(UnionADConfig.KEY_LOGO, logo) -// intent.putExtra(UnionADConfig.KEY_FETCH_DELAY, fetchDelay) -// activity.startActivity(intent) -// result.success(true) + val intent = Intent(activity, AdSplashActivity::class.java) + intent.putExtra(UnionADConfig.KEY_POSID, posId) + intent.putExtra(UnionADConfig.KEY_LOGO, logo) + intent.putExtra(UnionADConfig.KEY_FETCH_DELAY, fetchDelay) + activity.startActivity(intent) + result.success(true) } } diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfPlugin.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfPlugin.kt index 8523fa9..a40bd9a 100644 --- a/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfPlugin.kt +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/UnionAdSsgfPlugin.kt @@ -31,7 +31,7 @@ class UnionAdSsgfPlugin : FlutterPlugin, ActivityAware { /** * 插件代理 */ - var delegate: PluginDelegate? = null + var delegate: PluginDelegate? = null /** @@ -67,7 +67,7 @@ class UnionAdSsgfPlugin : FlutterPlugin, ActivityAware { * 绑定activity */ override fun onAttachedToActivity(binding: ActivityPluginBinding) { - delegate = PluginDelegate(binding.getActivity(), bind) + delegate = PluginDelegate(binding.activity, bind) methodChannel.setMethodCallHandler(delegate) eventChannel.setStreamHandler(delegate) } diff --git a/example/lib/ads_config.dart b/example/lib/ads_config.dart new file mode 100644 index 0000000..d237b08 --- /dev/null +++ b/example/lib/ads_config.dart @@ -0,0 +1,82 @@ +import 'dart:io'; + +/// 广告配置信息 +class AdsConfig { + /// 获取 Logo 资源名称 + static String get logo { + if (Platform.isAndroid) { + return 'flutterads_logo'; + } else { + return 'LaunchImage'; + } + } + + /// 获取 Logo 资源名称 2 + static String get logo2 { + if (Platform.isAndroid) { + return 'flutterads_logo2'; + } else { + return 'LaunchImage2'; + } + } + + /// 获取 App id + static String get appId { + return Platform.isAndroid ? '1204814627' : '1204814641'; + } + + /// 获取开屏广告位id + static String get splashId { + return Platform.isAndroid ? '4046660274345204' : '1046662224832381'; + } + + /// 获取插屏广告位id + static String get interstitialId { + return Platform.isAndroid ? '1066865274941328' : '7046066294830767'; + } + + /// 获取插屏全屏视频广告位id + static String get interstitialFullScreenVideoId { + if (Platform.isAndroid) { + return '3012521499614895'; + } else { + return '3092322459911886'; + } + } + + /// 获取插屏激励视频广告位id + static String get interstitialRewardVideoId { + if (Platform.isAndroid) { + return '2052820580637311'; + } else { + return '9022927550132316'; + } + } + + /// 获取激励视频广告位id + static String get rewardVideoId { + if (Platform.isAndroid) { + return '6086667264144219'; + } else { + return '3066367234238599'; + } + } + + /// 获取 Banner 广告位id + static String get bannerId { + if (Platform.isAndroid) { + return '5086068204047616'; + } else { + return '7026465284342149'; + } + } + + /// 获取信息流广告位id + static String get feedId { + if (Platform.isAndroid) { + return '7036167274246466'; + } else { + return '8076264204347078'; + } + } +} diff --git a/example/lib/home_page.dart b/example/lib/home_page.dart new file mode 100644 index 0000000..d3710e8 --- /dev/null +++ b/example/lib/home_page.dart @@ -0,0 +1,245 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:union_ad_ssgf/event/ad_event_handler.dart'; +import 'package:union_ad_ssgf_example/ads_config.dart'; +import 'package:union_ad_ssgf/union_ad_ssgf.dart'; + +// 结果信息 +String _result = ''; + +class HomePage extends StatefulWidget { + @override + _HomePageState createState() => _HomePageState(); +} + +class _HomePageState extends State { + String _adEvent = ''; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Union AD plugin'), + ), + body: Center( + child: SingleChildScrollView( + padding: const EdgeInsets.all(10), + child: Column( + children: [ + SizedBox(height: 10), + Text('Result: $_result'), + SizedBox(height: 10), + Text('onAdEvent: $_adEvent'), + SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ElevatedButton( + child: Text('初始化'), + onPressed: () {}, + ), + SizedBox(height: 20), + ElevatedButton( + child: Text('请求跟踪授权'), + onPressed: () { + requestIDFA(); + }, + ), + SizedBox(height: 20), + ElevatedButton( + child: Text('个性化广告'), + onPressed: () { + setPersonalizedAd(1); + }, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ElevatedButton( + child: Text('开屏(Logo2)'), + onPressed: () { + showSplashAd(AdsConfig.logo2); + }, + ), + SizedBox(height: 20), + ElevatedButton( + child: Text('开屏(全屏)'), + onPressed: () { + showSplashAd(); + setState(() {}); + }, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ElevatedButton( + child: Text('插屏广告'), + onPressed: () { + showInterstitialAd(AdsConfig.interstitialId); + }, + ), + SizedBox(height: 20), + ElevatedButton( + child: Text('插全屏广告'), + onPressed: () { + showInterstitialAd( + AdsConfig.interstitialFullScreenVideoId, + showFullScreenVideo: true, + ); + }, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ElevatedButton( + child: Text('插屏激励'), + onPressed: () { + showInterstitialAd( + AdsConfig.interstitialRewardVideoId, + showFullScreenVideo: true, + showRewardVideo: true, + ); + }, + ), + SizedBox(height: 20), + ElevatedButton( + child: Text('激励视频'), + onPressed: () { + showRewardVideoAd(); + }, + ), + ], + ), + SizedBox(height: 20), + ElevatedButton( + child: Text('信息流'), + onPressed: () { + // Navigator.push( + // context, + // MaterialPageRoute( + // builder: (context) => FeedPage(), + // )); + }, + ), + SizedBox(height: 20), + const Center(child: Text('👇🏻 Banner 广告 👇🏻')), + const SizedBox(height: 10), + // AdBannerWidget( + // posId: AdsConfig.bannerId, + // width: 300, + // height: 80, + // interval: 0, + // show: true, + // ), + SizedBox(height: 10), + ], + ), + ), + ), + ); + } + + /// 设置广告监听 + Future setAdEvent() async { + setState(() { + _adEvent = '设置成功'; + }); + UnionAdSsgf.onEventListener((event) { + _adEvent = 'adId:${event.adId} action:${event.action}'; + if (event is AdErrorEvent) { + // 错误事件 + _adEvent += ' errCode:${event.errCode} errMsg:${event.errMsg}'; + } else if (event is AdRewardEvent) { + // 激励事件 + _adEvent += + ' transId:${event.transId} customData:${event.customData} userId:${event.userId}'; + } + print('onEventListener:$_adEvent'); + setState(() {}); + }); + } + + /// 请求应用跟踪透明度授权 + Future requestIDFA() async { + bool result = await UnionAdSsgf.requestIDFA; + _adEvent = '请求广告标识符:$result'; + setState(() {}); + } + + /// 设置个性化广告 + /// [state] 0:不限制 1:限制 + Future setPersonalizedAd(int state) async { + bool result = await UnionAdSsgf.setPersonalizedState(state); + _adEvent = '设置个性化广告:$result'; + setState(() {}); + } + + /// 展示插屏广告 + Future showInterstitialAd( + String posId, { + bool showFullScreenVideo = false, + bool showRewardVideo = false, + }) async { + // try { + // bool result = await UnionAdSsgf.showInterstitialAd( + // posId, + // showPopup: false, + // showFullScreenVideo: showFullScreenVideo, + // showRewardVideo: showRewardVideo, + // autoPlayMuted: false, + // autoPlayOnWifi: false, + // userId: 'userId', + // customData: 'showInterstitialAd customData', + // ); + // _result = "展示插屏广告${result ? '成功' : '失败'}"; + // } on PlatformException catch (e) { + // _result = "展示插屏广告失败 code:${e.code} msg:${e.message} details:${e.details}"; + // } + setState(() {}); + } + + /// 展示激励视频广告 + Future showRewardVideoAd() async { + // try { + // bool result = await UnionAdSsgf.showRewardVideoAd( + // AdsConfig.rewardVideoId, + // playMuted: false, + // customData: 'showRewardVideoAd customData', + // userId: 'userId', + // ); + // _result = "展示激励视频广告${result ? '成功' : '失败'}"; + // } on PlatformException catch (e) { + // _result = + // "展示激励视频广告失败 code:${e.code} msg:${e.message} details:${e.details}"; + // } + setState(() {}); + } +} + +/// 展示开屏广告 +/// [logo] 展示如果传递则展示logo,不传递不展示 +Future showSplashAd([String? logo]) async { + try { + bool result = await UnionAdSsgf.showSplashAd( + AdsConfig.splashId, + logo: logo, + fetchDelay: 3, + ); + _result = "展示开屏广告${result ? '成功' : '失败'}"; + } on PlatformException catch (e) { + _result = "展示开屏广告失败 code:${e.code} msg:${e.message} details:${e.details}"; + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 4b96e5b..16a4c45 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,10 +1,14 @@ import 'package:flutter/material.dart'; import 'dart:async'; -import 'package:flutter/services.dart'; import 'package:union_ad_ssgf/union_ad_ssgf.dart'; +import 'package:union_ad_ssgf/event/ad_error_event.dart'; +import 'package:union_ad_ssgf/event/ad_reward_event.dart'; +import 'package:union_ad_ssgf_example/ads_config.dart'; +import 'package:union_ad_ssgf_example/home_page.dart'; void main() { + WidgetsFlutterBinding.ensureInitialized(); runApp(const MyApp()); } @@ -16,48 +20,44 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - String _platformVersion = 'Unknown'; - final _unionAdSsgfPlugin = UnionAdSsgf(); - @override void initState() { super.initState(); - initPlatformState(); - } - - // Platform messages are asynchronous, so we initialize in an async method. - Future initPlatformState() async { - String platformVersion; - // Platform messages may fail, so we use a try/catch PlatformException. - // We also handle the message potentially returning null. - try { - platformVersion = - await _unionAdSsgfPlugin.getPlatformVersion() ?? 'Unknown platform version'; - } on PlatformException { - platformVersion = 'Failed to get platform version.'; - } - - // If the widget was removed from the tree while the asynchronous platform - // message was in flight, we want to discard the reply rather than calling - // setState to update our non-existent appearance. - if (!mounted) return; - - setState(() { - _platformVersion = platformVersion; + setAdEvent(); + init().then((value) { + if (value) { + + } }); } @override Widget build(BuildContext context) { return MaterialApp( - home: Scaffold( - appBar: AppBar( - title: const Text('Plugin example app'), - ), - body: Center( - child: Text('Running on: $_platformVersion\n'), - ), - ), + home: HomePage(), ); } + + /// 初始化广告 SDK + Future init() async { + bool result = await UnionAdSsgf.initAd(AdsConfig.appId); + print("----->> result: $result"); + debugPrint("广告SDK 初始化${result ? '成功' : '失败'}"); + return result; + } + + /// 设置广告监听 + Future setAdEvent() async { + UnionAdSsgf.onEventListener((event) { + debugPrint('adId:${event.adId} action:${event.action}'); + if (event is AdErrorEvent) { + // 错误事件 + debugPrint(' errCode:${event.errCode} errMsg:${event.errMsg}'); + } else if (event is AdRewardEvent) { + // 激励事件 + debugPrint( + ' transId:${event.transId} userId:${event.userId} customData:${event.customData}'); + } + }); + } } diff --git a/lib/event/ad_error_event.dart b/lib/event/ad_error_event.dart new file mode 100644 index 0000000..9580b3b --- /dev/null +++ b/lib/event/ad_error_event.dart @@ -0,0 +1,24 @@ +import 'ad_event.dart'; + +/// 广告错误事件 +class AdErrorEvent extends AdEvent { + AdErrorEvent( + {required this.errCode, + required this.errMsg, + required String adId, + required String action}) + : super(adId: adId, action: action); + // 错误码 + final int errCode; + // 错误信息 + final String errMsg; + // 解析 json 为错误事件对象 + factory AdErrorEvent.fromJson(Map json) { + return AdErrorEvent( + errCode: json['errCode'], + errMsg: json['errMsg'], + adId: json['adId'], + action: json['action'], + ); + } +} diff --git a/lib/event/ad_event.dart b/lib/event/ad_event.dart new file mode 100644 index 0000000..9927678 --- /dev/null +++ b/lib/event/ad_event.dart @@ -0,0 +1,30 @@ +import 'ad_error_event.dart'; +import 'ad_event_action.dart'; +import 'ad_reward_event.dart'; +export 'ad_error_event.dart'; +export 'ad_event_action.dart'; +export 'ad_reward_event.dart'; + +/// 广告事件 +class AdEvent { + AdEvent({required this.adId, required this.action}); + // 广告 id + final String adId; + // 操作 + final String action; + + /// 解析 AdEvent + factory AdEvent.fromJson(Map json) { + String action = json['action']; + if (action == AdEventAction.onAdError) { + return AdErrorEvent.fromJson(json); + } else if (action == AdEventAction.onAdReward) { + return AdRewardEvent.fromJson(json); + } else { + return AdEvent( + adId: json['adId'], + action: action, + ); + } + } +} diff --git a/lib/event/ad_event_action.dart b/lib/event/ad_event_action.dart new file mode 100644 index 0000000..3723d5d --- /dev/null +++ b/lib/event/ad_event_action.dart @@ -0,0 +1,21 @@ +/// 广告事件操作 +class AdEventAction { + // 广告错误 + static final String onAdError = "onAdError"; + // 广告加载成功 + static final String onAdLoaded = "onAdLoaded"; + // 广告填充 + static final String onAdPresent = "onAdPresent"; + // 广告曝光 + static final String onAdExposure = "onAdExposure"; + // 广告关闭(开屏计时结束或者用户点击关闭) + static final String onAdClosed = "onAdClosed"; + // 广告点击 + static final String onAdClicked = "onAdClicked"; + // 广告跳过 + static final String onAdSkip = "onAdSkip"; + // 广告播放或计时完毕 + static final String onAdComplete = "onAdComplete"; + // 获得广告激励 + static final String onAdReward = "onAdReward"; +} diff --git a/lib/event/ad_event_handler.dart b/lib/event/ad_event_handler.dart new file mode 100644 index 0000000..a7f7921 --- /dev/null +++ b/lib/event/ad_event_handler.dart @@ -0,0 +1,13 @@ +import 'ad_event.dart'; +export 'ad_event.dart'; + +/// 广告事件回调监听 +typedef OnAdEventListener = void Function(AdEvent event); + +/// 处理广告事件 +void hanleAdEvent(dynamic data, OnAdEventListener listener) { + if (data != null) { + AdEvent adEvent = AdEvent.fromJson(data); + listener.call(adEvent); + } +} diff --git a/lib/event/ad_reward_event.dart b/lib/event/ad_reward_event.dart new file mode 100644 index 0000000..27bc846 --- /dev/null +++ b/lib/event/ad_reward_event.dart @@ -0,0 +1,28 @@ +import 'ad_event.dart'; + +/// 广告激励事件 +class AdRewardEvent extends AdEvent { + AdRewardEvent( + {required this.transId, + this.customData, + this.userId, + required String adId, + required String action}) + : super(adId: adId, action: action); + // 激励服务端验证的唯一 ID + final String transId; + // 服务端验证的自定义信息 + final String? customData; + // 服务端验证的用户信息 + final String? userId; + // 解析 json 为激励事件对象 + factory AdRewardEvent.fromJson(Map json) { + return AdRewardEvent( + adId: json['adId'], + action: json['action'], + transId: json['transId'], + customData: json['customData'], + userId: json['userId'], + ); + } +} diff --git a/lib/union_ad_ssgf.dart b/lib/union_ad_ssgf.dart index 050d449..894186f 100644 --- a/lib/union_ad_ssgf.dart +++ b/lib/union_ad_ssgf.dart @@ -1,7 +1,74 @@ +import 'dart:io'; + +import 'package:flutter/services.dart'; +import 'package:union_ad_ssgf/event/ad_event_handler.dart'; import 'union_ad_ssgf_platform_interface.dart'; +/// 三商共富 Flutter 广告插件 class UnionAdSsgf { + /// 方法通道 + static const MethodChannel _methodChannel = + MethodChannel('union_ad_ssgf_method'); + + /// 事件通道 + static const EventChannel _eventChannel = EventChannel('union_ad_ssgf_event'); + + /// 请求应用跟踪透明度授权 + static Future get requestIDFA async { + if (Platform.isIOS) { + final bool result = await _methodChannel.invokeMethod('requestIDFA'); + return result; + } + return true; + } + + /// 初始化广告 + /// [appId] 应用媒体ID + static Future initAd(String appId) async { + final bool result = await _methodChannel.invokeMethod( + 'initAd', + {'appId': appId}, + ); + print("🎉🎉🎉 UnionAd ==> 初始化完成"); + return result; + } + + /// 设置个性化广告 + /// 0:代表开启个性化广告推荐,1:代表关闭个性化广告推荐 + static Future setPersonalizedState(int state) async { + final bool result = await _methodChannel.invokeMethod( + 'setPersonalizedState', + {'state': state}, + ); + return result; + } + + /// 展示开屏广告 + /// [posId] 广告位 id + /// [logo] 如果传值则展示底部logo,不传不展示,则全屏展示 + /// [fetchDelay] 拉取广告的超时时间,默认值 3 秒,取值范围[1.5~5]秒 + static Future showSplashAd(String posId, + {String? logo, double fetchDelay = 3}) async { + final bool result = await _methodChannel.invokeMethod( + 'showSplashAd', + { + 'posId': posId, + 'logo': logo, + 'fetchDelay': fetchDelay, + }, + ); + return result; + } + + ///事件回调 + ///@params onData 事件回调 + static Future onEventListener(OnAdEventListener onAdEventListener) async { + _eventChannel.receiveBroadcastStream().listen((data) { + hanleAdEvent(data, onAdEventListener); + }); + } + Future getPlatformVersion() { return UnionAdSsgfPlatform.instance.getPlatformVersion(); }