初步添加 Android 开屏广告

This commit is contained in:
Jin857 2024-10-15 17:47:34 +08:00
parent e3f5f1340e
commit 34f73d5c45
22 changed files with 889 additions and 29 deletions

7
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Android API 34, extension level 7 Platform" project-jdk-type="Android SDK" />
<component name="ProjectType">
<option name="id" value="io.flutter" />
</component>
</project>

6
android/.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View File

@ -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<String>("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<Int>("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)
}
}

View File

@ -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")
}
/**

View File

@ -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"
}
}

View File

@ -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<String, Any?> {
val newMap = super.toMap()
newMap["errCode"] = errCode
newMap["errMsg"] = errMsg
return newMap
}
}

View File

@ -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<String, Any?> {
val map = HashMap<String, Any?>()
map["adId"] = adId
map["posId"] = posId
map["action"] = action
map["viewId"] = viewId
return map
}
}

View File

@ -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"
}
}

View File

@ -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())
}
}
}

View File

@ -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<Int>())
}
override fun onADLoaded(list: MutableList<NativeExpressADView>) {
Log.i(TAG, "onADLoaded")
val adResultList: MutableList<Int> = 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)
}
}

View File

@ -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<Int, NativeExpressADView> = 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)
}
}

View File

@ -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<String, Any>?,
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()
}
}
}

View File

@ -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<String, Any>?,
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()
}
}
}

View File

@ -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<FrameLayout>(R.id.splash_ad_container)
ad_logo = findViewById<AppCompatImageView>(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)
}
}

View File

@ -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<String>(UnionADConfig.KEY_POSID)
this.adId = call.argument<String>(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))
}
}

View File

@ -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<String, Object>
return if (viewName == UnionADConfig.KEY_BANNER_VIEW) {
AdBannerView(context, viewId, creationParams, pluginDelegate)
} else {
AdFeedView(context, viewId, creationParams, pluginDelegate)
}
}
}

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
tools:context=".page.AdSplashActivity">
<!-- 广告容器 -->
<FrameLayout
android:id="@+id/splash_ad_container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/splash_ad_logo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- Logo 内容 -->
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/splash_ad_logo"
android:layout_width="match_parent"
android:layout_height="96dp"
android:src="@mipmap/flutterads_logo"
android:scaleType="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1 @@
<resources></resources>

View File

@ -0,0 +1,17 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
<!-- Status bar color. -->
<!-- <item name="android:statusBarColor" tools:targetApi="l">@android:color/transparent</item>-->
<!-- Customize your theme here. -->
</style>
<!-- 开屏页主题 -->
<style name="SplashTheme" parent="AppTheme">
<item name="android:windowAnimationStyle">@style/WindowAnimationStyle</item>
</style>
<!-- 设置动画 -->
<style name="WindowAnimationStyle">
<item name="android:windowEnterAnimation">@android:anim/fade_in</item>
<item name="android:windowExitAnimation">@android:anim/fade_out</item>
</style>
</resources>

View File

@ -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)
}
}

View File

@ -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(