From 578c1974c5da368c1e529c688a499d7124909936 Mon Sep 17 00:00:00 2001 From: Jin857 Date: Wed, 16 Oct 2024 17:35:13 +0800 Subject: [PATCH] =?UTF-8?q?=20=E6=B7=BB=E5=8A=A0=20=E6=BF=80=E5=8A=B1?= =?UTF-8?q?=E8=A7=86=E9=A2=91=20-=20=E5=88=9D=E6=AD=A5=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 3 + .../example/union_ad_ssgf/PluginDelegate.kt | 99 ++++++++----- .../union_ad_ssgf/event/AdRewardEvent.kt | 25 ++++ .../union_ad_ssgf/page/NativeViewFactory.kt | 7 +- .../union_ad_ssgf/page/RewardVideoPage.kt | 135 ++++++++++++++++++ example/lib/home_page.dart | 24 ++-- lib/union_ad_ssgf.dart | 26 +++- 7 files changed, 272 insertions(+), 47 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 android/src/main/kotlin/com/example/union_ad_ssgf/event/AdRewardEvent.kt create mode 100644 android/src/main/kotlin/com/example/union_ad_ssgf/page/RewardVideoPage.kt diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f854a54 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cmake.sourceDirectory": "/Users/jin/dev/ssgf/union_ad_ssgf/linux" +} \ No newline at end of file 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 119bb24..0c8aa45 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 @@ -6,6 +6,7 @@ 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.example.union_ad_ssgf.page.RewardVideoPage import com.qq.e.comm.managers.GDTAdSdk import com.qq.e.comm.managers.setting.GlobalSetting.setPersonalizedState import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding @@ -15,24 +16,30 @@ import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel -class PluginDelegate(var activity: Activity, pluginBinding: FlutterPluginBinding) : +/** + * 插件代理中心 + * + * @param activity 当前 Activity + * @param bind Flutter 插件绑定对象 + */ +class PluginDelegate(var activity: Activity, bind: FlutterPluginBinding) : MethodChannel.MethodCallHandler, EventChannel.StreamHandler { - - private val TAG = PluginDelegate::class.java.getSimpleName() - - // Flutter 插件绑定对象 - private var bind = pluginBinding + private val s = PluginDelegate::class.java.getSimpleName(); // 事件通道 private var eventSink: EventSink? = null - /*初始化代码块*/ + /** + * 初始化代码块 + */ init { _instance = this } companion object { - // 插件代理对象 + /** + * 插件代理对象 + */ @SuppressLint("StaticFieldLeak") private lateinit var _instance: PluginDelegate fun getInstance(): PluginDelegate { @@ -42,37 +49,49 @@ class PluginDelegate(var activity: Activity, pluginBinding: FlutterPluginBinding override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { val method = call.method - Log.d(TAG, "MethodChannel onMethodCall method:" + method + " arguments:" + call.arguments) + Log.d(s, "MethodChannel onMethodCall method:" + method + " arguments:" + call.arguments) when (method) { - // 获取当前版本 + /** + * 获取当前版本 + */ "getPlatformVersion" -> { getPlatformVersion(call, result) } - // 初始化 + /** + * 初始化 + */ "initAd" -> { initAd(call, result) } - // 设置广告个性化 + /** + * 设置广告个性化 + */ "setPersonalizedState" -> { setPersonalizedState(call, result) } - // 开屏广告 + /** + * 开屏广告 + */ "showSplashAd" -> { showSplashAd(call, result) } - // 激励广告 + /** + * 激励广告 + */ "showRewardVideoAd" -> { - + showRewardVideoAd(call, result); } - // 错误桥接 + /** + * 错误桥接 + */ else -> { result.notImplemented() } } } - override fun onListen(arguments: Any?, events: EventChannel.EventSink?) { - Log.d(TAG, "EventChannel onListen arguments:" + arguments) + override fun onListen(arguments: Any, events: EventChannel.EventSink) { + Log.d(s, "EventChannel onListen arguments:$arguments") eventSink = events } @@ -81,7 +100,7 @@ class PluginDelegate(var activity: Activity, pluginBinding: FlutterPluginBinding * @param arguments 参数 */ override fun onCancel(arguments: Any?) { - Log.d(TAG, "EventChannel onCancel") + Log.d(s, "EventChannel onCancel") eventSink = null } @@ -101,20 +120,25 @@ class PluginDelegate(var activity: Activity, pluginBinding: FlutterPluginBinding */ private fun initAd(call: MethodCall, result: MethodChannel.Result) { val appId = call.argument("appId") - GDTAdSdk.initWithoutStart(activity.applicationContext, appId) // 该接口不会采集用户信息 - // 调用initWithoutStart后请尽快调用start,否则可能影响广告填充,造成收入下降 - GDTAdSdk.start( - object : GDTAdSdk.OnStartListener { - override fun onStartSuccess() { - // 推荐开发者在 onStartSuccess 回调后开始拉广告 - Log.e("gdt onStartSuccess", "加载成功") - } - - override fun onStartFailed(e: Exception) { - Log.e("gdt onStartFailed:", e.toString()) - } + /** + * 该接口不会采集用户信息 + */ + GDTAdSdk.initWithoutStart(activity.applicationContext, appId) + /** + * 调用initWithoutStart后请尽快调用start,否则可能影响广告填充,造成收入下降 + */ + GDTAdSdk.start(object : GDTAdSdk.OnStartListener { + /** + * 推荐开发者在 onStartSuccess 回调后开始拉广告 + */ + override fun onStartSuccess() { + Log.e("gdt onStartSuccess", "加载成功") } - ) + + override fun onStartFailed(e: Exception) { + Log.e("gdt onStartFailed:", e.toString()) + } + }) result.success(true) } @@ -146,4 +170,15 @@ class PluginDelegate(var activity: Activity, pluginBinding: FlutterPluginBinding result.success(true) } + /** + * 显示激励视频广告 + * @param call MethodCall + * @param result Result + */ + private fun showRewardVideoAd(call: MethodCall, result: MethodChannel.Result) { + val iad = RewardVideoPage() + iad.showAd(activity, 1, call) + result.success(true) + } + } diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdRewardEvent.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdRewardEvent.kt new file mode 100644 index 0000000..62f1515 --- /dev/null +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdRewardEvent.kt @@ -0,0 +1,25 @@ +package com.example.union_ad_ssgf.event + + +/** + * @param transId 服务端验证唯一id + * @param customData 服务端验证的自定义信息 + * @param userId 服务端验证的用户信息 + */ +class AdRewardEvent( + posId: String?, + adId: String?, + viewId: Int?, + action: String?, + var transId: String, + var customData: String, + var userId: String, +) : AdEvent(posId, adId, viewId, action) { + override fun toMap(): HashMap { + val newMap = super.toMap() + newMap["transId"] = transId + newMap["customData"] = customData + newMap["userId"] = userId + return newMap + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/page/NativeViewFactory.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/page/NativeViewFactory.kt index 600baed..dcb9a4d 100644 --- a/android/src/main/kotlin/com/example/union_ad_ssgf/page/NativeViewFactory.kt +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/page/NativeViewFactory.kt @@ -7,9 +7,12 @@ import io.flutter.plugin.common.StandardMessageCodec import io.flutter.plugin.platform.PlatformView import io.flutter.plugin.platform.PlatformViewFactory -/// View 名字 +/** + * View 名字 + * @param viewName: 插件代理类 + */ class NativeViewFactory( - private val viewName: String, // 插件代理类 + private val viewName: String, private val pluginDelegate: PluginDelegate ) : PlatformViewFactory(StandardMessageCodec.INSTANCE) { diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/page/RewardVideoPage.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/page/RewardVideoPage.kt new file mode 100644 index 0000000..70c23d0 --- /dev/null +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/page/RewardVideoPage.kt @@ -0,0 +1,135 @@ +package com.example.union_ad_ssgf.page + +import android.util.Log +import com.example.union_ad_ssgf.event.AdEventAction +import com.example.union_ad_ssgf.event.AdRewardEvent +import com.qq.e.ads.rewardvideo.RewardVideoAD +import com.qq.e.ads.rewardvideo.RewardVideoADListener +import com.qq.e.ads.rewardvideo.ServerSideVerificationOptions +import com.qq.e.comm.util.AdError +import io.flutter.plugin.common.MethodCall +import java.util.Locale + +/** + * 激励视频页面 + */ +class RewardVideoPage() : BaseAdPage(), RewardVideoADListener { + private val TAG = RewardVideoPage::class.java.getSimpleName() + + /** + * 激励广告对象 + */ + private lateinit var rewardVideoAD: RewardVideoAD + + /** + * 设置激励视频服务端验证的自定义信息 + */ + private lateinit var customData: String + + /** + * 设置服务端验证的用户信息 + */ + private lateinit var userId: String + + override fun loadAd(call: MethodCall?) { + /** + * 获取对应参数 + */ + val playMuted: Boolean = call!!.argument("playMuted")!! + customData = call.argument("customData")!! + userId = call.argument("userId")!! + + // 1. 初始化激励视频广告 + rewardVideoAD = RewardVideoAD(activity, posId, this, !playMuted) + + // 2. 设置服务端验证信息 + val options = ServerSideVerificationOptions.Builder() + .setCustomData(customData) + .setUserId(userId) // 设置服务端验证的用户信息 + .build() + + // 3. 服务端验证信息 + rewardVideoAD.setServerSideVerificationOptions(options) + + // 4. 加载激励视频广告 + rewardVideoAD.loadAD() + } + + /** + * 广告加载成功,可在此回调后进行广告展示 + **/ + override fun onADLoad() { + Log.i(TAG, "onADLoad"); + rewardVideoAD.showAD(); + sendEvent(AdEventAction.onAdLoaded); + } + + /** + * 视频素材缓存成功,可在此回调后进行广告展示 + */ + override fun onVideoCached() { + Log.i(TAG, "onVideoCached") + } + + /** + * 激励视频广告页面展示 + */ + override fun onADShow() { + Log.i(TAG, "onADShow") + sendEvent(AdEventAction.onAdPresent) + } + + /** + * 激励视频广告曝光 + */ + override fun onADExpose() { + Log.i(TAG, "onADExpose") + sendEvent(AdEventAction.onAdExposure) + } + + /** + * 激励视频触发激励(观看视频大于一定时长或者视频播放完毕) + * @param map 若选择了服务端验证,可以通过 ServerSideVerificationOptions#TRANS_ID 键从 map 中获取此次交易的 id;若未选择服务端验证,则不需关注 map 参数。 + */ + override fun onReward(map: MutableMap?) { + val transId = map!![ServerSideVerificationOptions.TRANS_ID] as String? + Log.i(TAG, "onReward $transId") // 获取服务端验证的唯一 ID + sendEvent(AdRewardEvent(posId,"",1,AdEventAction.onAdReward, transId!!, customData, userId)) + } + + /** + * 激励视频广告被点击 + */ + override fun onADClick() { + Log.i(TAG, "onADClick"); + sendEvent(AdEventAction.onAdClicked); + } + + /** + * 激励视频广告被关闭 + */ + override fun onVideoComplete() { + Log.i(TAG, "onVideoComplete"); + } + + /** + * 激励视频广告被关闭 + */ + override fun onADClose() { + Log.i(TAG, "onADClose"); + sendEvent(AdEventAction.onAdClosed); + } + + /** + * 广告流程出错 + */ + override fun onError(error: AdError) { + val msg = java.lang.String.format( + Locale.getDefault(), + "onError, error code: %d, error msg: %s", + error.errorCode, error.errorMsg, + ) + Log.i(TAG, "onError, adError=$msg") + sendErrorEvent(error.errorCode, error.errorMsg) + } +} \ No newline at end of file diff --git a/example/lib/home_page.dart b/example/lib/home_page.dart index d3710e8..146a92a 100644 --- a/example/lib/home_page.dart +++ b/example/lib/home_page.dart @@ -213,18 +213,18 @@ class _HomePageState extends State { /// 展示激励视频广告 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}"; - // } + 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(() {}); } } diff --git a/lib/union_ad_ssgf.dart b/lib/union_ad_ssgf.dart index 894186f..87cca0a 100644 --- a/lib/union_ad_ssgf.dart +++ b/lib/union_ad_ssgf.dart @@ -61,9 +61,33 @@ class UnionAdSsgf { return result; } + /// 展示激励视频广告 + /// [posId] 广告位 id + /// [playMuted] 是否静音播放 + /// [customData] 设置服务端验证的自定义信息 + /// [userId] 设置服务端验证的用户信息 + static Future showRewardVideoAd( + String posId, { + bool playMuted = false, + String? customData, + String? userId, + }) async { + final bool result = await _methodChannel.invokeMethod( + 'showRewardVideoAd', + { + 'posId': posId, + 'playMuted': playMuted, + 'customData': customData, + 'userId': userId, + }, + ); + return result; + } + ///事件回调 ///@params onData 事件回调 - static Future onEventListener(OnAdEventListener onAdEventListener) async { + static Future onEventListener( + OnAdEventListener onAdEventListener) async { _eventChannel.receiveBroadcastStream().listen((data) { hanleAdEvent(data, onAdEventListener); });