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 0000000..f290fda
Binary files /dev/null and b/android/src/main/res/mipmap-xxhdpi/flutterads_logo.png differ
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(