From 08c7dd3ccce5c590b0ef35eb5ccd7cb9b99a0156 Mon Sep 17 00:00:00 2001 From: ocean <503259349@qq.com> Date: Fri, 14 Jun 2024 18:50:50 +0800 Subject: [PATCH] update --- app/build.gradle.kts | 2 +- app/src/main/java/melody/offline/music/App.kt | 3 + .../offline/music/activity/LaunchActivity.kt | 17 +- .../offline/music/activity/MainActivity.kt | 16 +- .../music/activity/MoLikedSongsActivity.kt | 4 + .../music/activity/MoOfflineSongsActivity.kt | 4 + .../music/activity/MoPlayDetailsActivity.kt | 26 ++ .../melody/offline/music/ads/AdPlacement.kt | 8 + .../melody/offline/music/ads/LolAdWrapper.kt | 76 +++- .../offline/music/firebase/Constants.kt | 353 ++++++++++++++++++ .../offline/music/fragment/MoMeFragment.kt | 18 +- .../offline/music/fragment/SearchFragment.kt | 21 +- .../java/melody/offline/music/sp/AppStore.kt | 38 +- .../melody/offline/music/util/AnalysisUtil.kt | 113 +++++- .../res/layout/ad_layout_admob_banner.xml | 89 +++++ .../res/layout/ad_layout_admob_result.xml | 91 +++++ .../main/res/layout/ad_layout_max_banner.xml | 115 ++++++ .../main/res/layout/ad_layout_max_result.xml | 109 ++++++ app/src/main/res/layout/fragment_mo_me.xml | 15 +- 19 files changed, 1049 insertions(+), 69 deletions(-) create mode 100644 app/src/main/res/layout/ad_layout_admob_banner.xml create mode 100644 app/src/main/res/layout/ad_layout_admob_result.xml create mode 100644 app/src/main/res/layout/ad_layout_max_banner.xml create mode 100644 app/src/main/res/layout/ad_layout_max_result.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index cc7a965..e574cd7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -61,7 +61,7 @@ dependencies { implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar")))) implementation("androidx.core:core-ktx:1.13.1") implementation("androidx.appcompat:appcompat:1.7.0") - implementation("com.google.android.material:material:1.12.0") + implementation("com.google.android.material:material:1.11.0") implementation("androidx.constraintlayout:constraintlayout:2.1.4") implementation("androidx.media3:media3-session:1.3.1") implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.2") diff --git a/app/src/main/java/melody/offline/music/App.kt b/app/src/main/java/melody/offline/music/App.kt index 82b1930..2902674 100644 --- a/app/src/main/java/melody/offline/music/App.kt +++ b/app/src/main/java/melody/offline/music/App.kt @@ -33,6 +33,7 @@ import melody.offline.music.util.AppLifecycleHandler import java.io.BufferedReader import java.io.InputStreamReader import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicLong @OptIn(UnstableApi::class) class App : Application() { @@ -118,6 +119,8 @@ class App : Application() { var isAdShowing: AtomicBoolean = AtomicBoolean(false)//是否正在广告界面 + var lastAdDisplayTime: AtomicLong = AtomicLong(0L)//上次广告展示的时间 + override fun onCreate() { super.onCreate() AnalysisUtil.logEvent(AnalysisUtil.USER_LAUNCH) diff --git a/app/src/main/java/melody/offline/music/activity/LaunchActivity.kt b/app/src/main/java/melody/offline/music/activity/LaunchActivity.kt index 74fef44..4ed45d4 100644 --- a/app/src/main/java/melody/offline/music/activity/LaunchActivity.kt +++ b/app/src/main/java/melody/offline/music/activity/LaunchActivity.kt @@ -87,23 +87,27 @@ class LaunchActivity : MoBaseActivity() { } private fun toMainActivity() { - if (!withPermission()) { - startActivity(Intent(this, MainActivity::class.java)) - } else { +// if (!withPermission()) { +// startActivity(Intent(this, MainActivity::class.java)) +// } else { startActivity(Intent(this, PrimaryActivity::class.java)) - } +// } AnalysisUtil.logEvent(AnalysisUtil.LAUNCH_PV) finish() } private fun loadAd() { - LolAdWrapper.shared.loadAd(this, + LolAdWrapper.shared.loadAd( + this, AdPlacement.INST_SPLASH, object : LolAdWrapper.LoLLoadListener { override fun loadFailed(error: LolLoadError?) { handler.sendEmptyMessage(MSG_LOAD_AD_FAIL) } }) + + LolAdWrapper.shared.loadAdIfNotCached(this, AdPlacement.INST_BACKUP_ADS) + LolAdWrapper.shared.loadAdIfNotCached(this, AdPlacement.INST_INTO_PLAY) } private fun adCanShow(): Boolean { @@ -111,7 +115,8 @@ class LaunchActivity : MoBaseActivity() { } private fun showAd() { - LolAdWrapper.shared.showAdIfCached(this, + LolAdWrapper.shared.showAdIfCached( + this, AdPlacement.INST_SPLASH, object : LolAdWrapper.LolShowListener { override fun closed() { diff --git a/app/src/main/java/melody/offline/music/activity/MainActivity.kt b/app/src/main/java/melody/offline/music/activity/MainActivity.kt index b2cf88d..1c3aee1 100644 --- a/app/src/main/java/melody/offline/music/activity/MainActivity.kt +++ b/app/src/main/java/melody/offline/music/activity/MainActivity.kt @@ -13,6 +13,8 @@ import androidx.media3.common.Player import com.bumptech.glide.Glide import com.gyf.immersionbar.ktx.immersionBar import melody.offline.music.R +import melody.offline.music.ads.AdPlacement +import melody.offline.music.ads.LolAdWrapper import melody.offline.music.bean.Audio import melody.offline.music.databinding.ActivityMainBinding import melody.offline.music.fragment.HomeFragment @@ -31,17 +33,9 @@ class MainActivity : BaseActivity() { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) -// initImmersionBar() initView() } - private fun initImmersionBar() { - immersionBar { - statusBarDarkFont(false) - statusBarView(binding.view) - } - } - private fun initView() { initClick() initFragment() @@ -49,8 +43,12 @@ class MainActivity : BaseActivity() { override fun onResume() { super.onResume() - val currentPlayer = LocalMediaControllerManager.getController() + LolAdWrapper.shared.loadAdIfNotCached(this, AdPlacement.INST_CUTTING_SONG) + LolAdWrapper.shared.loadAdIfNotCached(this, AdPlacement.INST_DOWNLOAD) + LolAdWrapper.shared.loadAdIfNotCached(this, AdPlacement.INST_SEARCH) + LolAdWrapper.shared.loadAdIfNotCached(this, AdPlacement.INST_ME_PAGE_LIST) + val currentPlayer = LocalMediaControllerManager.getController() if (melody.offline.music.App.currentPlayingAudio == null) { binding.playingStatusLayout.visibility = View.GONE } else { diff --git a/app/src/main/java/melody/offline/music/activity/MoLikedSongsActivity.kt b/app/src/main/java/melody/offline/music/activity/MoLikedSongsActivity.kt index beba76f..1566640 100644 --- a/app/src/main/java/melody/offline/music/activity/MoLikedSongsActivity.kt +++ b/app/src/main/java/melody/offline/music/activity/MoLikedSongsActivity.kt @@ -9,6 +9,8 @@ import kotlinx.coroutines.isActive import kotlinx.coroutines.selects.select import melody.offline.music.App import melody.offline.music.adapter.LikedSongsAdapter +import melody.offline.music.ads.AdPlacement +import melody.offline.music.ads.LolAdWrapper import melody.offline.music.bean.FavoriteBean import melody.offline.music.databinding.ActivityLikedSongsBinding @@ -28,9 +30,11 @@ class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavorites override suspend fun main() { binding = ActivityLikedSongsBinding.inflate(layoutInflater) setContentView(binding.root) + LolAdWrapper.shared.showAdTiming(this, AdPlacement.INST_ME_PAGE_LIST) initImmersionBar() initView() initAdapter() + LolAdWrapper.shared.loadAdIfNotCached(this, AdPlacement.INST_ME_PAGE_LIST) initData() onReceive() } diff --git a/app/src/main/java/melody/offline/music/activity/MoOfflineSongsActivity.kt b/app/src/main/java/melody/offline/music/activity/MoOfflineSongsActivity.kt index 9491264..ef0d920 100644 --- a/app/src/main/java/melody/offline/music/activity/MoOfflineSongsActivity.kt +++ b/app/src/main/java/melody/offline/music/activity/MoOfflineSongsActivity.kt @@ -9,6 +9,8 @@ import kotlinx.coroutines.isActive import kotlinx.coroutines.selects.select import melody.offline.music.App import melody.offline.music.adapter.OfflineSongsAdapter +import melody.offline.music.ads.AdPlacement +import melody.offline.music.ads.LolAdWrapper import melody.offline.music.bean.OfflineBean import melody.offline.music.databinding.ActivityOfflineSongsBinding @@ -26,9 +28,11 @@ class MoOfflineSongsActivity : MoBaseActivity() { override suspend fun main() { binding = ActivityOfflineSongsBinding.inflate(layoutInflater) setContentView(binding.root) + LolAdWrapper.shared.showAdTiming(this, AdPlacement.INST_ME_PAGE_LIST) initImmersionBar() initView() initAdapter() + LolAdWrapper.shared.loadAdIfNotCached(this, AdPlacement.INST_ME_PAGE_LIST) initData() onReceive() } diff --git a/app/src/main/java/melody/offline/music/activity/MoPlayDetailsActivity.kt b/app/src/main/java/melody/offline/music/activity/MoPlayDetailsActivity.kt index e379551..bd7a225 100644 --- a/app/src/main/java/melody/offline/music/activity/MoPlayDetailsActivity.kt +++ b/app/src/main/java/melody/offline/music/activity/MoPlayDetailsActivity.kt @@ -43,6 +43,8 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.selects.select import org.json.JSONObject import melody.offline.music.App +import melody.offline.music.ads.AdPlacement +import melody.offline.music.ads.LolAdWrapper import melody.offline.music.util.AnalysisUtil @OptIn(UnstableApi::class) @@ -86,6 +88,7 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { override suspend fun main() { binding = ActivityMoPlayDetailsBinding.inflate(layoutInflater) setContentView(binding.root) + showAD() initImmersionBar() initClick() initPlayerListener() @@ -180,6 +183,7 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { params ) } + loadAd() initDownloadFlow() onReceive() } @@ -237,6 +241,11 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { } is Request.OnDownload -> { + LolAdWrapper.shared.showAdTiming( + this@MoPlayDetailsActivity, + AdPlacement.INST_DOWNLOAD + ) + insertOfflineData(it.mediaItem) val jsonObject = JSONObject() jsonObject.put( @@ -250,6 +259,11 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { ) ) AnalysisUtil.logEvent(AnalysisUtil.PLAYER_B_DOWNLOAD_CLICK, songMap) + + LolAdWrapper.shared.loadAdIfNotCached( + this@MoPlayDetailsActivity, + AdPlacement.INST_DOWNLOAD + ) } is Request.UpdateFavorite -> { @@ -488,6 +502,7 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { } } binding.playSkipBackBtn.setOnClickListener { + LolAdWrapper.shared.showAdTiming(this, AdPlacement.INST_CUTTING_SONG) if (meController != null) { meController.seekToPreviousMediaItem() updateProgressUi() @@ -498,8 +513,10 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { meController.play() } } + LolAdWrapper.shared.loadAdIfNotCached(this, AdPlacement.INST_CUTTING_SONG) } binding.playSkipForwardBtn.setOnClickListener { + LolAdWrapper.shared.showAdTiming(this, AdPlacement.INST_CUTTING_SONG) if (meController != null) { meController.seekToNextMediaItem() updateProgressUi() @@ -510,6 +527,7 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { meController.play() } } + LolAdWrapper.shared.loadAdIfNotCached(this, AdPlacement.INST_CUTTING_SONG) } binding.listLayoutBtn.setOnClickListener { toggleBottomLayout() @@ -876,4 +894,12 @@ class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener { binding.bottomLayout.startAnimation(slideDownAnimation) binding.bottomLayout.visibility = View.GONE } + + private fun loadAd() { + LolAdWrapper.shared.loadAdIfNotCached(this, AdPlacement.INST_INTO_PLAY) + } + + private fun showAD() { + LolAdWrapper.shared.showAdTiming(this, AdPlacement.INST_INTO_PLAY) + } } \ No newline at end of file diff --git a/app/src/main/java/melody/offline/music/ads/AdPlacement.kt b/app/src/main/java/melody/offline/music/ads/AdPlacement.kt index c37ff99..3c67990 100644 --- a/app/src/main/java/melody/offline/music/ads/AdPlacement.kt +++ b/app/src/main/java/melody/offline/music/ads/AdPlacement.kt @@ -2,4 +2,12 @@ package melody.offline.music.ads object AdPlacement { const val INST_SPLASH = "inst_splash"//启动页广告 + const val INST_SEARCH = "inst_search"//搜索广告 + const val NATIVE_SEARCH = "native_search"//搜索原生 + const val INST_INTO_PLAY = "inst_into_play"//进入播放 + const val INST_CUTTING_SONG = "inst_cutting_song"//主动切歌 + const val INST_DOWNLOAD = "inst_download"//下载歌曲 + const val INST_ME_PAGE_LIST = "inst_me_page_list"//我的界面的内容跳转 + const val NATIVE_ME_PAGE_LIST = "native_me_page_list"//我的界面的内容原生 + const val INST_BACKUP_ADS = "inst_backup_ads" } \ No newline at end of file diff --git a/app/src/main/java/melody/offline/music/ads/LolAdWrapper.kt b/app/src/main/java/melody/offline/music/ads/LolAdWrapper.kt index 48dc3f2..7108435 100644 --- a/app/src/main/java/melody/offline/music/ads/LolAdWrapper.kt +++ b/app/src/main/java/melody/offline/music/ads/LolAdWrapper.kt @@ -1,13 +1,21 @@ package melody.offline.music.ads import android.app.Activity +import android.widget.FrameLayout +import androidx.constraintlayout.widget.ConstraintLayout +import com.google.android.gms.ads.nativead.NativeAdView import com.lol.apex.ok.google.adlibrary.base.listener.AdLoadListener import com.lol.apex.ok.google.adlibrary.base.listener.AdShowListener import com.lol.apex.ok.google.adlibrary.base.listener.LolLoadError import com.lol.apex.ok.google.adlibrary.base.listener.LolShowError +import com.lol.apex.ok.google.adlibrary.inner.LOLAdsInnerDispatcher +import com.lol.apex.ok.google.adlibrary.inner.base.AdInnerLoadAdapter +import com.lol.apex.ok.google.adlibrary.inner.base.AdInnerShowAdapter import com.lol.apex.ok.google.adlibrary.inst.LOLAdsInstDispatcher import com.lol.apex.ok.google.adlibrary.rewarded.LOLAdsRewardedDispatcher import melody.offline.music.App +import melody.offline.music.R +import melody.offline.music.sp.AppStore import melody.offline.music.util.AnalysisUtil class LolAdWrapper { @@ -74,7 +82,7 @@ class LolAdWrapper { loadAd(act, placement, listener) } - fun showAd(act: Activity, placement: String, listener: LolShowListener? = null) { + private fun showAd(act: Activity, placement: String, listener: LolShowListener? = null) { if (act.isFinishing) return LOLAdsInstDispatcher.getShower(act, placement, object : AdShowListener { override fun onAdClicked() { @@ -99,6 +107,9 @@ class LolAdWrapper { App.app.isAdShowing.set(true) listener?.shown() AnalysisUtil.placeToLogEvent(placement, AnalysisAdState.AD_SHOWN) + + + App.app.lastAdDisplayTime.set(System.currentTimeMillis()) } override fun onAfterClickClosed() {} @@ -117,5 +128,68 @@ class LolAdWrapper { showAd(act, placement, listener) } } + + fun showAdTiming(act: Activity, placement: String, listener: LolShowListener? = null) { + //当前时间减去旧时间,才展示广告 + if (System.currentTimeMillis() - App.app.lastAdDisplayTime.get() >= AppStore(App.app).showAdIntervalTime) { + showAdIfCached(act, placement, listener) + } + } + + fun loadAdShowNativeAd( + context: Activity, nativeId: String, frameAd: FrameLayout, admobLayout: Int, maxLayout: Int + ) { + val inner = LOLAdsInnerDispatcher(context, object : AdInnerLoadAdapter() { + //设置广告位 + override fun getPlace(): String { + return nativeId + } + + //设置admob的native广告布局 + override fun getAdmobLayoutResId(): Int { + return admobLayout + } + + override fun getMaxLayoutResId(): Int { + return maxLayout + } + }) + + inner.addAdLoadListener(object : AdLoadListener { + + override fun onAdLoadFailed(error: LolLoadError?) { + + } + + override fun onAdLoaded() { + + } + }) + + //广告展示监听回调 + inner.addAdShowListener(object : AdShowListener { + override fun onAdClicked() { + + } + + override fun onAdRewarded() { + + } + + override fun onAdShowFailed(error: LolShowError?) { + } + + override fun onAdShown() {} + override fun onAdClosed() {} + override fun onAfterClickClosed() {} + override fun onDelayClosed() {} + }) + + inner.loadAd2Show(object : AdInnerShowAdapter() { + override fun getAdContainer(): FrameLayout { + return frameAd + } + }) + } } diff --git a/app/src/main/java/melody/offline/music/firebase/Constants.kt b/app/src/main/java/melody/offline/music/firebase/Constants.kt index 3086668..374a95c 100644 --- a/app/src/main/java/melody/offline/music/firebase/Constants.kt +++ b/app/src/main/java/melody/offline/music/firebase/Constants.kt @@ -10,6 +10,9 @@ object Constants { } """ + const val KEY_SHOW_AD_INTERVAL_TIME = "key_show_ad_interval_time" + const val DEFAULT_SHOW_AD_INTERVAL_TIME = 1000 * 30L + const val KEY_AD_JSON = "music_key_ad_json" const val DEFAULT_AD_JSON = """ { @@ -64,6 +67,356 @@ object Constants { "timeout": 15000, "showIntervalEnable": false }] + }, + "Music_inst_search": { + "data": [{ + "after_click": { + "admob_inst": "keep", + "max_inst": "keep" + }, + "block": { + "admob_inst": { + "delay": 0, + "rate": 0 + }, + "max_inst": { + "delay": 0, + "rate": 0 + } + }, + "close": { + "admob_inst": { + "delay": 0, + "rate": 0 + }, + "max_inst": { + "delay": 0, + "rate": 0 + } + }, + "config": [ + [ + "admob_inst", + { + "ca-app-pub-3940256099942544/1033173712": 100 + } + ] + ], + "limit": { + "admob_inst": 100, + "max_inst": 100 + }, + "cycle": 0, + "timeout": 15000, + "showIntervalEnable": false + }] + }, + "Music_native_search": { + "data": [{ + "config": [ + [ + "admob_native", + { + "ca-app-pub-3940256099942544/2247696110": 100 + } + ] + ], + "block": { + "admob_native": { + "delay": 0, + "rate": 0 + }, + "max_native": { + "delay": 0, + "rate": 0 + } + }, + "click": { + "admob_native": [ + 100, + 100, + 100, + 100, + 100 + ], + "max_native": [ + 100, + 100, + 100, + 100, + 100 + ] + }, + "after_click": { + "admob_native": "next", + "max_native": "next" + }, + "limit": { + "admob_native": 100, + "max_native": 100 + } + }] + }, + "Music_inst_into_play": { + "data": [{ + "after_click": { + "admob_inst": "keep", + "max_inst": "keep" + }, + "block": { + "admob_inst": { + "delay": 0, + "rate": 0 + }, + "max_inst": { + "delay": 0, + "rate": 0 + } + }, + "close": { + "admob_inst": { + "delay": 0, + "rate": 0 + }, + "max_inst": { + "delay": 0, + "rate": 0 + } + }, + "config": [ + [ + "admob_inst", + { + "ca-app-pub-3940256099942544/1033173712": 100 + } + ] + ], + "limit": { + "admob_inst": 100, + "max_inst": 100 + }, + "cycle": 0, + "timeout": 15000, + "showIntervalEnable": false + }] + }, + "Music_inst_cutting_song": { + "data": [{ + "after_click": { + "admob_inst": "keep", + "max_inst": "keep" + }, + "block": { + "admob_inst": { + "delay": 0, + "rate": 0 + }, + "max_inst": { + "delay": 0, + "rate": 0 + } + }, + "close": { + "admob_inst": { + "delay": 0, + "rate": 0 + }, + "max_inst": { + "delay": 0, + "rate": 0 + } + }, + "config": [ + [ + "admob_inst", + { + "ca-app-pub-3940256099942544/1033173712": 100 + } + ] + ], + "limit": { + "admob_inst": 100, + "max_inst": 100 + }, + "cycle": 0, + "timeout": 15000, + "showIntervalEnable": false + }] + }, + "Music_inst_download": { + "data": [{ + "after_click": { + "admob_inst": "keep", + "max_inst": "keep" + }, + "block": { + "admob_inst": { + "delay": 0, + "rate": 0 + }, + "max_inst": { + "delay": 0, + "rate": 0 + } + }, + "close": { + "admob_inst": { + "delay": 0, + "rate": 0 + }, + "max_inst": { + "delay": 0, + "rate": 0 + } + }, + "config": [ + [ + "admob_inst", + { + "ca-app-pub-3940256099942544/1033173712": 100 + } + ] + ], + "limit": { + "admob_inst": 100, + "max_inst": 100 + }, + "cycle": 0, + "timeout": 15000, + "showIntervalEnable": false + }] + }, + "Music_inst_me_page_list": { + "data": [{ + "after_click": { + "admob_inst": "keep", + "max_inst": "keep" + }, + "block": { + "admob_inst": { + "delay": 0, + "rate": 0 + }, + "max_inst": { + "delay": 0, + "rate": 0 + } + }, + "close": { + "admob_inst": { + "delay": 0, + "rate": 0 + }, + "max_inst": { + "delay": 0, + "rate": 0 + } + }, + "config": [ + [ + "admob_inst", + { + "ca-app-pub-3940256099942544/1033173712": 100 + } + ] + ], + "limit": { + "admob_inst": 100, + "max_inst": 100 + }, + "cycle": 0, + "timeout": 15000, + "showIntervalEnable": false + }] + }, + "Music_native_me_page_list": { + "data": [{ + "config": [ + [ + "admob_native", + { + "ca-app-pub-3940256099942544/2247696110": 100 + } + ] + ], + "block": { + "admob_native": { + "delay": 0, + "rate": 0 + }, + "max_native": { + "delay": 0, + "rate": 0 + } + }, + "click": { + "admob_native": [ + 100, + 100, + 100, + 100, + 100 + ], + "max_native": [ + 100, + 100, + 100, + 100, + 100 + ] + }, + "after_click": { + "admob_native": "next", + "max_native": "next" + }, + "limit": { + "admob_native": 100, + "max_native": 100 + } + }] + }, + "Music_inst_backup_ads": { + "data": [{ + "after_click": { + "admob_inst": "keep", + "max_inst": "keep" + }, + "block": { + "admob_inst": { + "delay": 0, + "rate": 0 + }, + "max_inst": { + "delay": 0, + "rate": 0 + } + }, + "close": { + "admob_inst": { + "delay": 0, + "rate": 0 + }, + "max_inst": { + "delay": 0, + "rate": 0 + } + }, + "config": [ + [ + "admob_inst", + { + "ca-app-pub-3940256099942544/1033173712": 100 + } + ] + ], + "limit": { + "admob_inst": 100, + "max_inst": 100 + }, + "cycle": 0, + "timeout": 15000, + "showIntervalEnable": false + }] } } """ diff --git a/app/src/main/java/melody/offline/music/fragment/MoMeFragment.kt b/app/src/main/java/melody/offline/music/fragment/MoMeFragment.kt index 2d320e8..e764ed1 100644 --- a/app/src/main/java/melody/offline/music/fragment/MoMeFragment.kt +++ b/app/src/main/java/melody/offline/music/fragment/MoMeFragment.kt @@ -13,6 +13,8 @@ import melody.offline.music.R import melody.offline.music.activity.MoLikedSongsActivity import melody.offline.music.activity.MoOfflineSongsActivity import melody.offline.music.activity.SettingsActivity +import melody.offline.music.ads.AdPlacement +import melody.offline.music.ads.LolAdWrapper import melody.offline.music.databinding.FragmentMoMeBinding import melody.offline.music.util.AnalysisUtil @@ -72,9 +74,7 @@ class MoMeFragment : MoBaseFragment() { AnalysisUtil.logEvent(AnalysisUtil.ME_B_PV) } else { Toast.makeText( - activity, - getString(R.string.liked_songs_no_data_prompt), - Toast.LENGTH_LONG + activity, getString(R.string.liked_songs_no_data_prompt), Toast.LENGTH_LONG ).show() } } @@ -86,9 +86,7 @@ class MoMeFragment : MoBaseFragment() { AnalysisUtil.logEvent(AnalysisUtil.ME_B_PV) } else { Toast.makeText( - activity, - getString(R.string.offline_songs_no_data_prompt), - Toast.LENGTH_LONG + activity, getString(R.string.offline_songs_no_data_prompt), Toast.LENGTH_LONG ).show() } } @@ -104,6 +102,14 @@ class MoMeFragment : MoBaseFragment() { val favoriteBeans = App.appFavoriteDBManager.getAllFavoriteBeans() val favorites = favoriteBeans.count { it.isFavorite } binding.likedSongsTv.text = "$favorites" + + LolAdWrapper.shared.loadAdShowNativeAd( + requireActivity(), + AdPlacement.NATIVE_ME_PAGE_LIST, + binding.frameAd, + R.layout.ad_layout_admob_result, + R.layout.ad_layout_max_result + ) } override fun onResume() { diff --git a/app/src/main/java/melody/offline/music/fragment/SearchFragment.kt b/app/src/main/java/melody/offline/music/fragment/SearchFragment.kt index bfab49a..b05aee4 100644 --- a/app/src/main/java/melody/offline/music/fragment/SearchFragment.kt +++ b/app/src/main/java/melody/offline/music/fragment/SearchFragment.kt @@ -34,6 +34,8 @@ import melody.offline.music.view.SearchResultOtherView import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.isActive import kotlinx.coroutines.selects.select +import melody.offline.music.ads.AdPlacement +import melody.offline.music.ads.LolAdWrapper import org.json.JSONObject import melody.offline.music.util.AnalysisUtil @@ -99,16 +101,13 @@ class SearchFragment : MoBaseFragment(), TextWatcher, SearchSuggestionsAdapter(requireActivity(), searchSuggestionsList) searchSuggestionsAdapterAdapter?.setOnItemClickListener(this) binding.searchSuggestionsRv.layoutManager = LinearLayoutManager( - requireActivity(), - LinearLayoutManager.VERTICAL, - false + requireActivity(), LinearLayoutManager.VERTICAL, false ) binding.searchSuggestionsRv.adapter = searchSuggestionsAdapterAdapter } private fun initSearchHistoryAdapter() { - searchHistoryAdapter = - SearchHistoryAdapter(requireActivity(), searchHistory) + searchHistoryAdapter = SearchHistoryAdapter(requireActivity(), searchHistory) searchHistoryAdapter?.setOnItemClickListener(this) val layoutManager = FlexboxLayoutManager(requireActivity()) layoutManager.flexWrap = FlexWrap.WRAP // 设置换行方式为自动换行 @@ -167,6 +166,9 @@ class SearchFragment : MoBaseFragment(), TextWatcher, } is Request.SearchData -> { + LolAdWrapper.shared.showAdTiming( + requireActivity(), AdPlacement.INST_SEARCH + ) showLoadingLayout() binding.contentLayout.removeAllViews() binding.searchEdit.clearFocus() @@ -189,16 +191,14 @@ class SearchFragment : MoBaseFragment(), TextWatcher, if (dataPage.type == 1) {//type为1的是最佳结果。 binding.contentLayout.addView( SearchResultOptimalView( - requireActivity(), - dataPage + requireActivity(), dataPage ) ) } else if (dataPage.type == 2) {//type为2的是其他搜索结果。 if (dataPage.searchResultList.isNotEmpty()) {//如何数据集合为空就不添加view binding.contentLayout.addView( SearchResultOtherView( - requireActivity(), - dataPage + requireActivity(), dataPage ) ) } @@ -208,6 +208,9 @@ class SearchFragment : MoBaseFragment(), TextWatcher, showNoContentLayout() } } + LolAdWrapper.shared.loadAdIfNotCached( + requireActivity(), AdPlacement.INST_SEARCH + ) } } } diff --git a/app/src/main/java/melody/offline/music/sp/AppStore.kt b/app/src/main/java/melody/offline/music/sp/AppStore.kt index 6621233..977fb5f 100644 --- a/app/src/main/java/melody/offline/music/sp/AppStore.kt +++ b/app/src/main/java/melody/offline/music/sp/AppStore.kt @@ -8,49 +8,39 @@ import melody.offline.music.util.PlayMode class AppStore(context: Context) { private val store = Store( - context - .getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE) - .asStoreProvider() + context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE).asStoreProvider() ) var searchHistoryStore: Set by store.stringSet( - key = SEARCH_HISTORY, - defaultValue = emptySet() + key = SEARCH_HISTORY, defaultValue = emptySet() ) var myVisitorData: String by store.string( - key = MY_VISITOR_DATA, - defaultValue = "" + key = MY_VISITOR_DATA, defaultValue = "" ) var playMusicMode: Int by store.int( - key = PLAY_MUSIC_MODE, - defaultValue = PlayMode.LIST_LOOP.value + key = PLAY_MUSIC_MODE, defaultValue = PlayMode.LIST_LOOP.value ) var userID: String by store.string( - key = APP_USERID, - defaultValue = "" + key = APP_USERID, defaultValue = "" ) var appUUID: String by store.string( - key = APP_UUID, - defaultValue = "" + key = APP_UUID, defaultValue = "" ) var ipCountryCode: String by store.string( - key = IP_COUNTRY_CODE, - defaultValue = "" + key = IP_COUNTRY_CODE, defaultValue = "" ) var firstOpenIsSucceed: Boolean by store.boolean( - key = FIRST_OPEN_IS_SUCCEED, - defaultValue = false + key = FIRST_OPEN_IS_SUCCEED, defaultValue = false ) var shouldEnterMusicPage: Boolean by store.boolean( - key = SHOULD_ENTER_MUSIC_PAGE, - defaultValue = true + key = SHOULD_ENTER_MUSIC_PAGE, defaultValue = true ) var shouldEnterMusicPageJson: String by store.string( @@ -60,8 +50,13 @@ class AppStore(context: Context) { //广告json-firebase配置 var adJson: String by store.string( - key = Constants.KEY_AD_JSON, - defaultValue = Constants.DEFAULT_AD_JSON + key = Constants.KEY_AD_JSON, defaultValue = Constants.DEFAULT_AD_JSON + ) + + //展示广告的间隔时间 + var showAdIntervalTime: Long by store.long( + key = Constants.KEY_SHOW_AD_INTERVAL_TIME, + defaultValue = Constants.DEFAULT_SHOW_AD_INTERVAL_TIME ) companion object { @@ -74,5 +69,6 @@ class AppStore(context: Context) { const val IP_COUNTRY_CODE = "ip_country_code" const val FIRST_OPEN_IS_SUCCEED = "first_open_is_succeed" const val SHOULD_ENTER_MUSIC_PAGE = "key_should_enter_music_page" + } } \ No newline at end of file diff --git a/app/src/main/java/melody/offline/music/util/AnalysisUtil.kt b/app/src/main/java/melody/offline/music/util/AnalysisUtil.kt index 3f0abb9..5517144 100644 --- a/app/src/main/java/melody/offline/music/util/AnalysisUtil.kt +++ b/app/src/main/java/melody/offline/music/util/AnalysisUtil.kt @@ -33,9 +33,30 @@ object AnalysisUtil { const val SEARCH_RESULT_SUCCESS_ACTION = "search_result_success_action"//搜索有结果 - private const val AD_USER_OPEN_SUCCESS = "ad_user_open_success"//首页开屏广告展示成功 - private const val AD_USER_OPEN_FAIL = "ad_user_open_fail"//首页开屏广告展示失败 - private const val AD_USER_OPEN_LOAD_FAIL = "ad_user_open_load_fail"//首页开屏广告展示load失败 + private const val AD_INST_SPLASH_SUCCESS = "ad_user_open_success"//首页开屏广告展示成功 + private const val AD_INST_SPLASH_FAIL = "ad_user_open_fail"//首页开屏广告展示失败 + private const val AD_INST_SPLASH_LOAD_FAIL = "ad_user_open_load_fail"//首页开屏广告展示load失败 + + private const val AD_INST_SEARCH_SUCCESS = "ad_inst_search_success" + private const val AD_INST_SEARCH_FAIL = "ad_inst_search_fail" + private const val AD_INST_SEARCH_LOAD_FAIL = "ad_inst_search_load_fail" + + private const val AD_INST_INTO_PLAY_SUCCESS = "ad_inst_into_play_success" + private const val AD_INST_INTO_PLAY_FAIL = "ad_inst_into_play_fail" + private const val AD_INST_INTO_PLAY_LOAD_FAIL = "ad_inst_into_play_load_fail" + + private const val AD_INST_CUTTING_SONG_SUCCESS = "ad_inst_cutting_song_success" + private const val AD_INST_CUTTING_SONG_FAIL = "ad_inst_cutting_song_fail" + private const val AD_INST_CUTTING_SONG_LOAD_FAIL = "ad_inst_cutting_song_load_fail" + + private const val AD_INST_DOWNLOAD_SUCCESS = "ad_inst_download_success" + private const val AD_INST_DOWNLOAD_FAIL = "ad_inst_download_fail" + private const val AD_INST_DOWNLOAD_LOAD_FAIL = "ad_inst_download_load_fail" + + private const val AD_INST_ME_PAGE_LIST_SUCCESS = "ad_inst_me_page_list_success" + private const val AD_INST_ME_PAGE_LIST_FAIL = "ad_inst_me_page_list_fail" + private const val AD_INST_ME_PAGE_LIST_LOAD_FAIL = "ad_inst_me_page_list_load_fail" + private var firebaseAnalytics: FirebaseAnalytics? = null @@ -76,15 +97,95 @@ object AnalysisUtil { AdPlacement.INST_SPLASH -> { when (state) { AnalysisAdState.AD_LOAD_FAILED -> { - logEvent(AD_USER_OPEN_LOAD_FAIL, param) + logEvent(AD_INST_SPLASH_LOAD_FAIL, param) } AnalysisAdState.AD_SHOW_FAILED -> { - logEvent(AD_USER_OPEN_FAIL, param) + logEvent(AD_INST_SPLASH_FAIL, param) } AnalysisAdState.AD_SHOWN -> { - logEvent(AD_USER_OPEN_SUCCESS) + logEvent(AD_INST_SPLASH_SUCCESS) + } + } + } + + AdPlacement.INST_SEARCH -> { + when (state) { + AnalysisAdState.AD_LOAD_FAILED -> { + logEvent(AD_INST_SEARCH_LOAD_FAIL, param) + } + + AnalysisAdState.AD_SHOW_FAILED -> { + logEvent(AD_INST_SEARCH_FAIL, param) + } + + AnalysisAdState.AD_SHOWN -> { + logEvent(AD_INST_SEARCH_SUCCESS) + } + } + } + + AdPlacement.INST_INTO_PLAY -> { + when (state) { + AnalysisAdState.AD_LOAD_FAILED -> { + logEvent(AD_INST_INTO_PLAY_LOAD_FAIL, param) + } + + AnalysisAdState.AD_SHOW_FAILED -> { + logEvent(AD_INST_INTO_PLAY_FAIL, param) + } + + AnalysisAdState.AD_SHOWN -> { + logEvent(AD_INST_INTO_PLAY_SUCCESS) + } + } + } + + AdPlacement.INST_CUTTING_SONG -> { + when (state) { + AnalysisAdState.AD_LOAD_FAILED -> { + logEvent(AD_INST_CUTTING_SONG_LOAD_FAIL, param) + } + + AnalysisAdState.AD_SHOW_FAILED -> { + logEvent(AD_INST_CUTTING_SONG_FAIL, param) + } + + AnalysisAdState.AD_SHOWN -> { + logEvent(AD_INST_CUTTING_SONG_SUCCESS) + } + } + } + + AdPlacement.INST_DOWNLOAD -> { + when (state) { + AnalysisAdState.AD_LOAD_FAILED -> { + logEvent(AD_INST_DOWNLOAD_LOAD_FAIL, param) + } + + AnalysisAdState.AD_SHOW_FAILED -> { + logEvent(AD_INST_DOWNLOAD_FAIL, param) + } + + AnalysisAdState.AD_SHOWN -> { + logEvent(AD_INST_DOWNLOAD_SUCCESS) + } + } + } + + AdPlacement.INST_ME_PAGE_LIST -> { + when (state) { + AnalysisAdState.AD_LOAD_FAILED -> { + logEvent(AD_INST_ME_PAGE_LIST_LOAD_FAIL, param) + } + + AnalysisAdState.AD_SHOW_FAILED -> { + logEvent(AD_INST_ME_PAGE_LIST_FAIL, param) + } + + AnalysisAdState.AD_SHOWN -> { + logEvent(AD_INST_ME_PAGE_LIST_SUCCESS) } } } diff --git a/app/src/main/res/layout/ad_layout_admob_banner.xml b/app/src/main/res/layout/ad_layout_admob_banner.xml new file mode 100644 index 0000000..f2db361 --- /dev/null +++ b/app/src/main/res/layout/ad_layout_admob_banner.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/ad_layout_admob_result.xml b/app/src/main/res/layout/ad_layout_admob_result.xml new file mode 100644 index 0000000..f76742e --- /dev/null +++ b/app/src/main/res/layout/ad_layout_admob_result.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/ad_layout_max_banner.xml b/app/src/main/res/layout/ad_layout_max_banner.xml new file mode 100644 index 0000000..e29f97d --- /dev/null +++ b/app/src/main/res/layout/ad_layout_max_banner.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + +