diff --git a/app/src/main/java/com/gh/ad/AdDelegateHelper.kt b/app/src/main/java/com/gh/ad/AdDelegateHelper.kt index 45871731fa..3f31efcee7 100644 --- a/app/src/main/java/com/gh/ad/AdDelegateHelper.kt +++ b/app/src/main/java/com/gh/ad/AdDelegateHelper.kt @@ -227,18 +227,7 @@ object AdDelegateHelper { /** * 是否大于开屏广告展示间隔时长 */ - private fun isMatchStartUpAdDisplayRule(): Boolean { - mSplashAd?.displayRule?.run { - if (adDisplayInterval > 0) { - val lastShowTime = SPUtils.getLong(Constants.SP_LAST_SPLASH_AD_SHOW_TIME, 0L) - val durationInMinutes = (System.currentTimeMillis() - lastShowTime).toFloat() / 1000 / 60 - return durationInMinutes > adDisplayInterval - } else { - return true - } - } - return true - } + private fun isMatchStartUpAdDisplayRule(): Boolean = isMatchAdDisplayRule(mSplashAd, Constants.SP_LAST_SPLASH_AD_SHOW_TIME) /** * 是否大于广告管理展示间隔时长 @@ -292,6 +281,7 @@ object AdDelegateHelper { adViewHeightInDp: Float, startAdContainer: ViewGroup, sdkStartAdContainer: ViewGroup, + sdkJumpBtn: TextView, adsViewGroup: FrameLayout, handler: BaseActivity.BaseHandler, isHotLaunch: Boolean, @@ -313,6 +303,7 @@ object AdDelegateHelper { adViewHeightInDp, startAdContainer, sdkStartAdContainer, + sdkJumpBtn, adsViewGroup, handler, isHotLaunch, @@ -330,6 +321,7 @@ object AdDelegateHelper { adViewHeightInDp, startAdContainer, sdkStartAdContainer, + sdkJumpBtn, adsViewGroup, handler, isHotLaunch, @@ -353,6 +345,7 @@ object AdDelegateHelper { adViewHeightInDp: Float, startAdContainer: ViewGroup, sdkStartAdContainer: ViewGroup, + sdkJumpBtn: TextView, adsViewGroup: FrameLayout, handler: BaseActivity.BaseHandler, isHotLaunch: Boolean, @@ -374,6 +367,7 @@ object AdDelegateHelper { adViewHeightInDp, startAdContainer, sdkStartAdContainer, + sdkJumpBtn, adsViewGroup, handler, isHotLaunch, @@ -403,13 +397,14 @@ object AdDelegateHelper { sdkStartAdContainer.visibility = View.VISIBLE requestCsjSplashAd( activity, - thirdPartyAd.slotId, adViewWidthInPx, adViewHeightInPx, adViewWidthInDp, adViewHeightInDp, sdkStartAdContainer, + sdkJumpBtn, timeout, + isHotLaunch, sdkSplashCallback ) } @@ -420,27 +415,65 @@ object AdDelegateHelper { */ private fun requestCsjSplashAd( activity: Activity, - slotId: String, adViewWidthInPx: Int, adViewHeightInPx: Int, adViewWidthInDp: Float, adViewHeightInDp: Float, startAdContainer: ViewGroup, + sdkJumpBtn: TextView, timeout: Int, + isHotLaunch: Boolean, callback: (isSuccess: Boolean) -> Unit, ) { - if (mCsjAdImpl == null) { + val thirdPartyAd = if (isHotLaunch) mSplashAd?.hotStartThirdPartyAd else mSplashAd?.thirdPartyAd + if (mCsjAdImpl == null || thirdPartyAd == null) { callback.invoke(false) } else { + sdkJumpBtn.setOnClickListener { + callback.invoke(true) + if (activity is BaseActivity) { + activity.baseHandler.removeMessages(MainActivity.COUNTDOWN_SDK_AD) + } + } + + val onAdShowAction = { + sdkJumpBtn.visibility = View.VISIBLE + if (activity is BaseActivity) { + activity.baseHandler.sendEmptyMessageDelayed(MainActivity.COUNTDOWN_SDK_AD, 1000) + } + SensorsBridge.trackEvent("ThirdPartyAdShow", + "ad_source", thirdPartyAd.sourceName, + "ad_id", thirdPartyAd.slotId, + "ad_format", mSplashAd?.typeChinese ?: "", + "ad_placement", "光环启动", + "launch_type", if (isHotLaunch) "热启动" else "冷启动", + "ad_space_id", mSplashAd?.id ?: "", + "ad_space_name", mSplashAd?.name ?: "" + ) + } + val onAdClickAction = { + callback.invoke(true) + SensorsBridge.trackEvent("ThirdPartyAdClick", + "ad_source", thirdPartyAd.sourceName, + "ad_id", thirdPartyAd.slotId, + "ad_format", mSplashAd?.typeChinese ?: "", + "ad_placement", "光环启动", + "launch_type", if (isHotLaunch) "热启动" else "冷启动", + "ad_space_id", mSplashAd?.id ?: "", + "ad_space_name", mSplashAd?.name ?: "" + ) + } mCsjAdImpl?.requestSplashAd( activity, - slotId, + thirdPartyAd.slotId, adViewWidthInPx, adViewHeightInPx, adViewWidthInDp, adViewHeightInDp, startAdContainer, timeout, + onAdShowAction, + onAdClickAction, callback, ) } @@ -457,6 +490,7 @@ object AdDelegateHelper { adViewHeightInDp: Float, startAdContainer: ViewGroup, sdkStartAdContainer: ViewGroup, + sdkJumpBtn: TextView, adsViewGroup: FrameLayout, handler: BaseActivity.BaseHandler, isHotLaunch: Boolean, @@ -474,6 +508,7 @@ object AdDelegateHelper { adViewHeightInDp, startAdContainer, sdkStartAdContainer, + sdkJumpBtn, adsViewGroup, handler, isHotLaunch, @@ -621,9 +656,11 @@ object AdDelegateHelper { slotId: String, adContainerView: ViewGroup, expressViewWidth: Float, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit, callback: (isSuccess: Boolean) -> Unit, ) { - mCsjAdImpl?.requestFlowAd(fragment, adContainerView, slotId, expressViewWidth, callback) + mCsjAdImpl?.requestFlowAd(fragment, adContainerView, slotId, expressViewWidth, onAdShowAction, onAdClickAction, callback) } /** @@ -634,6 +671,8 @@ object AdDelegateHelper { containerView: ViewGroup, ad: AdConfig.ThirdPartyAd, expressViewWidthInDp: Float, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit, callback: (isSuccess: Boolean) -> Unit ) { @@ -656,6 +695,28 @@ object AdDelegateHelper { slotId, expressViewWidthInDp, expressViewHeightInDp, + onAdShowAction, + onAdClickAction, + callback + ) + } + + /** + * 获取第三方 全屏/插屏 广告 + */ + fun requestFullScreenAd( + fragment: Fragment, + ad: AdConfig.ThirdPartyAd, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit, + callback: (isSuccess: Boolean) -> Unit + ) { + val slotId = ad.slotId + mCsjAdImpl?.requestFullScreenAd( + fragment, + slotId, + onAdShowAction, + onAdClickAction, callback ) } diff --git a/app/src/main/java/com/gh/ad/LaunchAdImpl.kt b/app/src/main/java/com/gh/ad/LaunchAdImpl.kt index 9b56a9f1bd..2d7194a05e 100644 --- a/app/src/main/java/com/gh/ad/LaunchAdImpl.kt +++ b/app/src/main/java/com/gh/ad/LaunchAdImpl.kt @@ -3,42 +3,105 @@ package com.gh.ad import android.content.Context import android.view.View import android.view.ViewGroup - +import android.view.ViewStub import androidx.fragment.app.Fragment - import com.alibaba.android.arouter.facade.annotation.Route import com.gh.gamecenter.common.constant.Constants import com.gh.gamecenter.common.constant.RouteConsts import com.gh.gamecenter.common.provider.ILaunchAd +import com.gh.gamecenter.common.utils.SensorsBridge import com.gh.gamecenter.common.utils.goneIf import com.gh.gamecenter.core.utils.DisplayUtils import com.gh.gamecenter.core.utils.SPUtils +import com.gh.gamecenter.entity.AdConfig @Route(path = RouteConsts.provider.vaAd, name = "畅玩启动页广告") class LaunchAdImpl : ILaunchAd { override fun init(context: Context?) { } - override fun requestAd(fragment: Fragment, container: ViewGroup, maskView: View) { + override fun requestAd(fragment: Fragment, container: ViewGroup, maskView: View, topViewStub: ViewStub, bottomViewStub: ViewStub, adClickAction: () -> Unit): View { if (AdDelegateHelper.shouldShowHelperLaunchAd()) { val launchAd = AdDelegateHelper.vGameLaunchAd val showThirdPartyAd = launchAd?.displayRule?.adSource == AdDelegateHelper.AD_TYPE_SDK val thirdPartyAd = launchAd?.thirdPartyAd if (showThirdPartyAd && thirdPartyAd != null) { - AdDelegateHelper.requestThirdPartyBannerAd( - fragment, - container, - thirdPartyAd, - DisplayUtils.getScreenWidthInDp(fragment.requireActivity()), - ) { isSuccess -> - maskView.goneIf(!isSuccess) - if (isSuccess) { - SPUtils.setLong(Constants.SP_LAST_HELPER_LAUNCH_AD_SHOW_TIME, System.currentTimeMillis()) - } + val onAdShowAction = { + SensorsBridge.trackEvent("ThirdPartyAdShow", + "ad_source", thirdPartyAd.sourceName, + "ad_id", thirdPartyAd.slotId, + "ad_format", launchAd.typeChinese, + "ad_placement", AD_PLACEMENT, + "ad_space_id", launchAd.id, + "ad_space_name", launchAd.name + ) } + val onAdClickAction = { + SensorsBridge.trackEvent("ThirdPartyAdClick", + "ad_source", thirdPartyAd.sourceName, + "ad_id", thirdPartyAd.slotId, + "ad_format", launchAd.typeChinese, + "ad_placement", AD_PLACEMENT, + "ad_space_id", launchAd.id, + "ad_space_name", launchAd.name + ) + adClickAction.invoke() + } + + if (launchAd.type == AdConfig.TYPE_BANNER) { + requestBannerAd(fragment, container, maskView, thirdPartyAd, onAdShowAction, onAdClickAction) + return topViewStub.inflate() + } else if (launchAd.type == AdConfig.TYPE_INTERSTITIAL) { + requestFullScreenAd(fragment, thirdPartyAd, onAdShowAction, onAdClickAction) + return bottomViewStub.inflate() + } + } + } + return bottomViewStub.inflate() + } + + private fun requestBannerAd( + fragment: Fragment, + container: ViewGroup, + maskView: View, + thirdPartyAd: AdConfig.ThirdPartyAd, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit, + ) { + AdDelegateHelper.requestThirdPartyBannerAd( + fragment, + container, + thirdPartyAd, + DisplayUtils.getScreenWidthInDp(fragment.requireActivity()), + onAdShowAction, + onAdClickAction + ) { isSuccess -> + maskView.goneIf(!isSuccess) + if (isSuccess) { + SPUtils.setLong(Constants.SP_LAST_HELPER_LAUNCH_AD_SHOW_TIME, System.currentTimeMillis()) } } } + private fun requestFullScreenAd( + fragment: Fragment, + thirdPartyAd: AdConfig.ThirdPartyAd, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit + ) { + AdDelegateHelper.requestFullScreenAd( + fragment, + thirdPartyAd, + onAdShowAction, + onAdClickAction + ) { isSuccess -> + if (isSuccess) { + SPUtils.setLong(Constants.SP_LAST_HELPER_LAUNCH_AD_SHOW_TIME, System.currentTimeMillis()) + } + } + } + companion object { + private const val AD_PLACEMENT = "畅玩启动" + } } diff --git a/app/src/main/java/com/gh/gamecenter/MainActivity.java b/app/src/main/java/com/gh/gamecenter/MainActivity.java index d1c5d63be1..8e4af79e16 100644 --- a/app/src/main/java/com/gh/gamecenter/MainActivity.java +++ b/app/src/main/java/com/gh/gamecenter/MainActivity.java @@ -148,6 +148,8 @@ public class MainActivity extends BaseActivity { public static final String SHOW_AD = "show_ad"; public static final int COUNTDOWN_AD = 100; private int mCountdownMaxCount = 3; + public static final int COUNTDOWN_SDK_AD = 101; + public static final int COUNTDOWN_SDK_MAX_COUNT = 5; private int mCountdownCount = 0; private static final String CURRENT_PAGE = "current_page"; @@ -489,6 +491,7 @@ public class MainActivity extends BaseActivity { if (AdDelegateHelper.INSTANCE.shouldShowStartUpAd(false)) { ViewGroup startAdContainer = findViewById(R.id.startAdContainer); ViewGroup sdkStartAdContainer = findViewById(R.id.sdkStartAdContainer); + TextView sdkJumpBtn = findViewById(R.id.sdkJumpBtn); FrameLayout adsFl = findViewById(R.id.adsFl); View icpContainer = findViewById(R.id.sdkStartAdIcpContainer); if (icpContainer != null) { @@ -517,6 +520,7 @@ public class MainActivity extends BaseActivity { screenHeightInDp, startAdContainer, sdkStartAdContainer, + sdkJumpBtn, adsFl, (BaseHandler) mBaseHandler, false, @@ -536,13 +540,19 @@ public class MainActivity extends BaseActivity { @Override protected void handleMessage(Message msg) { super.handleMessage(msg); - if (msg.what == COUNTDOWN_AD) { + if (msg.what == COUNTDOWN_AD || msg.what == COUNTDOWN_SDK_AD) { mCountdownCount++; - if (mCountdownMaxCount < mCountdownCount) { + int maxCount; + if (msg.what == COUNTDOWN_AD) { + maxCount = mCountdownMaxCount; + } else { + maxCount = COUNTDOWN_SDK_MAX_COUNT; + } + if (maxCount < mCountdownCount) { AdDelegateHelper.INSTANCE.setShowingSplashAd(false); hideSplashAd(); - if (msg.obj instanceof StartupAdEntity) { + if (msg.what == COUNTDOWN_AD && msg.obj instanceof StartupAdEntity) { StartupAdEntity ad = (StartupAdEntity) msg.obj; LinkEntity linkEntity = ad.getJump(); SensorsBridge.trackEvent( @@ -555,14 +565,26 @@ public class MainActivity extends BaseActivity { linkEntity.getLink(), "link_text", linkEntity.getText()); + } else if (msg.what == COUNTDOWN_SDK_AD) { + SPUtils.setLong(Constants.SP_LAST_SPLASH_AD_SHOW_TIME, System.currentTimeMillis()); } } else { - TextView jumpBtn = findViewById(R.id.jumpBtn); - jumpBtn.setText(getString(R.string.splash_jump, mCountdownMaxCount - mCountdownCount)); - Message newMsg = Message.obtain(); - newMsg.what = COUNTDOWN_AD; - newMsg.obj = msg.obj; - mBaseHandler.sendMessageDelayed(newMsg, 1000); + if (msg.what == COUNTDOWN_AD) { + TextView jumpBtn = findViewById(R.id.jumpBtn); + if (jumpBtn != null) { + jumpBtn.setText(getString(R.string.splash_jump, maxCount - mCountdownCount)); + } + Message newMsg = Message.obtain(); + newMsg.what = COUNTDOWN_AD; + newMsg.obj = msg.obj; + mBaseHandler.sendMessageDelayed(newMsg, 1000); + } else { + TextView jumpBtn = findViewById(R.id.sdkJumpBtn); + if (jumpBtn != null) { + jumpBtn.setText(getString(R.string.splash_jump, maxCount - mCountdownCount)); + } + mBaseHandler.sendEmptyMessageDelayed(COUNTDOWN_SDK_AD, 1000); + } } } } @@ -600,7 +622,11 @@ public class MainActivity extends BaseActivity { ExtensionsKt.removeFromParent(startSdkAdContainer, true); AdDelegateHelper.INSTANCE.cancelSplashAd(this); } - + TextView jumpBtn = findViewById(R.id.sdkJumpBtn); + if (jumpBtn != null) { + jumpBtn.setVisibility(View.GONE); + ExtensionsKt.removeFromParent(jumpBtn, true); + } View startSdkAdIcpContainer = findViewById(R.id.sdkStartAdIcpContainer); if (startSdkAdIcpContainer != null) { startSdkAdIcpContainer.setVisibility(View.GONE); diff --git a/app/src/main/java/com/gh/gamecenter/SplashAdActivity.kt b/app/src/main/java/com/gh/gamecenter/SplashAdActivity.kt index 73dd151430..b6bd8e3bfb 100644 --- a/app/src/main/java/com/gh/gamecenter/SplashAdActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/SplashAdActivity.kt @@ -12,8 +12,10 @@ import com.gh.ad.AdDelegateHelper import com.gh.ad.AdDelegateHelper.requestSplashAd import com.gh.ad.AdDelegateHelper.shouldShowStartUpAd import com.gh.gamecenter.common.base.activity.BaseActivity +import com.gh.gamecenter.common.constant.Constants import com.gh.gamecenter.common.utils.dip2px import com.gh.gamecenter.core.utils.DisplayUtils +import com.gh.gamecenter.core.utils.SPUtils import java.util.* /** @@ -37,6 +39,7 @@ class SplashAdActivity : BaseActivity() { if (shouldShowStartUpAd(true)) { val startAdContainer = findViewById(R.id.startAdContainer) val sdkStartAdContainer = findViewById(R.id.sdkStartAdContainer) + val sdkJumpBtn = findViewById(R.id.sdkJumpBtn) val adsFl = findViewById(R.id.adsFl) val icpContainer = findViewById(R.id.sdkStartAdIcpContainer) @@ -58,6 +61,7 @@ class SplashAdActivity : BaseActivity() { screenHeightInDp, startAdContainer!!, sdkStartAdContainer!!, + sdkJumpBtn!!, adsFl!!, (mBaseHandler as BaseHandler), true @@ -81,15 +85,23 @@ class SplashAdActivity : BaseActivity() { override fun handleMessage(msg: Message) { super.handleMessage(msg) - if (msg.what == MainActivity.COUNTDOWN_AD) { + if (msg.what == MainActivity.COUNTDOWN_AD || msg.what == MainActivity.COUNTDOWN_SDK_AD) { mCountdownCount++ - if (COUNTDOWN_MAX_COUNT < mCountdownCount) { + val maxCount = if (msg.what == MainActivity.COUNTDOWN_AD) { + COUNTDOWN_MAX_COUNT + } else { + MainActivity.COUNTDOWN_SDK_MAX_COUNT + } + if (maxCount < mCountdownCount) { AdDelegateHelper.isShowingSplashAd = false + if (msg.what == MainActivity.COUNTDOWN_SDK_AD) { + SPUtils.setLong(Constants.SP_LAST_SPLASH_AD_SHOW_TIME, System.currentTimeMillis()) + } finishActivity() } else { - val jumpBtn = findViewById(R.id.jumpBtn) - jumpBtn.text = getString(R.string.splash_jump, COUNTDOWN_MAX_COUNT - mCountdownCount) - mBaseHandler.sendEmptyMessageDelayed(MainActivity.COUNTDOWN_AD, 1000) + val jumpBtn = findViewById(if (msg.what == MainActivity.COUNTDOWN_AD) R.id.jumpBtn else R.id.sdkJumpBtn) + jumpBtn?.text = getString(R.string.splash_jump, maxCount - mCountdownCount) + mBaseHandler.sendEmptyMessageDelayed(msg.what, 1000) } } } diff --git a/app/src/main/java/com/gh/gamecenter/download/DownloadFragment.kt b/app/src/main/java/com/gh/gamecenter/download/DownloadFragment.kt index 8cb857f4a4..19696baf85 100644 --- a/app/src/main/java/com/gh/gamecenter/download/DownloadFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/download/DownloadFragment.kt @@ -160,7 +160,7 @@ class DownloadFragment : BaseFragment_TabLayout() { val ownerAd = downloadManagerAd?.ownerAd val showOnFailed = downloadManagerAd?.displayRule?.onFailedAction == "show" if ((showThirdPartyAd && thirdPartyAd != null) || (!showThirdPartyAd && thirdPartyAd != null && ownerAd == null)) { - initThirdPartyAd(thirdPartyAd) { isSuccess -> + initThirdPartyAd(downloadManagerAd, thirdPartyAd) { isSuccess -> mBinding.maskView.goneIf(!isSuccess) if (!isSuccess && ownerAd != null && showOnFailed) { mSlideInterval = ownerAd.adSource?.sliderInterval ?: -1 @@ -182,12 +182,34 @@ class DownloadFragment : BaseFragment_TabLayout() { } } - private fun initThirdPartyAd(thirdPartyAd: AdConfig.ThirdPartyAd, callback: (isSuccess: Boolean) -> Unit) { + private fun initThirdPartyAd(adConfig: AdConfig?, thirdPartyAd: AdConfig.ThirdPartyAd, callback: (isSuccess: Boolean) -> Unit) { + val onAdShowAction = { + SensorsBridge.trackEvent("ThirdPartyAdShow", + "ad_source", thirdPartyAd.sourceName, + "ad_id", thirdPartyAd.slotId, + "ad_format", adConfig?.typeChinese ?: "", + "ad_placement", "下载管理", + "ad_space_id", adConfig?.id ?: "", + "ad_space_name", adConfig?.name ?: "" + ) + } + val onAdClickAction = { + SensorsBridge.trackEvent("ThirdPartyAdClick", + "ad_source", thirdPartyAd.sourceName, + "ad_id", thirdPartyAd.slotId, + "ad_format", adConfig?.typeChinese ?: "", + "ad_placement", "下载管理", + "ad_space_id", adConfig?.id ?: "", + "ad_space_name", adConfig?.name ?: "" + ) + } AdDelegateHelper.requestThirdPartyBannerAd( this, mBinding.adContainer, thirdPartyAd, DisplayUtils.getScreenWidthInDp(requireActivity()), + onAdShowAction, + onAdClickAction, callback ) } @@ -226,7 +248,7 @@ class DownloadFragment : BaseFragment_TabLayout() { if (it.isNullOrEmpty() && adConfig.displayRule.adSource == AdDelegateHelper.AD_TYPE_OWNER && adConfig.displayRule.onFailedAction == "show" && adConfig.thirdPartyAd != null) { // 自有广告游戏为空时,显示第三方广告 - initThirdPartyAd(adConfig.thirdPartyAd) { isSuccess -> + initThirdPartyAd(adConfig, adConfig.thirdPartyAd) { isSuccess -> mBinding.maskView.goneIf(!isSuccess) if (isSuccess) { SPUtils.setLong(Constants.SP_LAST_DOWNLOAD_MANAGER_AD_SHOW_TIME, System.currentTimeMillis()) diff --git a/app/src/main/java/com/gh/gamecenter/entity/AdConfig.kt b/app/src/main/java/com/gh/gamecenter/entity/AdConfig.kt index 873be69cf8..5ff1405f7e 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/AdConfig.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/AdConfig.kt @@ -6,7 +6,7 @@ class AdConfig( @SerializedName("_id") val id: String = "", val name: String, - val location: String, // 广告插入位置。光环启动:halo_launch 下载管理:download_manager 游戏搜索:game_search 助手启动:helper_launch + val location: String, // 广告插入位置。光环启动:halo_launch 下载管理:download_manager 游戏搜索:game_search 畅玩启动:helper_launch val type: String, // 广告位类型。开屏广告:launch 信息流广告:native banner 广告:banner 插屏广告:interstitial val position: Int, // 定位,不存在的时候返回:-1 @SerializedName("display_rules") @@ -18,12 +18,19 @@ class AdConfig( @SerializedName("owner_ads") val ownerAd: OwnerAdEntity? = null, ) { + companion object { + const val TYPE_LAUNCH = "launch" + const val TYPE_NATIVE = "native" + const val TYPE_BANNER = "banner" + const val TYPE_INTERSTITIAL = "interstitial" + } + val typeChinese get() = when (type) { - "launch" -> "开屏" - "native" -> "信息流" - "banner" -> "banner" - "interstitial" -> "插屏" + TYPE_LAUNCH -> "开屏" + TYPE_NATIVE -> "信息流" + TYPE_BANNER -> "banner" + TYPE_INTERSTITIAL -> "插屏" else -> "" } diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchGameResultAdapter.kt b/app/src/main/java/com/gh/gamecenter/search/SearchGameResultAdapter.kt index 38424c001e..50abfbc866 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameResultAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameResultAdapter.kt @@ -68,6 +68,12 @@ class SearchGameResultAdapter( val positionAndPackageMap = HashMap() + private val adIdSet = hashSetOf() // 记录展示过的广告id + + fun clearAdIdSet() { + adIdSet.clear() + } + override fun setListData(updateData: MutableList?) { exposureEventArray = SparseArray(updateData?.size ?: 0) // 记录游戏位置 @@ -216,6 +222,7 @@ class SearchGameResultAdapter( is SearchGameAdItemViewHolder -> { val adEntity = mEntityList[position].ad + val adConfig = mEntityList[position].adConfig val slotId = adEntity?.slotId ?: "" val adContainer = holder.binding.adContainer val screenWidthInDp = DisplayUtils.getScreenWidthInDp(fragment.activity) @@ -224,7 +231,36 @@ class SearchGameResultAdapter( // 广告 slotId 没有变,不管它 } else { adContainer.tag = slotId - AdDelegateHelper.requestThirdPartyFlowAd(fragment, slotId, adContainer, screenWidthInDp) { + val onAdShowAction: () -> Unit = { + if (!adIdSet.contains(adConfig?.id)) { + SensorsBridge.trackEvent("ThirdPartyAdShow", + json { + "ad_source" to adEntity?.sourceName + "ad_id" to slotId + "ad_format" to adConfig?.typeChinese + "ad_placement" to "搜索结果" + "ad_space_id" to adConfig?.id + "ad_space_name" to adConfig?.name + "position" to adConfig?.position + } + ) + } + adIdSet.add(adConfig?.id ?: "") + } + val onAdClickAction = { + SensorsBridge.trackEvent("ThirdPartyAdClick", + json { + "ad_source" to adEntity?.sourceName + "ad_id" to slotId + "ad_format" to adConfig?.typeChinese + "ad_placement" to "搜索结果" + "ad_space_id" to adConfig?.id + "ad_space_name" to adConfig?.name + "position" to adConfig?.position + } + ) + } + AdDelegateHelper.requestThirdPartyFlowAd(fragment, slotId, adContainer, screenWidthInDp, onAdShowAction, onAdClickAction) { } } diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchGameResultFragment.kt b/app/src/main/java/com/gh/gamecenter/search/SearchGameResultFragment.kt index 1f06f17227..2a9186a521 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameResultFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameResultFragment.kt @@ -354,6 +354,7 @@ open class SearchGameResultFragment : ListFragment ) { thirdPartyAdList.forEach { - decoratedItemDataList.add(it.position - 1, SearchItemData(ad = it.thirdPartyAd)) + decoratedItemDataList.add(it.position - 1, SearchItemData(ad = it.thirdPartyAd, adConfig = it)) SPUtils.setLong(Constants.SP_LAST_GAME_SEARCH_AD_SHOW_TIME + it.position, System.currentTimeMillis()) } postResultList(decoratedItemDataList, list) @@ -209,7 +209,7 @@ class SearchGameResultViewModel( if ((showThirdPartyAd && adConfig?.thirdPartyAd != null) || (showOwnerAd && adConfig?.ownerAd == null && adConfig?.thirdPartyAd != null && showOnFailed) ) { - decoratedItemDataList.add(position - 1, SearchItemData(ad = adConfig.thirdPartyAd)) + decoratedItemDataList.add(position - 1, SearchItemData(ad = adConfig.thirdPartyAd, adConfig = adConfig)) SPUtils.setLong( Constants.SP_LAST_GAME_SEARCH_AD_SHOW_TIME + adConfig.position, System.currentTimeMillis() @@ -254,7 +254,7 @@ class SearchGameResultViewModel( ) } else if (showOnFailed && adConfig.thirdPartyAd != null) { // 自有广告为空时,显示第三方广告 - decoratedItemDataList.add(position - 1, SearchItemData(ad = adConfig.thirdPartyAd)) + decoratedItemDataList.add(position - 1, SearchItemData(ad = adConfig.thirdPartyAd, adConfig = adConfig)) SPUtils.setLong( Constants.SP_LAST_GAME_SEARCH_AD_SHOW_TIME + adConfig.position, System.currentTimeMillis() diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index ca2430b2d1..e221931e72 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -72,6 +72,22 @@ + + + android:layout_height="match_parent" + xmlns:tools="http://schemas.android.com/tools"> @@ -12,6 +13,22 @@ + + + + \ No newline at end of file diff --git a/feature/csj_ad/src/main/java/com/gh/gamecenter/csj/CsjAdHelper.kt b/feature/csj_ad/src/main/java/com/gh/gamecenter/csj/CsjAdHelper.kt index 855cef4fbf..a78a5ac25b 100644 --- a/feature/csj_ad/src/main/java/com/gh/gamecenter/csj/CsjAdHelper.kt +++ b/feature/csj_ad/src/main/java/com/gh/gamecenter/csj/CsjAdHelper.kt @@ -6,6 +6,8 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import com.bykv.vk.openvk.* +import com.bykv.vk.openvk.TTFullVideoObject.FullVideoVsInteractionListener +import com.bykv.vk.openvk.TTVfNative.FullScreenVideoAdListener import com.bykv.vk.openvk.TTVfNative.NtExpressVfListener import com.bykv.vk.openvk.stub.server.MainServerManager import com.gh.gamecenter.common.utils.PackageFlavorHelper @@ -104,6 +106,8 @@ object CsjAdHelper { adViewHeightInDp: Float, startAdContainer: ViewGroup, timeout: Int, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit, callback: (isSuccess: Boolean) -> Unit, ) { val mTTVfNative = TTVfSdk.getVfManager().createVfNative(activity) @@ -142,14 +146,16 @@ object CsjAdHelper { } if (!activity.isFinishing) { startAdContainer.removeAllViews() + p0.hideSkipButton() p0.setSplashAdListener(object : CSJSplashAd.SplashAdListener { override fun onSplashAdShow(p0: CSJSplashAd?) { Utils.log(TAG, "显示开屏广告") + onAdShowAction.invoke() } override fun onSplashAdClick(p0: CSJSplashAd?) { Utils.log(TAG, "点击开屏广告") - callback.invoke(true) + onAdClickAction.invoke() } override fun onSplashAdClose(ad: CSJSplashAd?, closeType: Int) { @@ -183,6 +189,8 @@ object CsjAdHelper { containerView: ViewGroup, slotId: String, expressViewAcceptedSize: Float, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit, callback: (isSuccess: Boolean) -> Unit ) { val isBoundedActivityValid = @@ -221,12 +229,13 @@ object CsjAdHelper { // 广告点击回调 override fun onClicked(view: View, type: Int) { Utils.log(TAG, "requestFlowAd 广告点击 $type") + onAdClickAction.invoke() } // 广告展示回调 override fun onShow(view: View, type: Int) { Utils.log(TAG, "requestFlowAd 广告展示") - + onAdShowAction.invoke() callback.invoke(true) } @@ -273,6 +282,8 @@ object CsjAdHelper { slotId: String, expressViewWidthInDp: Float, expressViewHeightInDp: Float, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit, callback: (isSuccess: Boolean) -> Unit ) { @@ -309,11 +320,13 @@ object CsjAdHelper { // 广告点击回调 override fun onClicked(view: View, type: Int) { Utils.log(TAG, "banner 广告点击 $type") + onAdClickAction.invoke() } // 广告展示回调 override fun onShow(view: View, type: Int) { Utils.log(TAG, "banner 广告展示 $type") + onAdShowAction.invoke() } // 广告渲染失败回调 @@ -356,4 +369,75 @@ object CsjAdHelper { }) } + fun requestFullScreenAd( + fragment: Fragment, + slotId: String, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit, + callback: (isSuccess: Boolean) -> Unit + ) { + // 创建TTVfNative对象,createAdNative(Context context) context需要传入Activity对象 + val mTTVfNative = TTVfSdk.getVfManager().createVfNative(fragment.activity) + + val isBoundedActivityValid = + fragment.isAdded && fragment.activity != null && !fragment.requireActivity().isFinishing + + if (!isBoundedActivityValid) { + Utils.log(TAG, "requestFullScreenAd but activity is invalid.") + return + } + + val adSlot = VfSlot.Builder() + .setCodeId(slotId) // 广告位id + .setSupportDeepLink(true) + .setAdCount(1) // 请求广告数量为1 + .setAdLoadType(TTAdLoadType.LOAD) // 推荐使用,用于标注此次的广告请求用途为预加载(当做缓存)还是实时加载,方便后续为开发者优化相关策略 + .build() + + val fullVideoVsInteractionListener = object : FullVideoVsInteractionListener { + override fun onShow() { + Utils.log(TAG, "全屏/插屏 广告展示") + onAdShowAction.invoke() + callback.invoke(true) + } + + override fun onVideoBarClick() { + Utils.log(TAG, "全屏/插屏 广告下载bar点击") + onAdClickAction.invoke() + } + + override fun onClose() { + Utils.log(TAG, "全屏/插屏 广告关闭") + } + + override fun onVideoComplete() { + Utils.log(TAG, "全屏/插屏 视频播放完成") + } + + override fun onSkippedVideo() { + Utils.log(TAG, "全屏/插屏 跳过视频播放") + } + } + + mTTVfNative.loadFullVideoVs(adSlot, object : FullScreenVideoAdListener { + override fun onError(code: Int, message: String?) { + Utils.log(TAG, "全屏/插屏 $code 请求广告失败 $message") + callback.invoke(false) + } + + override fun onFullVideoVsLoad(ad: TTFullVideoObject) { + Utils.log(TAG, "全屏/插屏 广告物料加载完成 $ad") + } + + override fun onFullVideoCached() { + // 已废弃 + } + + override fun onFullVideoCached(ad: TTFullVideoObject) { + Utils.log(TAG, "全屏/插屏 广告视频/图片加载完成 $ad") + ad.setFullScreenVideoAdInteractionListener(fullVideoVsInteractionListener) + ad.showFullVideoVs(fragment.activity) + } + }) + } } \ No newline at end of file diff --git a/feature/csj_ad/src/main/java/com/gh/gamecenter/csj/CsjAdProviderImpl.kt b/feature/csj_ad/src/main/java/com/gh/gamecenter/csj/CsjAdProviderImpl.kt index 266b7ad436..9d9dec6772 100644 --- a/feature/csj_ad/src/main/java/com/gh/gamecenter/csj/CsjAdProviderImpl.kt +++ b/feature/csj_ad/src/main/java/com/gh/gamecenter/csj/CsjAdProviderImpl.kt @@ -23,6 +23,8 @@ class CsjAdProviderImpl : ICsjAdProvider { adViewHeightInDp: Float, startAdContainer: ViewGroup, timeout: Int, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit, callback: (isSuccess: Boolean) -> Unit, ) { CsjAdHelper.requestSplashAd( @@ -34,6 +36,8 @@ class CsjAdProviderImpl : ICsjAdProvider { adViewHeightInDp, startAdContainer, timeout, + onAdShowAction, + onAdClickAction, callback, ) } @@ -43,9 +47,11 @@ class CsjAdProviderImpl : ICsjAdProvider { containerView: ViewGroup, slotId: String, expressViewAcceptedSize: Float, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit, callback: (isSuccess: Boolean) -> Unit, ) { - CsjAdHelper.requestFlowAd(fragment, containerView, slotId, expressViewAcceptedSize, callback) + CsjAdHelper.requestFlowAd(fragment, containerView, slotId, expressViewAcceptedSize, onAdShowAction, onAdClickAction, callback) } override fun requestBannerAd( @@ -54,9 +60,21 @@ class CsjAdProviderImpl : ICsjAdProvider { slotId: String, expressViewWidthInDp: Float, expressViewHeightInDp: Float, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit, callback: (isSuccess: Boolean) -> Unit ) { - CsjAdHelper.requestBannerAd(fragment, containerView, slotId, expressViewWidthInDp, expressViewHeightInDp, callback) + CsjAdHelper.requestBannerAd(fragment, containerView, slotId, expressViewWidthInDp, expressViewHeightInDp, onAdShowAction, onAdClickAction, callback) + } + + override fun requestFullScreenAd( + fragment: Fragment, + slotId: String, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit, + callback: (isSuccess: Boolean) -> Unit + ) { + CsjAdHelper.requestFullScreenAd(fragment, slotId, onAdShowAction, onAdClickAction, callback) } override fun updateThemeStatus(context: Context, isDarkMode: Boolean) { diff --git a/feature/csj_ad/src/main/java/com/gh/gamecenter/csj/CustomMainServerManager.kt b/feature/csj_ad/src/main/java/com/gh/gamecenter/csj/CustomMainServerManager.kt new file mode 100644 index 0000000000..d3fc4e6f9f --- /dev/null +++ b/feature/csj_ad/src/main/java/com/gh/gamecenter/csj/CustomMainServerManager.kt @@ -0,0 +1,6 @@ +package com.gh.gamecenter.csj + +import com.bytedance.pangle.servermanager.AbsServerManager + +// 自定义MainServerManager(移除MainServerManager的onCreate自动初始化部分) +class CustomMainServerManager: AbsServerManager() \ No newline at end of file diff --git a/module_common/src/main/java/com/gh/gamecenter/common/base/activity/BaseActivity.java b/module_common/src/main/java/com/gh/gamecenter/common/base/activity/BaseActivity.java index e064c5f5e4..0cb9ab63c2 100644 --- a/module_common/src/main/java/com/gh/gamecenter/common/base/activity/BaseActivity.java +++ b/module_common/src/main/java/com/gh/gamecenter/common/base/activity/BaseActivity.java @@ -133,6 +133,10 @@ public abstract class BaseActivity extends BaseAppCompatActivity implements IBus } } + public BaseHandler getBaseHandler() { + return (BaseHandler) mBaseHandler; + } + protected void handleMessage(Message msg) { } diff --git a/module_common/src/main/java/com/gh/gamecenter/common/provider/ILaunchAd.java b/module_common/src/main/java/com/gh/gamecenter/common/provider/ILaunchAd.java deleted file mode 100644 index 6b8db8855c..0000000000 --- a/module_common/src/main/java/com/gh/gamecenter/common/provider/ILaunchAd.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.gh.gamecenter.common.provider; - -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; - -import com.alibaba.android.arouter.facade.template.IProvider; - -public interface ILaunchAd extends IProvider { - void requestAd(@NonNull Fragment fragment, @NonNull ViewGroup container, @NonNull View maskView); -} diff --git a/module_common/src/main/java/com/gh/gamecenter/common/provider/ILaunchAd.kt b/module_common/src/main/java/com/gh/gamecenter/common/provider/ILaunchAd.kt new file mode 100644 index 0000000000..03dc6f6dfe --- /dev/null +++ b/module_common/src/main/java/com/gh/gamecenter/common/provider/ILaunchAd.kt @@ -0,0 +1,19 @@ +package com.gh.gamecenter.common.provider + +import android.view.View +import android.view.ViewGroup +import android.view.ViewStub +import androidx.fragment.app.Fragment +import com.alibaba.android.arouter.facade.template.IProvider + +interface ILaunchAd : IProvider { + fun requestAd( + fragment: Fragment, + container: ViewGroup, + maskView: View, + topViewStub: ViewStub, + bottomViewStub: ViewStub, + adClickAction: () -> Unit, + ): View + +} \ No newline at end of file diff --git a/module_core/src/main/java/com/gh/gamecenter/core/provider/ICsjAdProvider.kt b/module_core/src/main/java/com/gh/gamecenter/core/provider/ICsjAdProvider.kt index 39db26edad..a8e5889bc5 100644 --- a/module_core/src/main/java/com/gh/gamecenter/core/provider/ICsjAdProvider.kt +++ b/module_core/src/main/java/com/gh/gamecenter/core/provider/ICsjAdProvider.kt @@ -19,6 +19,8 @@ interface ICsjAdProvider : IProvider { adViewHeightInDp: Float, startAdContainer: ViewGroup, timeout: Int, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit, callback: (isSuccess: Boolean) -> Unit ) @@ -27,6 +29,8 @@ interface ICsjAdProvider : IProvider { containerView: ViewGroup, slotId: String, expressViewAcceptedSize: Float, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit, callback: (isSuccess: Boolean) -> Unit ) @@ -36,6 +40,16 @@ interface ICsjAdProvider : IProvider { slotId: String, expressViewWidthInDp: Float, expressViewHeightInDp: Float, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit, + callback: (isSuccess: Boolean) -> Unit + ) + + fun requestFullScreenAd( + fragment: Fragment, + slotId: String, + onAdShowAction: () -> Unit, + onAdClickAction: () -> Unit, callback: (isSuccess: Boolean) -> Unit ) diff --git a/vasdk b/vasdk index 41581800a7..d6c44eb700 160000 --- a/vasdk +++ b/vasdk @@ -1 +1 @@ -Subproject commit 41581800a7d5346d6ee8a7b9ce101faa1c424c39 +Subproject commit d6c44eb7001602addbc9614f5b1d1e1b802f01dc