From 34f73d5c453636fff3984560cb06c46bffaa12df Mon Sep 17 00:00:00 2001 From: Jin857 Date: Tue, 15 Oct 2024 17:47:34 +0800 Subject: [PATCH] =?UTF-8?q?=20=E5=88=9D=E6=AD=A5=E6=B7=BB=E5=8A=A0=20Andro?= =?UTF-8?q?id=20=E5=BC=80=E5=B1=8F=E5=B9=BF=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/misc.xml | 7 + android/.idea/vcs.xml | 6 + .../example/union_ad_ssgf/PluginDelegate.kt | 63 ++++--- .../union_ad_ssgf/UnionAdSsgfPlugin.kt | 17 +- .../union_ad_ssgf/config/UnionADConfig.kt | 40 +++++ .../union_ad_ssgf/event/AdErrorEvent.kt | 28 ++++ .../example/union_ad_ssgf/event/AdEvent.kt | 36 ++++ .../union_ad_ssgf/event/AdEventAction.kt | 32 ++++ .../union_ad_ssgf/event/AdEventHandler.kt | 31 ++++ .../example/union_ad_ssgf/load/FeedAdLoad.kt | 109 ++++++++++++ .../union_ad_ssgf/load/FeedAdManager.kt | 57 +++++++ .../union_ad_ssgf/page/AdBannerView.kt | 97 +++++++++++ .../example/union_ad_ssgf/page/AdFeedView.kt | 91 ++++++++++ .../union_ad_ssgf/page/AdSplashActivity.kt | 157 ++++++++++++++++++ .../example/union_ad_ssgf/page/BaseAdPage.kt | 69 ++++++++ .../union_ad_ssgf/page/NativeViewFactory.kt | 26 +++ .../main/res/layout/activity_ad_splash.xml | 28 ++++ .../res/mipmap-xxhdpi/flutterads_logo.png | Bin 0 -> 18072 bytes android/src/main/res/values/strings.xml | 1 + android/src/main/res/values/themes.xml | 17 ++ .../union_ad_ssgf/UnionAdSsgfPluginTest.kt | 4 +- test/union_ad_ssgf_method_channel_test.dart | 2 +- 22 files changed, 889 insertions(+), 29 deletions(-) create mode 100644 .idea/misc.xml create mode 100644 android/.idea/vcs.xml create mode 100644 android/src/main/kotlin/com/example/union_ad_ssgf/config/UnionADConfig.kt create mode 100644 android/src/main/kotlin/com/example/union_ad_ssgf/event/AdErrorEvent.kt create mode 100644 android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEvent.kt create mode 100644 android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEventAction.kt create mode 100644 android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEventHandler.kt create mode 100644 android/src/main/kotlin/com/example/union_ad_ssgf/load/FeedAdLoad.kt create mode 100644 android/src/main/kotlin/com/example/union_ad_ssgf/load/FeedAdManager.kt create mode 100644 android/src/main/kotlin/com/example/union_ad_ssgf/page/AdBannerView.kt create mode 100644 android/src/main/kotlin/com/example/union_ad_ssgf/page/AdFeedView.kt create mode 100644 android/src/main/kotlin/com/example/union_ad_ssgf/page/AdSplashActivity.kt create mode 100644 android/src/main/kotlin/com/example/union_ad_ssgf/page/BaseAdPage.kt create mode 100644 android/src/main/kotlin/com/example/union_ad_ssgf/page/NativeViewFactory.kt create mode 100644 android/src/main/res/layout/activity_ad_splash.xml create mode 100644 android/src/main/res/mipmap-xxhdpi/flutterads_logo.png create mode 100644 android/src/main/res/values/strings.xml create mode 100644 android/src/main/res/values/themes.xml diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..56a6d29 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/android/.idea/vcs.xml b/android/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/android/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ 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 9216e7f..82aaaa3 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 @@ -3,13 +3,16 @@ package com.example.union_ad_ssgf import android.annotation.SuppressLint import android.app.Activity import android.util.Log - +import com.example.union_ad_ssgf.config.UnionADConfig +import com.qq.e.comm.managers.GDTAdSdk +import com.qq.e.comm.managers.setting.GlobalSetting.setPersonalizedState import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding import io.flutter.plugin.common.EventChannel import io.flutter.plugin.common.EventChannel.EventSink import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel + class PluginDelegate(var activity: Activity, pluginBinding: FlutterPluginBinding) : MethodChannel.MethodCallHandler, EventChannel.StreamHandler { @@ -53,7 +56,7 @@ class PluginDelegate(var activity: Activity, pluginBinding: FlutterPluginBinding } // 开屏广告 "showSplashAd" -> { - + showSplashAd(call, result) } // 激励广告 "showRewardVideoAd" -> { @@ -85,7 +88,7 @@ class PluginDelegate(var activity: Activity, pluginBinding: FlutterPluginBinding * @param call MethodCall * @param result Result */ - private fun getPlatformVersion(call: MethodCall?, result: MethodChannel.Result) { + private fun getPlatformVersion(call: MethodCall, result: MethodChannel.Result) { result.success(" Union AD Android " + android.os.Build.VERSION.RELEASE); } @@ -94,22 +97,23 @@ class PluginDelegate(var activity: Activity, pluginBinding: FlutterPluginBinding * @param call MethodCall * @param result Result */ - private fun initAd(call: MethodCall?, result: MethodChannel.Result) { + private fun initAd(call: MethodCall, result: MethodChannel.Result) { val appId = call.argument("appId") - result.success(" Union AD AppId " + appId); - // GDTAdSdk.initWithoutStart(activity.getApplicationContext(), appId); - // GDTAdSdk.start(new GDTAdSdk.OnStartListener() { - // @Override - // public void onStartSuccess() { - // Log.e(TAG, "广告初始化成功"); - // result.success(true); - // } - // @Override - // public void onStartFailed(Exception e) { - // Log.e(TAG, "广告初始化失败", e); - // result.success(false); - // } - // }); + 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()) + } + } + ) + result.success(true) } /** @@ -117,9 +121,28 @@ class PluginDelegate(var activity: Activity, pluginBinding: FlutterPluginBinding * @param call MethodCall * @param result Result */ - private fun setPersonalizedState(call: MethodCall?, result: MethodChannel.Result) { + private fun setPersonalizedState(call: MethodCall, result: MethodChannel.Result) { val state = call.argument("state")!! - // GlobalSetting.setPersonalizedState(state); + setPersonalizedState(state) result.success(true); } + + /** + * 开屏广告 + * @param call MethodCall + * @param result Result + */ + 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) + } + } 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 3a78631..8523fa9 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 @@ -14,13 +14,16 @@ class UnionAdSsgfPlugin : FlutterPlugin, ActivityAware { /** * 方法通道: * - * 用于Flutter与原生Android之间通信的MethodChannel + * 用于Flutter与原生Android之间通信的 MethodChannel * 此本地引用用于向Flutter引擎注册插件,并在Flutter引擎与Activity分离时注销它 */ - private var methodChannel: MethodChannel = null; + private lateinit var methodChannel: MethodChannel /** * 事件通道 + * + * 用于Flutter与原生Android之间通信的 EventChannel + * 此本地引用用于向Flutter引擎注册插件,并在Flutter引擎与Activity分离时注销它 */ private lateinit var eventChannel: EventChannel @@ -28,7 +31,7 @@ class UnionAdSsgfPlugin : FlutterPlugin, ActivityAware { /** * 插件代理 */ - private var delegate: PluginDelegate? = null + var delegate: PluginDelegate? = null /** @@ -40,13 +43,13 @@ class UnionAdSsgfPlugin : FlutterPlugin, ActivityAware { * 初始化方法通道和事件通道 */ override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { - bind = flutterPluginBinding; + bind = flutterPluginBinding + // 注册 - 方法通道 - methodChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "union_ad_ssgf_method"); + methodChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "union_ad_ssgf_method") // 注册 - 监听通道 - eventChannel = - EventChannel(flutterPluginBinding.getBinaryMessenger(), "union_ad_ssgf_event"); + eventChannel = EventChannel(flutterPluginBinding.getBinaryMessenger(), "union_ad_ssgf_event") } /** diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/config/UnionADConfig.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/config/UnionADConfig.kt new file mode 100644 index 0000000..69cd85d --- /dev/null +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/config/UnionADConfig.kt @@ -0,0 +1,40 @@ +package com.example.union_ad_ssgf.config + +import android.annotation.SuppressLint + +class UnionADConfig { + + /*初始化代码块*/ + init { + _instance = this + } + + companion object { + // 插件代理对象 + @SuppressLint("StaticFieldLeak") + private lateinit var _instance: UnionADConfig + + fun getInstance(): UnionADConfig { + return _instance + } + + // Banner View + const val KEY_BANNER_VIEW = "flutter_qq_ads_banner" + + // Feed View + const val KEY_FEED_VIEW = "flutter_qq_ads_feed" + + // 广告参数 + const val KEY_POSID = "posId" + + // 广告参数 + const val KEY_ADID = "adId" + + // logo 参数 + const val KEY_LOGO = "logo" + + // fetchDelay 参数 + const val KEY_FETCH_DELAY = "fetchDelay" + } + +} \ No newline at end of file diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdErrorEvent.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdErrorEvent.kt new file mode 100644 index 0000000..ccacf37 --- /dev/null +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdErrorEvent.kt @@ -0,0 +1,28 @@ +package com.example.union_ad_ssgf.event + + +class AdErrorEvent(posId: String?, adId: String?, viewId: Int?, errCode: Int, errMsg: String?) : + AdEvent(posId, adId, viewId, AdEventAction.onAdError) { + // 错误码 + private var errCode = 0 + + // 错误信息 + private var errMsg: String? = null + + // 错误事件实体 + init { + this.errMsg = errMsg + this.errCode = errCode + } + + /** + * 重写 toMap 方法 + * @return 返回错误事件的map + */ + override fun toMap(): HashMap { + val newMap = super.toMap() + newMap["errCode"] = errCode + newMap["errMsg"] = errMsg + return newMap + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEvent.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEvent.kt new file mode 100644 index 0000000..4382717 --- /dev/null +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEvent.kt @@ -0,0 +1,36 @@ +package com.example.union_ad_ssgf.event + +import java.util.HashMap + +open class AdEvent(posId: String?, adId: String?, viewId: Int?, action: String?) { + // 广告位 id + private var posId: String? = null + + // 广告 id + private var adId: String? = null + + private var viewId: Int? = null + + // 操作 + private var action: String? = null + + init { + this.adId = adId + this.posId = posId + this.action = action + this.viewId = viewId + } + + /** + * 转换为 Map 方面传输 + * @return 转换后的 Map 对象 + */ + open fun toMap(): HashMap { + val map = HashMap() + map["adId"] = adId + map["posId"] = posId + map["action"] = action + map["viewId"] = viewId + return map + } +} diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEventAction.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEventAction.kt new file mode 100644 index 0000000..1f92f89 --- /dev/null +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEventAction.kt @@ -0,0 +1,32 @@ +package com.example.union_ad_ssgf.event + +class AdEventAction { + companion object { + // 广告错误 + val onAdError = "onAdError" + + // 广告加载成功 + val onAdLoaded = "onAdLoaded" + + // 广告填充 + val onAdPresent = "onAdPresent" + + // 广告曝光 + val onAdExposure = "onAdExposure" + + // 广告关闭 + val onAdClosed = "onAdClosed" + + // 广告点击 + val onAdClicked = "onAdClicked" + + // 广告跳过 + val onAdSkip = "onAdSkip" + + // 广告播放或计时完毕 + val onAdComplete = "onAdComplete" + + // 获得广告激励 + val onAdReward = "onAdReward" + } +} diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEventHandler.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEventHandler.kt new file mode 100644 index 0000000..21dccc8 --- /dev/null +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/event/AdEventHandler.kt @@ -0,0 +1,31 @@ +package com.example.union_ad_ssgf.event + + +class AdEventHandler { + companion object { + + // 广告事件处理对象 + @Volatile private var _instance: AdEventHandler? = null + + /** + * 获取广告事件处理类 + * @return 广告事件处理对象 + */ + fun getInstance(): AdEventHandler? { + if (_instance == null) { + synchronized(AdEventHandler::class.java) { _instance = AdEventHandler() } + } + return _instance + } + } + + /** + * 添加广告事件 + * @param event 广告事件 + */ + fun sendEvent(event: AdEvent?) { + if (event != null) { +// PluginDelegate.getInstance().addEvent(event.toMap()) + } + } +} diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/load/FeedAdLoad.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/load/FeedAdLoad.kt new file mode 100644 index 0000000..80e271d --- /dev/null +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/load/FeedAdLoad.kt @@ -0,0 +1,109 @@ +package com.example.union_ad_ssgf.load + +import android.app.Activity +import android.content.Intent +import android.util.Log +import androidx.localbroadcastmanager.content.LocalBroadcastManager +import com.example.union_ad_ssgf.config.UnionADConfig +import com.example.union_ad_ssgf.event.AdEventAction +import com.example.union_ad_ssgf.page.BaseAdPage +import com.qq.e.ads.nativ.ADSize +import com.qq.e.ads.nativ.NativeExpressAD +import com.qq.e.ads.nativ.NativeExpressADView +import com.qq.e.comm.util.AdError +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel +import java.util.Locale + +/** 信息流加载对象 */ +class FeedAdLoad : BaseAdPage(), NativeExpressAD.NativeExpressADListener { + private val TAG = FeedAdLoad::class.java.getSimpleName() + private var result: MethodChannel.Result? = null + + /** + * 加载信息流广告列表 + * @param call + * @param result + */ + fun loadFeedAdList(activity: Activity?, call: MethodCall, result: MethodChannel.Result) { + this.result = result + showAd(activity, null, call) + } + + override fun onNoAD(error: AdError) { + val msg = + String.format( + Locale.getDefault(), + "onError, error code: %d, error msg: %s", + error.getErrorCode(), + error.getErrorMsg() + ) + Log.i(TAG, "onError, adError=$msg") + sendErrorEvent(error.getErrorCode(), error.getErrorMsg()) + this.result!!.success(ArrayList()) + } + + override fun onADLoaded(list: MutableList) { + Log.i(TAG, "onADLoaded") + val adResultList: MutableList = ArrayList() + + if (list.isEmpty()) { + result!!.success(adResultList) + return + } + for (adItem in list) { + val key = adItem.hashCode() + adResultList.add(key) + FeedAdManager.getInstance()?.putAd(key, adItem) + } + // 添加广告事件 + sendEvent(AdEventAction.onAdLoaded) + result!!.success(adResultList) + } + + override fun onRenderFail(nativeExpressADView: NativeExpressADView) { + Log.i(TAG, "onRenderFail") + sendErrorEvent(-100, "onRenderFail") + sendBroadcastEvent(nativeExpressADView, AdEventAction.onAdError) + } + + private fun sendBroadcastEvent(adView: NativeExpressADView, event: String) { + val intent = Intent() + intent.setAction(UnionADConfig.KEY_FEED_VIEW + "_" + adView.hashCode()) + intent.putExtra("event", event) + LocalBroadcastManager.getInstance(activity!!).sendBroadcast(intent) + } + + override fun onRenderSuccess(nativeExpressADView: NativeExpressADView) { + Log.i(TAG, "onRenderSuccess") + sendEvent(AdEventAction.onAdPresent) + sendBroadcastEvent(nativeExpressADView, AdEventAction.onAdPresent) + } + + override fun onADExposure(nativeExpressADView: NativeExpressADView?) { + Log.i(TAG, "onADExposure") + sendEvent(AdEventAction.onAdExposure) + } + + override fun onADClicked(nativeExpressADView: NativeExpressADView?) { + Log.i(TAG, "onADClicked") + sendEvent(AdEventAction.onAdClicked) + } + + override fun onADClosed(nativeExpressADView: NativeExpressADView) { + Log.i(TAG, "onADClosed") + sendEvent(AdEventAction.onAdClosed) + sendBroadcastEvent(nativeExpressADView, AdEventAction.onAdClosed) + } + + override fun onADLeftApplication(p0: NativeExpressADView?) {} + + override fun loadAd(call: MethodCall?) { + // 获取请求模板广告素材的尺寸 + val width: Int = call!!.argument("width")!! + val height: Int = call.argument("height")!! + val count: Int = call.argument("count")!! + val ad = NativeExpressAD(activity, ADSize(width, height), posId, this) + ad.loadAD(count) + } +} diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/load/FeedAdManager.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/load/FeedAdManager.kt new file mode 100644 index 0000000..d4d0e9c --- /dev/null +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/load/FeedAdManager.kt @@ -0,0 +1,57 @@ +package com.example.union_ad_ssgf.load + +import com.qq.e.ads.nativ.NativeExpressADView + + +/** + * 信息流广告管理 + */ +class FeedAdManager { + private val TAG = FeedAdManager::class.java.getSimpleName() + + companion object { + // 信息流广告管理类对象 + private var _instance: FeedAdManager? = null + + @Synchronized + fun getInstance(): FeedAdManager? { + if (_instance == null) { + synchronized(FeedAdManager::class.java) { _instance = FeedAdManager() } + } + return _instance + } + } + + // 信息流广告列表 + private val feedAdList: MutableMap = HashMap() + + /** + * 添加广告渲染对象 + * + * @param key 广告缓存id + * @param ad 广告渲染对象 + */ + fun putAd(key: Int, ad: NativeExpressADView) { + feedAdList[key] = ad + } + + /** + * 获取广告渲染对象 + * + * @param key 广告缓存 id + * @return 广告渲染对象 + */ + fun getAd(key: Int): NativeExpressADView? { + return feedAdList[key] + } + + /** + * 删除广告渲染对象 + * + * @param key 广告缓存id + * @return 广告渲染对象 + */ + fun removeAd(key: Int): NativeExpressADView? { + return feedAdList.remove(key) + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdBannerView.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdBannerView.kt new file mode 100644 index 0000000..8d71c96 --- /dev/null +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdBannerView.kt @@ -0,0 +1,97 @@ +package com.example.union_ad_ssgf.page + +import android.content.Context +import android.view.View +import android.widget.FrameLayout +import com.qq.e.ads.banner2.UnifiedBannerADListener +import com.qq.e.ads.banner2.UnifiedBannerView +import com.qq.e.comm.util.AdError +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.platform.PlatformView +import java.util.Locale + +import android.util.Log; +import com.example.union_ad_ssgf.PluginDelegate +import com.example.union_ad_ssgf.event.AdEventAction + +class AdBannerView( + context: Context, + private var id: Int, + creationParams: Map?, + private var pluginDelegate: PluginDelegate? +) : BaseAdPage(), PlatformView, UnifiedBannerADListener { + private val TAG = AdBannerView::class.java.getSimpleName() + private var frameLayout = FrameLayout(context) + private var bv: UnifiedBannerView? = null + private var params = creationParams + + init { + val call = MethodCall("AdBannerView", creationParams) + showAd(this.pluginDelegate!!.activity, id, call); + } + + override fun loadAd(call: MethodCall?) { + // 获取轮播时间间隔参数 + val interval = params!!["interval"] as Int + // 加载广告 Banner + bv = UnifiedBannerView(activity, posId, this) + frameLayout!!.addView(bv) + // 设置轮播时间间隔 + bv!!.setRefresh(interval) + bv!!.loadAD() + } + + override fun getView(): View? { + return frameLayout; + } + + override fun dispose() { + disposeAd(); + } + + override fun onNoAD(error: AdError) { + val msg = java.lang.String.format( + Locale.getDefault(), "onNoAD, error code: %d, error msg: %s", + error.getErrorCode(), error.getErrorMsg() + ) + Log.e(TAG, msg) + sendErrorEvent(error.getErrorCode(), error.getErrorMsg()) + disposeAd() + } + + override fun onADReceive() { + Log.i(TAG, "onADReceive"); + sendEvent(AdEventAction.onAdLoaded); + } + + override fun onADExposure() { + Log.i(TAG, "onADExposure"); + sendEvent(AdEventAction.onAdExposure); + } + + override fun onADClosed() { + Log.i(TAG, "onADClosed"); + sendEvent(AdEventAction.onAdClosed); + disposeAd(); + } + + override fun onADClicked() { + Log.i(TAG, "onADClicked"); + sendEvent(AdEventAction.onAdClicked); + } + + override fun onADLeftApplication() { + Log.i(TAG, "onADLeftApplication"); + } + + /** + * 销毁广告 + */ + private fun disposeAd() { + frameLayout!!.removeAllViews() + if (bv != null) { + bv!!.destroy() + } + } + +} \ No newline at end of file diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdFeedView.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdFeedView.kt new file mode 100644 index 0000000..b0b139f --- /dev/null +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdFeedView.kt @@ -0,0 +1,91 @@ +package com.example.union_ad_ssgf.page + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.view.View +import android.widget.FrameLayout +import androidx.localbroadcastmanager.content.LocalBroadcastManager +import com.example.union_ad_ssgf.PluginDelegate +import com.example.union_ad_ssgf.config.UnionADConfig +import com.example.union_ad_ssgf.event.AdEventAction +import com.example.union_ad_ssgf.load.FeedAdManager +import com.qq.e.ads.nativ.NativeExpressADView +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.platform.PlatformView + +class AdFeedView( + context: Context, + private var id: Int, + private var creationParams: Map?, + private var pluginDelegate: PluginDelegate? +) : BaseAdPage(), PlatformView { + private var frameLayout = FrameLayout(context) + private var fad: NativeExpressADView? = null + private var receiver: BroadcastReceiver? = null + + init { + val call = MethodCall("AdFeedView", creationParams) + showAd(this.pluginDelegate!!.activity, id, call) + } + + override fun loadAd(call: MethodCall?) { + val key = adId!!.toInt() + regReceiver(key) + fad = FeedAdManager.getInstance()!!.getAd(key) + if (fad != null) { + if (frameLayout.childCount > 0) { + frameLayout.removeAllViews() + } + fad!!.render() + frameLayout.addView(fad) + } + } + + override fun getView(): View? { + return frameLayout + } + + override fun dispose() { + removeAd() + } + + /** + * 注册广播 + * @param key key + */ + private fun regReceiver(key: Int) { + // 注册广播 + receiver = + object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val event = intent.getStringExtra("event") + sendEvent(event) + if (AdEventAction.onAdClosed == event || AdEventAction.onAdError == event) { + this@AdFeedView.disposeAd() + } + } + } + val intentFilter = IntentFilter(UnionADConfig.KEY_FEED_VIEW + "_" + key) + LocalBroadcastManager.getInstance(activity!!).registerReceiver(receiver!!, intentFilter) + } + + /** 移除广告 */ + private fun removeAd() { + frameLayout!!.removeAllViews() + // 注销广播 + if (receiver != null) { + LocalBroadcastManager.getInstance(activity!!).unregisterReceiver(receiver!!) + } + } + + /** 销毁广告 */ + private fun disposeAd() { + removeAd() + FeedAdManager.getInstance()!!.removeAd(adId!!.toInt()) + if (fad != null) { + fad!!.destroy() + } + } +} diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdSplashActivity.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdSplashActivity.kt new file mode 100644 index 0000000..07e9acd --- /dev/null +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/page/AdSplashActivity.kt @@ -0,0 +1,157 @@ +package com.example.union_ad_ssgf.page + +import android.annotation.SuppressLint +import android.os.Bundle +import android.text.TextUtils +import android.util.Log +import android.view.KeyEvent +import android.view.View +import android.widget.FrameLayout +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.AppCompatImageView +import com.example.union_ad_ssgf.R +import com.example.union_ad_ssgf.config.UnionADConfig +import com.example.union_ad_ssgf.event.AdErrorEvent +import com.example.union_ad_ssgf.event.AdEvent +import com.example.union_ad_ssgf.event.AdEventAction +import com.example.union_ad_ssgf.event.AdEventHandler +import com.qq.e.ads.splash.SplashAD +import com.qq.e.ads.splash.SplashADListener +import com.qq.e.comm.util.AdError + + +/** + * 开屏广告 + */ +class AdSplashActivity() : AppCompatActivity(), SplashADListener { + private val TAG = AdSplashActivity::class.java.getSimpleName() + + // 广告容器 + private var ad_container: FrameLayout? = null + + // 自定义品牌 logo + private var ad_logo: AppCompatImageView? = null + + // 广告位 id + private var posId: String? = null + + // 是否全屏 + private var isFullScreen = false + + // 开屏广告 + private var splashAD: SplashAD? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_ad_splash); + initView(); + initData(); + } + + /** + * 初始化View + */ + private fun initView() { + ad_container = findViewById(R.id.splash_ad_container) + ad_logo = findViewById(R.id.splash_ad_logo) + } + + /** + * 初始化数据 + */ + private fun initData() { + // 获取参数 + posId = intent.getStringExtra(UnionADConfig.KEY_POSID) + val logo = intent.getStringExtra(UnionADConfig.KEY_LOGO) + val fetchDelay = intent.getDoubleExtra(UnionADConfig.KEY_FETCH_DELAY, 0.0) + val absFetchDelay = (fetchDelay * 1000).toInt() + isFullScreen = TextUtils.isEmpty(logo) + // 创建开屏广告 + splashAD = SplashAD(this, posId, this, absFetchDelay) + if (isFullScreen) { + // logo 为空则加载全屏广告 + ad_logo!!.setVisibility(View.GONE) + splashAD!!.fetchFullScreenAdOnly() + } else { + // 加载 logo + val resId: Int = getMipmapId(logo!!) + if (resId > 0) { + ad_logo!!.setVisibility(View.VISIBLE) + ad_logo!!.setImageResource(resId) + } + // 加载广告 + splashAD!!.fetchAdOnly() + } + } + + override fun onADDismissed() { + Log.d(TAG, "onADDismissed") + finishPage() + AdEventHandler.getInstance()?.sendEvent(AdEvent(posId, "", 1, AdEventAction.onAdClosed)); + } + + override fun onNoAD(adError: AdError) { + Log.d(TAG, "onNoAD adError:" + adError.errorMsg); + finishPage() + AdEventHandler.getInstance()!! + .sendEvent(AdErrorEvent(posId, "", 1, adError.errorCode, adError.errorMsg)); + } + + override fun onADPresent() { + Log.d(TAG, "onADPresent") + AdEventHandler.getInstance()!!.sendEvent(AdEvent(posId, "", 1, AdEventAction.onAdPresent)) + } + + override fun onADClicked() { + Log.d(TAG, "onADClicked") + AdEventHandler.getInstance()!!.sendEvent(AdEvent(posId, "", 1, AdEventAction.onAdClicked)) + } + + override fun onADTick(millisUntilFinished: Long) { + Log.d(TAG, "onADTick millisUntilFinished:$millisUntilFinished"); + } + + override fun onADExposure() { + Log.d(TAG, "onADExposure") + AdEventHandler.getInstance()!!.sendEvent(AdEvent(posId, "", 1, AdEventAction.onAdExposure)) + } + + override fun onADLoaded(expireTimestamp: Long) { + Log.d(TAG, "onADLoaded expireTimestamp:$expireTimestamp") + AdEventHandler.getInstance()!!.sendEvent(AdEvent(posId, "", 1, AdEventAction.onAdLoaded)) + if (isFullScreen) { + splashAD!!.showFullScreenAd(ad_container) + } else { + splashAD!!.showAd(ad_container) + } + } + + /** + * 完成广告,退出开屏页面 + */ + private fun finishPage() { + finish() + // 设置退出动画 + overridePendingTransition(0, android.R.anim.fade_out) + } + + /** + * 开屏页一定要禁止用户对返回按钮的控制,否则将可能导致用户手动退出了App而广告无法正常曝光和计费 + */ + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { + return if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_HOME) { + true + } else super.onKeyDown(keyCode, event) + } + + /** + * 获取图片资源的id + * + * @param resName 资源名称,不带后缀 + * @return 返回资源id + */ + @SuppressLint("DiscouragedApi") + private fun getMipmapId(resName: String): Int { + return getResources().getIdentifier(resName, "mipmap", packageName) + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/com/example/union_ad_ssgf/page/BaseAdPage.kt b/android/src/main/kotlin/com/example/union_ad_ssgf/page/BaseAdPage.kt new file mode 100644 index 0000000..2769a65 --- /dev/null +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/page/BaseAdPage.kt @@ -0,0 +1,69 @@ +package com.example.union_ad_ssgf.page + +import android.app.Activity +import com.example.union_ad_ssgf.config.UnionADConfig +import com.example.union_ad_ssgf.event.AdErrorEvent +import com.example.union_ad_ssgf.event.AdEvent +import com.example.union_ad_ssgf.event.AdEventHandler +import io.flutter.plugin.common.MethodCall + +abstract class BaseAdPage { + // 上下文 + protected var activity: Activity? = null + + // 广告位 id + protected var posId: String? = null + + // 广告位 id + protected var adId: String? = null + + // 广告定位ID + protected var viewId: Int? = null + + /** + * 显示广告 + * + * @param activity 上下文 + * @param call 方法调用 + */ + fun showAd(activity: Activity?, viewId: Int?, call: MethodCall) { + this.activity = activity + this.viewId = viewId + this.posId = call.argument(UnionADConfig.KEY_POSID) + this.adId = call.argument(UnionADConfig.KEY_ADID) + loadAd(call) + } + + /** + * 加载广告 + * @param call 方法调用 + */ + abstract fun loadAd(call: MethodCall?) + + /** + * 发送广告事件 + * @param event 广告事件 + */ + protected fun sendEvent(event: AdEvent?) { + AdEventHandler.getInstance()?.sendEvent(event) + } + + /** + * 发送广告事件 + * + * @param action 操作 + */ + protected fun sendEvent(action: String?) { + sendEvent(AdEvent(posId, adId, viewId, action)) + } + + /** + * 发送错误事件 + * + * @param errCode 错误码 + * @param errMsg 错误事件 + */ + protected fun sendErrorEvent(errCode: Int, errMsg: String?) { + sendEvent(AdErrorEvent(posId, adId, viewId, errCode, errMsg)) + } +} 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 new file mode 100644 index 0000000..600baed --- /dev/null +++ b/android/src/main/kotlin/com/example/union_ad_ssgf/page/NativeViewFactory.kt @@ -0,0 +1,26 @@ +package com.example.union_ad_ssgf.page + +import android.content.Context +import com.example.union_ad_ssgf.PluginDelegate +import com.example.union_ad_ssgf.config.UnionADConfig +import io.flutter.plugin.common.StandardMessageCodec +import io.flutter.plugin.platform.PlatformView +import io.flutter.plugin.platform.PlatformViewFactory + +/// View 名字 +class NativeViewFactory( + private val viewName: String, // 插件代理类 + private val pluginDelegate: PluginDelegate +) : + PlatformViewFactory(StandardMessageCodec.INSTANCE) { + + override fun create(context: Context, viewId: Int, args: Any?): PlatformView { + val creationParams = args as Map + return if (viewName == UnionADConfig.KEY_BANNER_VIEW) { + AdBannerView(context, viewId, creationParams, pluginDelegate) + } else { + AdFeedView(context, viewId, creationParams, pluginDelegate) + } + } + +} \ No newline at end of file diff --git a/android/src/main/res/layout/activity_ad_splash.xml b/android/src/main/res/layout/activity_ad_splash.xml new file mode 100644 index 0000000..d053f0a --- /dev/null +++ b/android/src/main/res/layout/activity_ad_splash.xml @@ -0,0 +1,28 @@ + + + + + + + \ No newline at end of file diff --git a/android/src/main/res/mipmap-xxhdpi/flutterads_logo.png b/android/src/main/res/mipmap-xxhdpi/flutterads_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f290fdaa8b10938620ff872b441cc49880fc4b0e GIT binary patch literal 18072 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 NJYD@<);T3K0RWxtoY4RP literal 0 HcmV?d00001 diff --git a/android/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml new file mode 100644 index 0000000..73862c4 --- /dev/null +++ b/android/src/main/res/values/strings.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/android/src/main/res/values/themes.xml b/android/src/main/res/values/themes.xml new file mode 100644 index 0000000..020f1da --- /dev/null +++ b/android/src/main/res/values/themes.xml @@ -0,0 +1,17 @@ + + + + + + + + \ No newline at end of file diff --git a/android/src/test/kotlin/com/example/union_ad_ssgf/UnionAdSsgfPluginTest.kt b/android/src/test/kotlin/com/example/union_ad_ssgf/UnionAdSsgfPluginTest.kt index 1008f0e..8d73f4d 100644 --- a/android/src/test/kotlin/com/example/union_ad_ssgf/UnionAdSsgfPluginTest.kt +++ b/android/src/test/kotlin/com/example/union_ad_ssgf/UnionAdSsgfPluginTest.kt @@ -20,8 +20,10 @@ internal class UnionAdSsgfPluginTest { val call = MethodCall("getPlatformVersion", null) val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java) - plugin.onMethodCall(call, mockResult) + println("--------->>>> ${plugin}, ${plugin.delegate}") + + plugin.delegate?.onMethodCall(call, mockResult) Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE) } } diff --git a/test/union_ad_ssgf_method_channel_test.dart b/test/union_ad_ssgf_method_channel_test.dart index 4e6089f..b11eb19 100644 --- a/test/union_ad_ssgf_method_channel_test.dart +++ b/test/union_ad_ssgf_method_channel_test.dart @@ -6,7 +6,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); MethodChannelUnionAdSsgf platform = MethodChannelUnionAdSsgf(); - const MethodChannel channel = MethodChannel('union_ad_ssgf'); + const MethodChannel channel = MethodChannel('union_ad_ssgf_method'); setUp(() { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(