diff --git a/app/build.gradle b/app/build.gradle index b67a17ecea..6b6387fefb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -101,6 +101,8 @@ android { buildConfigField "String", "NEW_API_HOST", "\"${NEW_API_HOST}\"" buildConfigField "String", "LOG_HUB_PROJECT", "\"${LOG_HUB_PROJECT}\"" buildConfigField "String", "VAPI_HOST", "\"${VAPI_HOST}\"" + buildConfigField "String", "WGAME_CPM_BUSIAPPID", "\"${WGAME_CPM_BUSIAPPID}\"" + buildConfigField "String", "WGAME_CPM_API_HOST", "\"${WGAME_CPM_API_HOST}\"" buildConfigField "String", "WECHAT_APPID", "\"${WECHAT_APPID}\"" buildConfigField "String", "WECHAT_SECRET", "\"${WECHAT_SECRET}\"" buildConfigField "String", "TENCENT_APPID", "\"${TENCENT_APPID}\"" diff --git a/app/src/main/java/com/gh/common/DefaultUrlHandler.kt b/app/src/main/java/com/gh/common/DefaultUrlHandler.kt index 2b34992ec9..05e91ede9f 100644 --- a/app/src/main/java/com/gh/common/DefaultUrlHandler.kt +++ b/app/src/main/java/com/gh/common/DefaultUrlHandler.kt @@ -374,7 +374,7 @@ object DefaultUrlHandler { val iconSubscript = uri.getQueryParameter("game_icon_subscript") ?: "" val gameEntity = if (forumType == BbsType.OFFICIAL_BBS.value && gameId.isNotEmpty() && gameName.isNotEmpty() && icon.isNotEmpty()) { - GameEntity(id = gameId, mName = gameName, mIcon = icon, mIconSubscript = iconSubscript) + GameEntity(_id = gameId, mName = gameName, mIcon = icon, mIconSubscript = iconSubscript) } else null val activityLabelEntity = if (activityId.isNotEmpty() && activityName.isNotEmpty()) { ActivityLabelEntity( diff --git a/app/src/main/java/com/gh/common/constant/Config.java b/app/src/main/java/com/gh/common/constant/Config.java index 7badb27dda..ac06415f99 100644 --- a/app/src/main/java/com/gh/common/constant/Config.java +++ b/app/src/main/java/com/gh/common/constant/Config.java @@ -63,6 +63,9 @@ public class Config { public static final String NEW_API_HOST = EnvHelper.getNewHost(); public static final String VAPI_HOST = EnvHelper.getVHost(); + public static final String WGAME_CPM_BUSIAPPID = BuildConfig.WGAME_CPM_BUSIAPPID; + public static final String WGAME_CPM_API_HOST = EnvHelper.getWGameCPMHost(); + // Third-Party confs public static final String WECHAT_APPID = BuildConfig.WECHAT_APPID; public static final String WECHAT_SECRET = BuildConfig.WECHAT_SECRET; diff --git a/app/src/main/java/com/gh/common/exposure/ExposureListener.kt b/app/src/main/java/com/gh/common/exposure/ExposureListener.kt index f933c7a70f..7d8dc605df 100644 --- a/app/src/main/java/com/gh/common/exposure/ExposureListener.kt +++ b/app/src/main/java/com/gh/common/exposure/ExposureListener.kt @@ -6,6 +6,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView.LayoutManager import androidx.recyclerview.widget.StaggeredGridLayoutManager +import com.gh.gamecenter.common.constant.Constants import com.gh.gamecenter.feature.exposure.ExposureEvent import io.reactivex.functions.Consumer @@ -16,8 +17,9 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy val throttleBus: ExposureThrottleBus by lazy { ExposureThrottleBus( - Consumer { commitExposure(it) }, - Consumer(Throwable::printStackTrace) + { commitExposure(it) }, + Consumer(Throwable::printStackTrace), + { commitWXCPMExposure(it) } ) } var layoutManager: LayoutManager? = null @@ -93,4 +95,32 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy ExposureManager.log(eventList) } + /** + * 微信小游戏CPM曝光事件接口上报,由于普通曝光事件的上报通道存在节流特性,不符合CPM接口对于数据上报的实时性和准确性的要求,所以使用额外的通道进行上报 + */ + private fun commitWXCPMExposure(visibleState: ExposureThrottleBus.VisibleState) { + + val eventList = arrayListOf() + + for (pos in visibleState.firstVisiblePosition..visibleState.lastVisiblePosition) { + try { + exposable.getEventByPosition(pos)?.let { + if (it.payload.miniGameType == Constants.WECHAT_MINI_GAME_CPM) { + eventList.add(it) + } + } + exposable.getEventListByPosition(pos)?.let { list -> + list.forEach { + if (it.payload.miniGameType == Constants.WECHAT_MINI_GAME_CPM) { + eventList.add(it) + } + } + } + } catch (ignore: Exception) { + // Just ignore the error. + } + } + ExposureManager.logCPM(eventList) + } + } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/exposure/ExposureManager.kt b/app/src/main/java/com/gh/common/exposure/ExposureManager.kt index 6b5d052981..d88ec24083 100644 --- a/app/src/main/java/com/gh/common/exposure/ExposureManager.kt +++ b/app/src/main/java/com/gh/common/exposure/ExposureManager.kt @@ -1,11 +1,13 @@ package com.gh.common.exposure import com.gh.gamecenter.BuildConfig +import com.gh.gamecenter.common.constant.Constants import com.gh.gamecenter.common.loghub.TLogHubHelper import com.gh.gamecenter.common.utils.FixedSizeLinkedHashSet import com.gh.gamecenter.common.utils.toJson import com.gh.gamecenter.core.AppExecutor import com.gh.gamecenter.feature.exposure.ExposureEvent +import com.gh.gamecenter.feature.minigame.wechat.WGameSubjectCPMListReportHelper import com.lightgame.utils.Utils import com.volcengine.model.tls.LogItem @@ -32,6 +34,9 @@ object ExposureManager { */ fun log(event: ExposureEvent) { AppExecutor.logExecutor.execute { + if (event.payload.miniGameType == Constants.WECHAT_MINI_GAME_CPM) { + WGameSubjectCPMListReportHelper.reportExposure(event) + } if (!exposureCache.contains(event.id)) { exposureSet.add(event) exposureCache.add(event.id) @@ -58,6 +63,17 @@ object ExposureManager { } } + /** + * Log a wechat mini game cpm collection of exposure event. + */ + fun logCPM(eventList: List) { + AppExecutor.logExecutor.execute { + if (eventList.isNotEmpty()) { + WGameSubjectCPMListReportHelper.reportExposure(eventList.toSet()) + } + } + } + /** * @param forcedUpload Ignore all restrictions. */ diff --git a/app/src/main/java/com/gh/common/exposure/ExposureThrottleBus.kt b/app/src/main/java/com/gh/common/exposure/ExposureThrottleBus.kt index 1f87288612..59620851f2 100644 --- a/app/src/main/java/com/gh/common/exposure/ExposureThrottleBus.kt +++ b/app/src/main/java/com/gh/common/exposure/ExposureThrottleBus.kt @@ -3,16 +3,20 @@ package com.gh.common.exposure import io.reactivex.disposables.CompositeDisposable import io.reactivex.functions.Consumer import io.reactivex.schedulers.Schedulers -import io.reactivex.subjects.PublishSubject +import io.reactivex.subjects.BehaviorSubject import java.util.concurrent.TimeUnit -class ExposureThrottleBus(var onSuccess: Consumer, var onError: Consumer) { +class ExposureThrottleBus( + var onSuccess: Consumer, + var onError: Consumer, + onPreSuccess: Consumer +) { companion object { private const val THRESHOLD_TIME = 300L } - private val mPublishSubject: PublishSubject = PublishSubject.create() + private val mPublishSubject: BehaviorSubject = BehaviorSubject.create() private val mCompositeDisposable: CompositeDisposable = CompositeDisposable() init { @@ -24,6 +28,7 @@ class ExposureThrottleBus(var onSuccess: Consumer, var onError: Co */ val disposable = mPublishSubject .distinctUntilChanged() + .doOnNext(onPreSuccess) .throttleWithTimeout(THRESHOLD_TIME, TimeUnit.MILLISECONDS) .subscribeOn(Schedulers.io()) .subscribe(onSuccess, onError) diff --git a/app/src/main/java/com/gh/common/provider/BuildConfigImpl.kt b/app/src/main/java/com/gh/common/provider/BuildConfigImpl.kt index 9104d63c98..5922e1f0db 100644 --- a/app/src/main/java/com/gh/common/provider/BuildConfigImpl.kt +++ b/app/src/main/java/com/gh/common/provider/BuildConfigImpl.kt @@ -33,5 +33,9 @@ class BuildConfigImpl : IBuildConfigProvider { override fun getVDevApiHost(): String = BuildConfig.DEV_VAPI_HOST + override fun getWGameCPMApiHost(): String = BuildConfig.WGAME_CPM_API_HOST + + override fun getWGameCPMBusiAppId(): String = BuildConfig.WGAME_CPM_BUSIAPPID + override fun getLogProducerProject(): String = BuildConfig.LOG_HUB_PROJECT } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/provider/DirectProviderImpl.kt b/app/src/main/java/com/gh/common/provider/DirectProviderImpl.kt index b989c32468..50e115f9b0 100644 --- a/app/src/main/java/com/gh/common/provider/DirectProviderImpl.kt +++ b/app/src/main/java/com/gh/common/provider/DirectProviderImpl.kt @@ -62,7 +62,13 @@ class DirectProviderImpl : IDirectProvider { DirectUtils.directToCommunityArticle(context, articleId, communityId, entrance, path, sourceEntrance) } - override fun directToVideoDetail(context: Context, videoId: String, entrance: String?, path: String?, sourceEntrance: String) { + override fun directToVideoDetail( + context: Context, + videoId: String, + entrance: String?, + path: String?, + sourceEntrance: String + ) { DirectUtils.directToVideoDetail(context, videoId, entrance, path, sourceEntrance) } @@ -78,8 +84,13 @@ class DirectProviderImpl : IDirectProvider { DirectUtils.directToQQGameById(activity, qqAppId) } - override fun directToWechatGameById(activity: Activity, qqAppId: String) { - DirectUtils.directToWechatGameById(activity, qqAppId) + override fun directToWechatGameById( + activity: Activity, + wechatAppId: String, + wechatAppPath: String, + wechatAppExtData: String + ) { + DirectUtils.directToWechatGameById(activity, wechatAppId, wechatAppPath, wechatAppExtData) } override fun directToExternalBrowser(context: Context, url: String) { diff --git a/app/src/main/java/com/gh/common/util/DirectUtils.kt b/app/src/main/java/com/gh/common/util/DirectUtils.kt index 4b0583a25b..9ea0372561 100644 --- a/app/src/main/java/com/gh/common/util/DirectUtils.kt +++ b/app/src/main/java/com/gh/common/util/DirectUtils.kt @@ -485,11 +485,13 @@ object DirectUtils { ColumnCollectionDetailFragment.TYPE_QQ_MINI_GAME_COLUMN -> directToQGameHome(context) // QQ游戏专题详情页 - ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN, ViewPagerFragmentHelper.TYPE_WECHAT_GAME_COLUMN -> { - val subjectType = if (linkEntity.type == ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN) { - SubjectData.SubjectType.QQ_GAME - } else { - SubjectData.SubjectType.WECHAT_GAME + ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN, + ViewPagerFragmentHelper.TYPE_WECHAT_GAME_COLUMN, + ViewPagerFragmentHelper.TYPE_WECHAT_GAME_CPM_COLUMN -> { + val subjectType = when (linkEntity.type) { + ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN -> SubjectData.SubjectType.QQ_GAME + ViewPagerFragmentHelper.TYPE_WECHAT_GAME_CPM_COLUMN -> SubjectData.SubjectType.WECHAT_GAME_CPM + else -> SubjectData.SubjectType.WECHAT_GAME } directToSubject( context = context, @@ -2009,6 +2011,8 @@ object DirectUtils { fun directToWechatGameById( activity: Activity, wechatAppId: String, + wechatAppPath: String = "", + wechatAppExtData: String = "" ) { val wxApiProxy = WXAPIFactory.createWXAPI( @@ -2023,8 +2027,9 @@ object DirectUtils { wxApiProxy.sendReq( WXLaunchMiniProgram.Req().apply { userName = wechatAppId - path = Constants.WECHAT_MINI_GAME_PCS - miniprogramType = WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE; + path = wechatAppPath.ifEmpty { Constants.WECHAT_MINI_GAME_PCS } + extData = wechatAppExtData + miniprogramType = WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE } ) diff --git a/app/src/main/java/com/gh/common/util/DownloadItemUtils.kt b/app/src/main/java/com/gh/common/util/DownloadItemUtils.kt index acebdf74d2..ddcd190d6c 100644 --- a/app/src/main/java/com/gh/common/util/DownloadItemUtils.kt +++ b/app/src/main/java/com/gh/common/util/DownloadItemUtils.kt @@ -880,7 +880,7 @@ object DownloadItemUtils { } if (gameEntity.isMiniGame()) { downloadBtn.setOnClickListener { - MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType) + MiniGameItemHelper.launchMiniGame(gameEntity) clickCallback?.onCallback() allStateClickCallback?.onCallback() } diff --git a/app/src/main/java/com/gh/common/util/DownloadObserver.kt b/app/src/main/java/com/gh/common/util/DownloadObserver.kt index 4ca94e2e11..a5d07c6112 100644 --- a/app/src/main/java/com/gh/common/util/DownloadObserver.kt +++ b/app/src/main/java/com/gh/common/util/DownloadObserver.kt @@ -494,7 +494,7 @@ object DownloadObserver { java.lang.Boolean.parseBoolean(downloadEntity.getMetaExtra(Constants.IS_PLATFORM_RECOMMEND)) val exposureEvent = ExposureUtils.logADownloadCompleteExposureEvent( GameEntity( - id = downloadEntity.gameId, + _id = downloadEntity.gameId, mName = downloadEntity.name.removeSuffix(Constants.GAME_NAME_DECORATOR), gameVersion = downloadEntity.versionName ?: "", isPlatformRecommend = isPlatformRecommend, diff --git a/app/src/main/java/com/gh/common/util/ViewPagerFragmentHelper.kt b/app/src/main/java/com/gh/common/util/ViewPagerFragmentHelper.kt index efce8cf09d..9ecfffca27 100644 --- a/app/src/main/java/com/gh/common/util/ViewPagerFragmentHelper.kt +++ b/app/src/main/java/com/gh/common/util/ViewPagerFragmentHelper.kt @@ -65,6 +65,7 @@ object ViewPagerFragmentHelper { const val TYPE_COLUMN = "column" // 游戏专题详情页 const val TYPE_QQ_MINI_GAME_COLUMN = "qq_mini_game_column_detail" // QQ小游戏专题详情页 const val TYPE_WECHAT_GAME_COLUMN = "wechat_game_column_detail" // 微信小游戏专题详情页 + const val TYPE_WECHAT_GAME_CPM_COLUMN = "wechat_game_cpm_column_detail" // 微信小游戏CPM专题详情页 const val TYPE_COLUMN_COLLECTION = "column_collection" // 专题合集详情页 const val TYPE_SERVER = "server" // 开服表 const val TYPE_COLUMN_TEST = "column_test_v2" // 新游开测 @@ -163,10 +164,11 @@ object ViewPagerFragmentHelper { className = GameCollectionSquareFragment::class.java.name } // 游戏专题详情页/QQ游戏专题详情页 - TYPE_COLUMN, TYPE_QQ_MINI_GAME_COLUMN, TYPE_WECHAT_GAME_COLUMN -> { + TYPE_COLUMN, TYPE_QQ_MINI_GAME_COLUMN, TYPE_WECHAT_GAME_COLUMN, TYPE_WECHAT_GAME_CPM_COLUMN -> { val subjectType = when(entity.type) { TYPE_QQ_MINI_GAME_COLUMN -> SubjectData.SubjectType.QQ_GAME TYPE_WECHAT_GAME_COLUMN -> SubjectData.SubjectType.WECHAT_GAME + TYPE_WECHAT_GAME_CPM_COLUMN -> SubjectData.SubjectType.WECHAT_GAME_CPM else -> SubjectData.SubjectType.NORMAL } className = SubjectFragment::class.java.name diff --git a/app/src/main/java/com/gh/gamecenter/SkipActivity.java b/app/src/main/java/com/gh/gamecenter/SkipActivity.java index 7c76d1da49..cc01786d3d 100644 --- a/app/src/main/java/com/gh/gamecenter/SkipActivity.java +++ b/app/src/main/java/com/gh/gamecenter/SkipActivity.java @@ -408,7 +408,7 @@ public class SkipActivity extends BaseActivity { try { JSONObject extJsonObject = new JSONObject(extJson); String qqGameId = extJsonObject.optString("aid"); - MiniGameItemHelper.INSTANCE.launchMiniGame(qqGameId, Constants.QQ_MINI_GAME); + MiniGameItemHelper.INSTANCE.launchMiniGame(qqGameId, Constants.QQ_MINI_GAME, "", ""); } catch (JSONException ignored) { } break; diff --git a/app/src/main/java/com/gh/gamecenter/download/AdGameBannerAdapter.kt b/app/src/main/java/com/gh/gamecenter/download/AdGameBannerAdapter.kt index 486cf2d6c2..e293d3c56b 100644 --- a/app/src/main/java/com/gh/gamecenter/download/AdGameBannerAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/download/AdGameBannerAdapter.kt @@ -93,7 +93,7 @@ class AdGameBannerAdapter( it.name ?: "" ) if (it.isMiniGame()) { - MiniGameItemHelper.launchMiniGame(it.miniGameAppId, it.miniGameType) + MiniGameItemHelper.launchMiniGame(it) } else { GameDetailActivity.startGameDetailActivity( mContext, diff --git a/app/src/main/java/com/gh/gamecenter/entity/SearchSubjectEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/SearchSubjectEntity.kt index 35bbcb035f..bc5baaac12 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/SearchSubjectEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/SearchSubjectEntity.kt @@ -9,14 +9,16 @@ import kotlinx.parcelize.Parcelize @Parcelize data class SearchSubjectEntity( val name: String = "", - val games: List = listOf(), + var games: List = listOf(), val location: Int = 0, @SerializedName("column_id") val columnId: String = "", val adId: String = "", // 广告ID(本地字段),不为空时为广告专题 val codeId: String = "", // 广告CODE_ID(本地字段),不为空时为广告专题 @SerializedName("ad_icon_active") - val adIconActive: Boolean = false + val adIconActive: Boolean = false, + // 本地字段,标记是否为微信小游戏CPM专题 + var isWGameSubjectCPM: Boolean = false ) : Parcelable { fun getFilterGame() = RegionSettingHelper.filterGame(games) } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/entity/SubjectData.kt b/app/src/main/java/com/gh/gamecenter/entity/SubjectData.kt index f61871745e..c3f1ad39fa 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/SubjectData.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/SubjectData.kt @@ -63,6 +63,11 @@ class SubjectData( /** * 微信小游戏专题 */ - WECHAT_GAME + WECHAT_GAME, + + /** + * 微信小游戏CPM专题 + */ + WECHAT_GAME_CPM, } } diff --git a/app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt index a98e2d6ffb..4f02518f8c 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt @@ -104,6 +104,8 @@ data class SubjectEntity( @SerializedName("is_wechat_column") var isWechatColumn: Boolean = false, + var isWechatColumnCPM: Boolean = false, + var explain: String = "", // 游戏单合集说明 @SerializedName("show_star") @@ -130,6 +132,7 @@ data class SubjectEntity( val subjectType: SubjectData.SubjectType get() = when { isQQColumn -> SubjectData.SubjectType.QQ_GAME + isWechatColumnCPM -> SubjectData.SubjectType.WECHAT_GAME_CPM isWechatColumn -> SubjectData.SubjectType.WECHAT_GAME else -> SubjectData.SubjectType.NORMAL } diff --git a/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt index 005cba445d..b165ebe64e 100644 --- a/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt @@ -611,7 +611,7 @@ class GameFragmentAdapter( val subjectData = gameEntity.subjectData DataCollectionUtils.uploadClick(mContext, subjectData?.name + "-列表", "游戏-专题", gameEntity.name) if (gameEntity.isMiniGame()) { - MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType) + MiniGameItemHelper.launchMiniGame(gameEntity) } else { GameDetailActivity.startGameDetailActivity( mContext, gameEntity, @@ -1322,7 +1322,7 @@ class GameFragmentAdapter( DataCollectionUtils.uploadClick(mContext, subjectData.name + "-列表", "游戏-专题", gameEntity.name) if (gameEntity.isMiniGame()) { - MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType) + MiniGameItemHelper.launchMiniGame(gameEntity) } else if (gameEntity.isPluggable) { GameDetailActivity.startGameDetailActivity( mContext, diff --git a/app/src/main/java/com/gh/gamecenter/game/gallery/GameGallerySlideViewHolder.kt b/app/src/main/java/com/gh/gamecenter/game/gallery/GameGallerySlideViewHolder.kt index 7b74edd638..08b13388ab 100644 --- a/app/src/main/java/com/gh/gamecenter/game/gallery/GameGallerySlideViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/game/gallery/GameGallerySlideViewHolder.kt @@ -135,7 +135,7 @@ class GameGallerySlideViewHolder(val binding: GameGallerySlideItemBinding) : Bas binding.iconIv.displayGameIcon(gameEntity) binding.iconIv.setOnClickListener { if (gameEntity.isMiniGame()) { - MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType) + MiniGameItemHelper.launchMiniGame(gameEntity) } else { GameDetailActivity.startGameDetailActivity( binding.root.context, diff --git a/app/src/main/java/com/gh/gamecenter/game/gallery/GameGalleryViewHolder.kt b/app/src/main/java/com/gh/gamecenter/game/gallery/GameGalleryViewHolder.kt index fde0da9a82..dbf8ea49cf 100644 --- a/app/src/main/java/com/gh/gamecenter/game/gallery/GameGalleryViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/game/gallery/GameGalleryViewHolder.kt @@ -55,7 +55,7 @@ class GameGalleryViewHolder(val cell: GameGalleryItemCell) : if (subjectEntity.isMiniGame) { gameIcon.setOnClickListener { - MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType) + MiniGameItemHelper.launchMiniGame(gameEntity) } } else { gameIcon.setOnClickListener(null) diff --git a/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalAdapter.kt index e66e9278be..b178608e65 100644 --- a/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalAdapter.kt @@ -140,7 +140,7 @@ class GameHorizontalAdapter( } if (gameEntity.isMiniGame()) { - MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType) + MiniGameItemHelper.launchMiniGame(gameEntity) } else { GameDetailActivity.startGameDetailActivity( mContext, diff --git a/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideAdapter.kt index aae601456a..1f508fdf14 100644 --- a/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideAdapter.kt @@ -68,7 +68,7 @@ class GameHorizontalSlideAdapter( holder.bindGameHorizontalItem(gameEntity, mSubjectEntity) holder.itemView.setOnClickListener { if (gameEntity.isMiniGame()) { - MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType) + MiniGameItemHelper.launchMiniGame(gameEntity) } else { val exposureEvent = exposureEventList?.safelyGetInRelease(position) if (exposureEvent != null) { diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeGameItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/home/HomeGameItemViewHolder.kt index c161137c4c..e6e2c103e7 100644 --- a/app/src/main/java/com/gh/gamecenter/home/HomeGameItemViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/home/HomeGameItemViewHolder.kt @@ -97,7 +97,7 @@ class HomeGameItemViewHolder(val binding: HomeGameItemBinding) : BaseRecyclerVie } holder.itemView.setOnClickListener { if (game.isMiniGame()) { - MiniGameItemHelper.launchMiniGame(game.miniGameAppId, game.miniGameType) + MiniGameItemHelper.launchMiniGame(game) } else { GameDetailActivity.startGameDetailActivity( binding.root.context, diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/CustomPageFragment.kt b/app/src/main/java/com/gh/gamecenter/home/custom/CustomPageFragment.kt index 31b9e529c7..021701f3b1 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/CustomPageFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/CustomPageFragment.kt @@ -292,7 +292,7 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable { gameDetailDestination.observe(viewLifecycleOwner, EventObserver { (entrance, game) -> if (game.isMiniGame()) { - MiniGameItemHelper.launchMiniGame(game.miniGameAppId, game.miniGameType) + MiniGameItemHelper.launchMiniGame(game) } else { GameDetailActivity.startGameDetailActivity( requireContext(), diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/CustomPageViewModel.kt b/app/src/main/java/com/gh/gamecenter/home/custom/CustomPageViewModel.kt index 578fc89209..2bdcb9cad2 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/CustomPageViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/CustomPageViewModel.kt @@ -78,6 +78,7 @@ class CustomPageViewModel( addSource(repository.customDiscoverItemLiveData, ::notifyItemChanged) addSource(repository.recentGamesItemLiveData, ::notifyItemChanged) addSource(repository.customPluginItemLiveData, ::notifyItemChanged) + addSource(repository.wechatMiniGameCPMItemLiveData, ::notifyWechatMiniGameCPMSubjectItemChanged) } val dataList: LiveData> = _dataList @@ -357,11 +358,11 @@ class CustomPageViewModel( } } - override fun onChangeABatch(subjectEntity: SubjectEntity, position: Int) { + override fun onChangeABatch(subjectEntity: SubjectEntity) { val subjectId = subjectEntity.id ?: return val gameList = subjectChangedMap[subjectId] if (gameList != null) { - changeSubjectCustomPageItem(position, getRandomGameList(subjectEntity.data, ArrayList(gameList))) + changeSubjectCustomPageItem(subjectId, getRandomGameList(subjectEntity.data, ArrayList(gameList))) } else { repository.loadChangeSubjectGame(subjectEntity) .subscribeOn(Schedulers.io()) @@ -370,7 +371,7 @@ class CustomPageViewModel( override fun onResponse(response: List?) { if (response != null) { subjectChangedMap[subjectId] = response - onChangeABatch(subjectEntity, position) + onChangeABatch(subjectEntity) } } @@ -396,21 +397,32 @@ class CustomPageViewModel( return resultGameList } - private fun changeSubjectCustomPageItem(position: Int, newGameList: MutableList) { + private fun changeSubjectCustomPageItem(id: String, newGameList: MutableList) { val oldData = _dataList.value as? MutableList - if (!oldData.isNullOrEmpty() && newGameList.isNotEmpty()) { + val newData = oldData?.toMutableList() + if (!newData.isNullOrEmpty() && newGameList.isNotEmpty()) { // 替换当前专题游戏数据 - val customPageItem = oldData.getOrNull(position) + val position = newData.indexOfFirst { + when(it) { + is CustomSubjectItem -> it.data.id == id + is CustomSplitSubjectItem -> it.data.id == id + else -> false + } + } + if (position == -1) return + + val customPageItem = newData[position] if (customPageItem is CustomSubjectItem) { - val newCustomPageItem = customPageItem.copy(data = customPageItem.data.copy(mData = newGameList)) - oldData[position] = newCustomPageItem + val newCustomPageItem = + customPageItem.copy(data = customPageItem.data.copy(mData = newGameList), _position = position) + newData[position] = newCustomPageItem gamePositionAndPackageHelper.putAll(getPositionAndPackageMap(newCustomPageItem, newGameList)) } if (customPageItem is CustomSplitSubjectItem) { // 移除所有旧数据 - oldData.removeAll { + newData.removeAll { it.componentPosition == customPageItem.componentPosition } @@ -433,21 +445,15 @@ class CustomPageViewModel( ) // 将新的 items 添加到列表集合 - if (position >= oldData.size) { - oldData.addAll(newItems) - } else { - oldData.addAll(position, newItems) - } - + newData.addAll(position, newItems) // 修正集合中 item 的position 取值 - oldData.forEachIndexed { index, item -> + newData.forEachIndexed { index, item -> item.position = index } - } // 通知更新 - _dataList.value = oldData + _dataList.value = newData } } @@ -467,6 +473,40 @@ class CustomPageViewModel( } } + /** + * 通过CPM接口异步请求获取的微信小游戏数据插入 + */ + private fun notifyWechatMiniGameCPMSubjectItemChanged(result: Pair>) { + val oldData = _dataList.value ?: return + val index = oldData.indexOfFirst { + it is CustomWeChatMiniGamesCPMSubjectItem && it.data.id == result.first + } + if (index == -1) return + val subjectItem = (oldData[index] as CustomWeChatMiniGamesCPMSubjectItem).apply { + data.data = result.second.toMutableList() + data.isWechatColumnCPM = true + } + val position = subjectItem.position + val componentPosition = subjectItem.componentPosition + val newData = oldData.toMutableList() + val customPageItemList = repository.convertColumnDetailSubjectItems( + position, + componentPosition, + subjectItem.link, + subjectItem.data + ) + if (customPageItemList.isEmpty()) return + newData[index] = customPageItemList[0] + newData.addAll(index + 1, customPageItemList.subList(1, customPageItemList.size)) + newData.forEachIndexed { pos, customPageItem -> + customPageItem.position = pos + } + repository.notifyPositionChanged(newData.size) + gamePositionAndPackageHelper.clear() + gamePositionAndPackageHelper.putAll(getPositionAndPackageMap(newData)) + _dataList.value = newData + } + private fun notifyItemRemoved(removeItem: CustomPageItem) { val oldData = _dataList.value ?: return val newData = oldData.toMutableList() @@ -476,7 +516,7 @@ class CustomPageViewModel( for (i in removeItem.position until newData.size) { newData[i].position-- } - repository.notifyPositionChanged(-1) + repository.notifyPositionAdded(-1) gamePositionAndPackageHelper.clear() gamePositionAndPackageHelper.putAll(getPositionAndPackageMap(newData)) _dataList.value = newData diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomGameHorizontalAdapter.kt b/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomGameHorizontalAdapter.kt index 57279104f6..5bd5ceeb74 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomGameHorizontalAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/adapter/CustomGameHorizontalAdapter.kt @@ -134,7 +134,7 @@ class CustomGameHorizontalAdapter( } if (gameEntity.isMiniGame()) { - MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType) + MiniGameItemHelper.launchMiniGame(gameEntity) } else { GameDetailActivity.startGameDetailActivity( context, diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/eventlistener/OnCustomPageEventListener.kt b/app/src/main/java/com/gh/gamecenter/home/custom/eventlistener/OnCustomPageEventListener.kt index b6ed6c3f6e..37833fac1b 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/eventlistener/OnCustomPageEventListener.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/eventlistener/OnCustomPageEventListener.kt @@ -29,7 +29,7 @@ interface OnCustomPageEventListener { /** * 换一批 */ - fun onChangeABatch(subjectEntity: SubjectEntity, position: Int) + fun onChangeABatch(subjectEntity: SubjectEntity) fun onChangeAppBarColor(color: Int) diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/eventlistener/SubjectEventHelper.kt b/app/src/main/java/com/gh/gamecenter/home/custom/eventlistener/SubjectEventHelper.kt index 2934bcbb1e..7de763935b 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/eventlistener/SubjectEventHelper.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/eventlistener/SubjectEventHelper.kt @@ -39,7 +39,7 @@ class SubjectEventHelper(viewModel: CustomPageViewModel) : CustomPageItemChildEv fun onChangeABatch(subject: SubjectEntity) { tracker.trackColumnClick(_item, null, "右上角", "换一批") - viewModel.onChangeABatch(subject, _item.position) + viewModel.onChangeABatch(subject) } fun onMoreClick(link: LinkEntity) { diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/model/CustomPageData.kt b/app/src/main/java/com/gh/gamecenter/home/custom/model/CustomPageData.kt index 9d13482d23..bd23d2f399 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/model/CustomPageData.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/model/CustomPageData.kt @@ -73,6 +73,8 @@ class CustomPageData( val qqMiniGameColumn: SubjectEntity? = null, @SerializedName("link_wechat_game_column_detail") val wechatMiniGameColumn: SubjectEntity? = null, + @SerializedName("link_wechat_game_cpm_column_detail") + val wechatMiniGameCPMColumn: SubjectEntity? = null, @SerializedName("link_common_collection") val linkCommonCollection: CommonContentCollection? = null, @SerializedName("link_qq_game_recently_played") @@ -83,6 +85,7 @@ class CustomPageData( get() = when (link.type) { CustomPageItem.CUSTOM_LINK_TYPE_QQ_MINI_GAME_COLUMN_DETAIL -> qqMiniGameColumn CustomPageItem.CUSTOM_LINK_TYPE_WECHAT_MINI_GAME_COLUMN_DETAIL -> wechatMiniGameColumn + CustomPageItem.CUSTOM_LINK_TYPE_WECHAT_WECHAT_GAME_CPM_COLUMN_DETAIL -> wechatMiniGameCPMColumn else -> linkColumn } @@ -672,7 +675,7 @@ class CustomPageData( @SerializedName("home") private val _home: String? = null, @SerializedName("more_link") - val moreLink: LinkEntity? = null + val moreLink: LinkEntity? = null ) { val home: String diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/model/CustomPageItem.kt b/app/src/main/java/com/gh/gamecenter/home/custom/model/CustomPageItem.kt index ed7a9dbd4e..2e83e130c6 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/model/CustomPageItem.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/model/CustomPageItem.kt @@ -4,10 +4,7 @@ import com.gh.common.util.ViewPagerFragmentHelper import com.gh.gamecenter.common.entity.LinkEntity import com.gh.gamecenter.common.exposure.ExposureSource import com.gh.gamecenter.core.utils.TimeUtils -import com.gh.gamecenter.entity.AmwayCommentEntity -import com.gh.gamecenter.entity.DiscoveryCardEntity -import com.gh.gamecenter.entity.HomeItemTestV2Entity -import com.gh.gamecenter.entity.SubjectEntity +import com.gh.gamecenter.entity.* import com.gh.gamecenter.feature.entity.GameEntity import com.gh.gamecenter.feature.exposure.ExposureEvent import com.gh.vspace.VGameItemData @@ -84,6 +81,7 @@ abstract class CustomPageItem( const val CUSTOM_LINK_TYPE_WECHAT_GAME_RECENTLY_PLAYED = "wechat_game_recently_played" const val CUSTOM_LINK_TYPE_QQ_MINI_GAME_COLUMN_DETAIL = ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN const val CUSTOM_LINK_TYPE_WECHAT_MINI_GAME_COLUMN_DETAIL = ViewPagerFragmentHelper.TYPE_WECHAT_GAME_COLUMN + const val CUSTOM_LINK_TYPE_WECHAT_WECHAT_GAME_CPM_COLUMN_DETAIL = ViewPagerFragmentHelper.TYPE_WECHAT_GAME_CPM_COLUMN const val CUSTOM_LINK_TYPE_HALO_RECOMMEND = "halo_recommend" const val CUSTOM_LINK_TYPE_COLUMN_COLLECTION = "column_collection" // 专题合集 const val CUSTOM_LINK_TYPE_GAME_LIST_COLLECTION = "game_list_collection" @@ -300,6 +298,7 @@ abstract class CustomPageItem( CUSTOM_LINK_TYPE_WECHAT_GAME_RECENTLY_PLAYED to "最近在玩", CUSTOM_LINK_TYPE_QQ_MINI_GAME_COLUMN_DETAIL to "QQ小游戏专题", CUSTOM_LINK_TYPE_WECHAT_MINI_GAME_COLUMN_DETAIL to "微信小游戏专题", + CUSTOM_LINK_TYPE_WECHAT_WECHAT_GAME_CPM_COLUMN_DETAIL to "微信小游戏专题", CUSTOM_LINK_TYPE_HALO_RECOMMEND to "光环推荐", CUSTOM_LINK_TYPE_COLUMN_COLLECTION to "专题合集", CUSTOM_LINK_TYPE_GAME_LIST_COLLECTION to "游戏单合集", @@ -623,6 +622,25 @@ data class CustomRecentWeChatMiniGamesItem( } } +// 微信小游戏CPM专题组件 +data class CustomWeChatMiniGamesCPMSubjectItem( + private val _link: LinkEntity, + val data: SubjectEntity, + private val _position: Int, + private val _componentPosition: Int +) : CustomPageItem(_link, _position, _componentPosition) { + + override val itemType: Int + get() = CUSTOM_PAGE_ITEM_TYPE_MINI_GAME_RECENT_PLAY + + override fun doAreContentsTheSames(other: CustomPageItem): Boolean { + return other is CustomWeChatMiniGamesCPMSubjectItem + && data == other.data + && position == other.position + && componentPosition == other.componentPosition + } +} + // qq小游戏-最近在玩 data class CustomRecentQqMiniGamesItem( private val _link: LinkEntity, diff --git a/app/src/main/java/com/gh/gamecenter/home/custom/model/CustomPageRepository.kt b/app/src/main/java/com/gh/gamecenter/home/custom/model/CustomPageRepository.kt index 33b8661b48..505900aadd 100644 --- a/app/src/main/java/com/gh/gamecenter/home/custom/model/CustomPageRepository.kt +++ b/app/src/main/java/com/gh/gamecenter/home/custom/model/CustomPageRepository.kt @@ -3,12 +3,12 @@ package com.gh.gamecenter.home.custom.model import android.graphics.Paint import androidx.lifecycle.LiveData import androidx.lifecycle.MediatorLiveData -import androidx.lifecycle.Observer import com.gh.common.filter.RegionSettingHelper import com.gh.common.util.GameSubstituteRepositoryHelper import com.gh.common.util.HomePluggableHelper import com.gh.download.DownloadManager import com.gh.gamecenter.common.constant.Constants +import com.gh.gamecenter.common.entity.LinkEntity import com.gh.gamecenter.common.utils.TextHelper import com.gh.gamecenter.common.utils.dip2px import com.gh.gamecenter.common.utils.sp2px @@ -18,11 +18,11 @@ import com.gh.gamecenter.entity.DiscoveryCardEntity import com.gh.gamecenter.entity.GameUpdateEntity import com.gh.gamecenter.entity.PullDownPush import com.gh.gamecenter.entity.SubjectEntity +import com.gh.gamecenter.feature.entity.FloatingWindowEntity import com.gh.gamecenter.feature.entity.GameEntity import com.gh.gamecenter.feature.entity.PluginLocation import com.gh.gamecenter.feature.entity.TagStyleEntity import com.gh.gamecenter.feature.utils.ApkActiveUtils -import com.gh.gamecenter.feature.entity.FloatingWindowEntity import com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMMON_CONTENT_COLLECTION_LAYOUT_BANNER import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMMON_CONTENT_COLLECTION_LAYOUT_DOUBLE_ROW_BANNER @@ -47,7 +47,6 @@ import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMPONENTS_S import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMPONENTS_SUBJECT_TYPE_GAME_HORIZONTAL_SLIDE import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMPONENTS_SUBJECT_TYPE_GAME_TIMELINE_HORIZONTAL_SLIDE import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMPONENTS_SUBJECT_TYPE_GAME_VERTICAL_SLIDE -import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMPONENTS_SUBJECT_TYPE_SINGLE_GAME_CARD import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_TYPE_COLUMN import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_TYPE_GAME import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_TYPE_HALO_RECOMMEND @@ -55,7 +54,11 @@ import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_ import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_TYPE_QQ_MINI_GAME_COLUMN_DETAIL import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_TYPE_WECHAT_GAME_RECENTLY_PLAYED import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_TYPE_WECHAT_MINI_GAME_COLUMN_DETAIL +import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_TYPE_WECHAT_WECHAT_GAME_CPM_COLUMN_DETAIL import com.gh.gamecenter.minigame.MiniGameRecentlyPlayUseCase +import com.gh.gamecenter.minigame.wechat.WGameSubjectCPMListRepository +import com.gh.gamecenter.minigame.wechat.WGameSubjectCPMListUseCase +import com.gh.gamecenter.minigame.wechat.WGameSubjectCPMRemoteDataSource import com.gh.gamecenter.packagehelper.PackageRepository import com.gh.gamecenter.retrofit.RetrofitManager import com.gh.gamecenter.wrapper.MainWrapperRepository @@ -63,12 +66,14 @@ import com.gh.vspace.VHelper import io.reactivex.Observable import io.reactivex.Single import io.reactivex.disposables.CompositeDisposable +import java.util.concurrent.atomic.AtomicInteger import java.util.regex.Pattern class CustomPageRepository private constructor( private val remoteDataSource: CustomPageRemoteDataSource, - private val localDataSource: CustomPageLocalDataSource + private val localDataSource: CustomPageLocalDataSource, + private val wGameSubjectCPMRemoteDataSource: WGameSubjectCPMRemoteDataSource ) { private val pageInfo = PageInfo() @@ -77,6 +82,10 @@ class CustomPageRepository private constructor( private val shareRepository = CustomPageShareRepository.instance + private val wGameSubjectCPMListUseCase = WGameSubjectCPMListUseCase( + WGameSubjectCPMListRepository(wGameSubjectCPMRemoteDataSource) + ) + private var recentItem: CustomRecentGamesItem? = null private var recentQQItem: CustomRecentQqMiniGamesItem? = null @@ -91,14 +100,13 @@ class CustomPageRepository private constructor( private var displayingGameIdSet = hashSetOf() // 当前正在显示的游戏 id 列表 - private val _customPluginItemLiveData = MediatorLiveData().apply { + val customPluginItemLiveData: LiveData = MediatorLiveData().apply { addSource(PackageRepository.gameUpdateLiveData) { refreshPluginIfNeed(it)?.let(this::setValue) } } - val customPluginItemLiveData: LiveData = _customPluginItemLiveData - private val _recentGamesItemLiveData = MediatorLiveData().apply { + val recentGamesItemLiveData: LiveData = MediatorLiveData().apply { addSource(DownloadManager.getInstance().downloadEntityLiveData) { refreshRecentVGameIfNeed()?.let(this::setValue) } @@ -106,29 +114,30 @@ class CustomPageRepository private constructor( refreshRecentVGameIfNeed()?.let(this::setValue) } } - val recentGamesItemLiveData: LiveData = _recentGamesItemLiveData - private val _recentMiniGamesItemLiveData = MediatorLiveData().apply { - addSource(MiniGameRecentlyPlayUseCase.wechatRecentGamesItemLiveData) { - refreshRecentWechatMiniGameIfNeed(it)?.let(this::setValue) + val recentMiniGamesItemLiveData: LiveData = + MediatorLiveData().apply { + addSource(MiniGameRecentlyPlayUseCase.wechatRecentGamesItemLiveData) { + refreshRecentWechatMiniGameIfNeed(it)?.let(this::setValue) + } } - } - val recentMiniGamesItemLiveData: LiveData = _recentMiniGamesItemLiveData - - private val _recentQqMiniGamesItemLiveData = MediatorLiveData().apply { - addSource(MiniGameRecentlyPlayUseCase.qqRecentGamesItemLiveData) { - refreshRecentQQMiniGameIfNeed(it)?.let(this::setValue) + val recentQqMiniGamesItemLiveData: LiveData = + MediatorLiveData().apply { + addSource(MiniGameRecentlyPlayUseCase.qqRecentGamesItemLiveData) { + refreshRecentQQMiniGameIfNeed(it)?.let(this::setValue) + } } - } - val recentQqMiniGamesItemLiveData: LiveData = _recentQqMiniGamesItemLiveData - private val _customDiscoverItemLiveData = MediatorLiveData().apply { - addSource(shareRepository.discoverData) { - refreshDiscoverDataIfNeed(it)?.let(this::setValue) + val customDiscoverItemLiveData: LiveData = + MediatorLiveData().apply { + addSource(shareRepository.discoverData) { + refreshDiscoverDataIfNeed(it)?.let(this::setValue) + } } - } - val customDiscoverItemLiveData: LiveData = _customDiscoverItemLiveData + + val wechatMiniGameCPMItemLiveData: LiveData>> = + wGameSubjectCPMListUseCase.wechatMiniGameCPMListLiveData val hiddenNotifications: LiveData>> get() = shareRepository.hiddenNotifications @@ -224,6 +233,7 @@ class CustomPageRepository private constructor( private fun transformRawDataIntoItemData(data: CustomPageData, reloadDiscoverData: Boolean): List { val list = arrayListOf() + data.customsComponents .forEachIndexed { _, item -> // 如果当前item不是展开大图,并且上一个item为展开大图,则说明展开大图组件已结束 @@ -265,112 +275,24 @@ class CustomPageRepository private constructor( } } - item.link.type == CUSTOM_LINK_TYPE_COLUMN || item.link.type == CUSTOM_LINK_TYPE_QQ_MINI_GAME_COLUMN_DETAIL || item.link.type == CUSTOM_LINK_TYPE_WECHAT_MINI_GAME_COLUMN_DETAIL -> { - // 游戏专题 - val gameSubject = item.gameSubjectEntity?.also { - if (item.link.type == CUSTOM_LINK_TYPE_COLUMN) { - it.data?.forEach { game -> - game.gameLocation = GameEntity.GameLocation.INDEX - } - } - } - - var isAdded = false - if (gameSubject != null && !gameSubject.data.isNullOrEmpty()) { - // 记录已显示的游戏 id - for (game in gameSubject.data!!) { - displayingGameIdSet.add(game.id) - } - - // 替换游戏 - substituteGameIfNeeded(gameSubject) - - if (gameSubject.tag == "update") { - // 优先显示更新标签 - gameSubject.data?.forEach { - it.tagStyle.clear() - it.tagStyle.add( - TagStyleEntity( - id = "local_generated", - name = TimeUtils.getFormatTime(it.updateTime, "MM-dd") + " 更新", - color = "1383EB", - background = "E8F3FF", - column = "1383EB" - ) - ) - } - } - - when (gameSubject.type) { - COMPONENTS_GAME_SUBJECT_TYPE_DOUBLE_CARD, COMPONENTS_SUBJECT_TYPE_DOUBLE_GAME_WELFARE_CARD -> { - // 双列卡片 双列福利卡片 - val gameCount = gameSubject.data?.size ?: 0 - if (gameCount >= COMPONENT_TYPE_COLUMN_LIMIT_TWO_COUNT) { - val subjectItems = convertSplitSubjectItems(item, 2, false) - list.addAll(subjectItems) - isAdded = true - } - } - - COMPONENTS_GAME_SUBJECT_TYPE_GAME_VERTICAL -> { - // 长列表式 - val subjectItems = convertSplitSubjectItems(item, 1, false) - list.addAll(subjectItems) - isAdded = true - } - - COMPONENTS_SUBJECT_TYPE_GAME_HORIZONTAL -> { - // 图标矩阵 - val subjectItems = convertSplitSubjectItems(item, 4, true) - list.addAll(subjectItems) - isAdded = true - } - - else -> { - if (gameSubject.type == COMPONENTS_GAME_SUBJECT_TYPE_GAME_VIDEO_HORIZONTAL_SLIDE || - gameSubject.type == COMPONENTS_SUBJECT_TYPE_GAME_FOLD_SLIDE - ) { - val gameCount = gameSubject.data?.size ?: 0 - if (gameCount >= COMPONENT_TYPE_COLUMN_LIMIT_TWO_COUNT) { - list.add( - CustomSubjectItem( - item.link, - gameSubject, - pageInfo.position, - pageInfo.componentPosition - ) - ) - pageInfo.positionIncrement() - isAdded = true - } - - } else { - val gameCount = gameSubject.data?.size ?: 0 - if (gameCount > 0) { - list.add( - CustomSubjectItem( - item.link, - gameSubject, - pageInfo.position, - pageInfo.componentPosition - ) - ) - pageInfo.positionIncrement() - isAdded = true - } - - } - - } - } - if (isAdded) { - pageInfo.componentPositionIncrement() - } + item.link.type == CUSTOM_LINK_TYPE_COLUMN + || item.link.type == CUSTOM_LINK_TYPE_QQ_MINI_GAME_COLUMN_DETAIL + || item.link.type == CUSTOM_LINK_TYPE_WECHAT_MINI_GAME_COLUMN_DETAIL -> { + val subItems = convertColumnDetailSubjectItems( + pageInfo.position, + pageInfo.componentPosition, + item.link, + item.gameSubjectEntity + ) + if (subItems.isNotEmpty()) { + list.addAll(subItems) + pageInfo.positionGetAndAdd(subItems.size) + pageInfo.componentPositionIncrement() } } + //QQ小游戏-最近在玩(需要用户登录才显示) item.link.type == CUSTOM_LINK_TYPE_QQ_GAME_RECENTLY_PLAYED -> { - //QQ小游戏-最近在玩(需要用户登录才显示) val linkQqGameRecentlyPlayed = item.linkQqGameRecentlyPlayed if (linkQqGameRecentlyPlayed != null) { recentQQItem = CustomRecentQqMiniGamesItem( @@ -386,8 +308,8 @@ class CustomPageRepository private constructor( } + // 微信小游戏-最近在玩 item.link.type == CUSTOM_LINK_TYPE_WECHAT_GAME_RECENTLY_PLAYED -> { - // 微信小游戏-最近在玩 recentWechatItem = CustomRecentWeChatMiniGamesItem( item.link, MiniGameRecentlyPlayUseCase.getRecentlyPlayedMiniGameList(Constants.WECHAT_MINI_GAME), @@ -398,6 +320,23 @@ class CustomPageRepository private constructor( pageInfo.componentPositionIncrement() } + // 微信小游戏CPM专题 + item.link.type == CUSTOM_LINK_TYPE_WECHAT_WECHAT_GAME_CPM_COLUMN_DETAIL -> { + item.gameSubjectEntity?.let { subject -> + list.add( + CustomWeChatMiniGamesCPMSubjectItem( + item.link, + subject, + pageInfo.position, + pageInfo.componentPosition + ) + ) + wGameSubjectCPMListUseCase.getWechatMiniGameCPMList(subject.id) + pageInfo.positionIncrement() + pageInfo.componentPositionIncrement() + } + } + item.linkColumnCollection != null -> { // 专题合集 val linkColumnCollection = item.linkColumnCollection @@ -475,7 +414,9 @@ class CustomPageRepository private constructor( || layout == COMMON_CONTENT_COLLECTION_LAYOUT_DOUBLE_ROW_VERTICAL_CARD || layout == COMMON_CONTENT_COLLECTION_LAYOUT_VERTICAL_IMAGE_TEXT ) { - list.addAll(convertSplitCommonContentCollection(item)) + val subItems = convertSplitCommonContentCollection(item) + list.addAll(subItems) + pageInfo.positionGetAndAdd(subItems.size) pageInfo.componentPositionIncrement() } else { var show = true @@ -528,12 +469,16 @@ class CustomPageRepository private constructor( // 最近在玩 val entities = VHelper.getSortedRecentlyPlayedList() recentItem = - CustomRecentGamesItem(item.link, entities, pageInfo.position, pageInfo.componentPosition) - .also { - list.add(it) - pageInfo.positionIncrement() - pageInfo.componentPositionIncrement() - } + CustomRecentGamesItem( + item.link, + entities, + pageInfo.position, + pageInfo.componentPosition + ).also { + list.add(it) + pageInfo.positionIncrement() + pageInfo.componentPositionIncrement() + } } item.link.type == "plugin_area" -> { @@ -666,45 +611,155 @@ class CustomPageRepository private constructor( } pageInfo.nextPage() + + return list + } + + fun convertColumnDetailSubjectItems( + position: Int, + componentPosition: Int, + link: LinkEntity, + subjectEntity: SubjectEntity?, + ): List { + + var currentPosition = position + val list = mutableListOf() + + // 游戏专题 + val gameSubject = subjectEntity?.also { + if (link.type == CUSTOM_LINK_TYPE_COLUMN) { + it.data?.forEach { game -> + game.gameLocation = GameEntity.GameLocation.INDEX + } + } + } + + if (gameSubject != null && !gameSubject.data.isNullOrEmpty()) { + // 记录已显示的游戏 id + for (game in gameSubject.data!!) { + displayingGameIdSet.add(game.id) + } + + // 替换游戏 + substituteGameIfNeeded(gameSubject) + + if (gameSubject.tag == "update") { + // 优先显示更新标签 + gameSubject.data?.forEach { + it.tagStyle.clear() + it.tagStyle.add( + TagStyleEntity( + id = "local_generated", + name = TimeUtils.getFormatTime(it.updateTime, "MM-dd") + " 更新", + color = "1383EB", + background = "E8F3FF", + column = "1383EB" + ) + ) + } + } + + when (gameSubject.type) { + COMPONENTS_GAME_SUBJECT_TYPE_DOUBLE_CARD, COMPONENTS_SUBJECT_TYPE_DOUBLE_GAME_WELFARE_CARD -> { + // 双列卡片 双列福利卡片 + val gameCount = gameSubject.data?.size ?: 0 + if (gameCount >= COMPONENT_TYPE_COLUMN_LIMIT_TWO_COUNT) { + val subjectItems = + convertSplitSubjectItems(link, subjectEntity, currentPosition, componentPosition, 2, false) + list.addAll(subjectItems) + currentPosition += subjectItems.size + } + } + + COMPONENTS_GAME_SUBJECT_TYPE_GAME_VERTICAL -> { + // 长列表式 + val subjectItems = + convertSplitSubjectItems(link, subjectEntity, currentPosition, componentPosition, 1, false) + list.addAll(subjectItems) + currentPosition += subjectItems.size + } + + COMPONENTS_SUBJECT_TYPE_GAME_HORIZONTAL -> { + // 图标矩阵 + val subjectItems = + convertSplitSubjectItems(link, subjectEntity, currentPosition, componentPosition, 4, true) + list.addAll(subjectItems) + currentPosition += subjectItems.size + } + + else -> { + if (gameSubject.type == COMPONENTS_GAME_SUBJECT_TYPE_GAME_VIDEO_HORIZONTAL_SLIDE || + gameSubject.type == COMPONENTS_SUBJECT_TYPE_GAME_FOLD_SLIDE + ) { + val gameCount = gameSubject.data?.size ?: 0 + if (gameCount >= COMPONENT_TYPE_COLUMN_LIMIT_TWO_COUNT) { + list.add( + CustomSubjectItem( + link, + gameSubject, + currentPosition, + componentPosition + ) + ) + } + + } else { + val gameCount = gameSubject.data?.size ?: 0 + if (gameCount > 0) { + list.add( + CustomSubjectItem( + link, + gameSubject, + currentPosition, + componentPosition + ) + ) + } + } + } + } + } return list } private fun convertSplitSubjectItems( - item: CustomPageData.CustomsComponent, + link: LinkEntity, + subjectEntity: SubjectEntity?, + position: Int, + componentPosition: Int, stepNum: Int, isMustFullyCover: Boolean ): List { - val gameSubject = item.gameSubjectEntity ?: return emptyList() + val gameSubject = subjectEntity ?: return emptyList() val items = arrayListOf() val games = gameSubject.data ?: emptyList() + var currentPosition = position (games.indices step stepNum).forEach { start -> if (isMustFullyCover) { if (start + stepNum - 1 < games.size) { items.add( CustomSplitSubjectItem( - item.link, + link, gameSubject, - pageInfo.position, - pageInfo.componentPosition, + currentPosition++, + componentPosition, stepNum, start ) ) - pageInfo.positionIncrement() } } else { items.add( CustomSplitSubjectItem( - item.link, + link, gameSubject, - pageInfo.position, - pageInfo.componentPosition, + currentPosition++, + componentPosition, stepNum, start ) ) - pageInfo.positionIncrement() } } items.forEach { @@ -729,7 +784,6 @@ class CustomPageRepository private constructor( left ) ) - pageInfo.positionIncrement() } return items } @@ -742,12 +796,20 @@ class CustomPageRepository private constructor( } } - fun notifyPositionChanged(offset: Int) { - pageInfo.position += offset + fun notifyPositionAdded(offset: Int) { + pageInfo.positionGetAndAdd(offset) + } + + fun notifyPositionChanged(value: Int) { + pageInfo.position = value } fun loadChangeSubjectGame(subjectEntity: SubjectEntity): Observable> = - remoteDataSource.loadChangeSubjectGame(subjectEntity) + if (subjectEntity.isWechatColumnCPM) {// 微信小游戏CPM专题的“换一批”接口 + wGameSubjectCPMRemoteDataSource.getRecommendCPMList(2, 10).toObservable() + } else { + remoteDataSource.loadChangeSubjectGame(subjectEntity) + } .map(RegionSettingHelper.filterGame) .map(ApkActiveUtils.filterMapperList) @@ -798,16 +860,16 @@ class CustomPageRepository private constructor( val page: Int get() = _page - private var _position: Int = 0 + private var _position: AtomicInteger = AtomicInteger(0) var position: Int - get() = _position + get() = _position.get() set(value) { - _position = value + _position.set(value) } - private var _componentPosition = 0 + private var _componentPosition: AtomicInteger = AtomicInteger(0) val componentPosition: Int - get() = _componentPosition + get() = _componentPosition.get() fun nextPage() { @@ -815,17 +877,25 @@ class CustomPageRepository private constructor( } fun positionIncrement() { - _position++ + positionGetAndAdd(1) } fun componentPositionIncrement() { - _componentPosition++ + componentPositionGetAndAdd(1) + } + + fun positionGetAndAdd(value: Int) { + _position.getAndAdd(value) + } + + fun componentPositionGetAndAdd(value: Int) { + _componentPosition.getAndAdd(value) } fun reset() { _page = 1 - _position = 0 - _componentPosition = 0 + _position.set(0) + _componentPosition.set(0) } } @@ -844,7 +914,8 @@ class CustomPageRepository private constructor( RetrofitManager.getInstance().newApi, MainWrapperRepository.getInstance() ), - CustomPageLocalDataSource() + CustomPageLocalDataSource(), + WGameSubjectCPMRemoteDataSource() ) } } diff --git a/app/src/main/java/com/gh/gamecenter/minigame/MiniGameRecentlyPlayListAdapter.kt b/app/src/main/java/com/gh/gamecenter/minigame/MiniGameRecentlyPlayListAdapter.kt index cdb8a7e3a9..35f8833175 100644 --- a/app/src/main/java/com/gh/gamecenter/minigame/MiniGameRecentlyPlayListAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/minigame/MiniGameRecentlyPlayListAdapter.kt @@ -59,7 +59,7 @@ class MiniGameRecentlyPlayListAdapter( if (onItemClick != null) { onItemClick.invoke(entity, position) } else { - MiniGameItemHelper.launchMiniGame(entity.miniGameAppId, entity.miniGameType) + MiniGameItemHelper.launchMiniGame(entity) } } } diff --git a/app/src/main/java/com/gh/gamecenter/minigame/MiniGameSearchDefaultRankAdapter.kt b/app/src/main/java/com/gh/gamecenter/minigame/MiniGameSearchDefaultRankAdapter.kt index c635bfce44..5a72006a50 100644 --- a/app/src/main/java/com/gh/gamecenter/minigame/MiniGameSearchDefaultRankAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/minigame/MiniGameSearchDefaultRankAdapter.kt @@ -56,7 +56,7 @@ class MiniGameSearchDefaultRankAdapter( // 转成Game实体比较好处理数据 val trackGame = GameEntity( - id = rank.id, + _id = rank.id, mName = rank.name, miniGameAppId = rank.link.link ?: "", miniGameType = Constants.WECHAT_MINI_GAME, diff --git a/app/src/main/java/com/gh/gamecenter/minigame/MiniGameSearchResultRepository.kt b/app/src/main/java/com/gh/gamecenter/minigame/MiniGameSearchResultRepository.kt index 115fd2cedd..2ee2e575c5 100644 --- a/app/src/main/java/com/gh/gamecenter/minigame/MiniGameSearchResultRepository.kt +++ b/app/src/main/java/com/gh/gamecenter/minigame/MiniGameSearchResultRepository.kt @@ -2,14 +2,16 @@ package com.gh.gamecenter.minigame import com.gh.gamecenter.entity.SearchSubjectEntity import com.gh.gamecenter.feature.entity.GameEntity +import com.gh.gamecenter.minigame.wechat.WGameSubjectCPMRemoteDataSource import com.gh.gamecenter.retrofit.RetrofitManager import com.gh.gamecenter.retrofit.service.ApiService import com.gh.gamecenter.search.ISearchGameResultRepository import io.reactivex.Observable -import java.net.URLEncoder +import io.reactivex.Single class MiniGameSearchResultRepository( - private val api: ApiService = RetrofitManager.getInstance().newApi + private val api: ApiService = RetrofitManager.getInstance().newApi, + private val mWGameSubjectCPMDataSource: WGameSubjectCPMRemoteDataSource = WGameSubjectCPMRemoteDataSource() ) : ISearchGameResultRepository { override fun getSearchGame( @@ -22,4 +24,8 @@ class MiniGameSearchResultRepository( override fun getSearchSubject(key: String?, page: Int): Observable> { return Observable.just(emptyList()) } + + override fun getWGameCPMGameList(): Single> { + return mWGameSubjectCPMDataSource.getRecommendCPMList(1) + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/minigame/wechat/WGameSubjectCPMListRepository.kt b/app/src/main/java/com/gh/gamecenter/minigame/wechat/WGameSubjectCPMListRepository.kt new file mode 100644 index 0000000000..1c83f933fc --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/minigame/wechat/WGameSubjectCPMListRepository.kt @@ -0,0 +1,21 @@ +package com.gh.gamecenter.minigame.wechat + +import com.gh.gamecenter.entity.SubjectSettingEntity +import com.gh.gamecenter.feature.entity.GameEntity +import com.gh.gamecenter.subject.ISubjectListRepository +import io.reactivex.Observable +import io.reactivex.Single + +class WGameSubjectCPMListRepository( + private val dataSource: WGameSubjectCPMRemoteDataSource = WGameSubjectCPMRemoteDataSource() +) : ISubjectListRepository { + + override fun getColumn(column_id: String?, page: Int, sort: String?, order: String?): Single> { + return dataSource.getRecommendCPMList(page) + } + + override fun getColumnSettings(column_id: String?): Observable { + return Observable.just(SubjectSettingEntity()) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/minigame/wechat/WGameSubjectCPMListUseCase.kt b/app/src/main/java/com/gh/gamecenter/minigame/wechat/WGameSubjectCPMListUseCase.kt new file mode 100644 index 0000000000..cc07947422 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/minigame/wechat/WGameSubjectCPMListUseCase.kt @@ -0,0 +1,46 @@ +package com.gh.gamecenter.minigame.wechat + +import android.annotation.SuppressLint +import androidx.lifecycle.LiveData +import com.gh.gamecenter.common.livedata.NonStickyMutableLiveData +import com.gh.gamecenter.common.retrofit.BiResponse +import com.gh.gamecenter.feature.entity.GameEntity +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers + +/** + * 微信小游戏CPM-网域层 + */ +class WGameSubjectCPMListUseCase( + private val repository: WGameSubjectCPMListRepository = WGameSubjectCPMListRepository() +) { + + /** + * 微信专题CPM请求记录,用于避免重复请求,以专题ID作为Key + */ + private val requestKeyList = mutableListOf() + + /** + * 微信小游戏CPM列表,这里的LiveData充当类似于EventBus的角色,因此使用NonStickyMutableLiveData + */ + private val _wechatMiniGameCPMListLiveData = NonStickyMutableLiveData>>() + val wechatMiniGameCPMListLiveData: LiveData>> = _wechatMiniGameCPMListLiveData + + @SuppressLint("CheckResult") + fun getWechatMiniGameCPMList(subjectId: String?) { + if (subjectId.isNullOrEmpty() || requestKeyList.contains(subjectId)) { + return + } + + requestKeyList.add(subjectId) + repository.getColumn(null, 1, null, null) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : BiResponse>() { + override fun onSuccess(data: List) { + requestKeyList.remove(subjectId) + _wechatMiniGameCPMListLiveData.value = subjectId to data + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/minigame/wechat/WGameSubjectCPMRemoteDataSource.kt b/app/src/main/java/com/gh/gamecenter/minigame/wechat/WGameSubjectCPMRemoteDataSource.kt new file mode 100644 index 0000000000..0c6e8ee365 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/minigame/wechat/WGameSubjectCPMRemoteDataSource.kt @@ -0,0 +1,59 @@ +package com.gh.gamecenter.minigame.wechat + +import com.gh.common.constant.Config +import com.gh.gamecenter.common.constant.Constants +import com.gh.gamecenter.common.exposure.meta.MetaUtil +import com.gh.gamecenter.common.utils.toRequestBody +import com.gh.gamecenter.feature.entity.GameEntity +import com.gh.gamecenter.feature.entity.TagStyleEntity +import com.gh.gamecenter.retrofit.RetrofitManager +import com.gh.gamecenter.feature.retrofit.WGameCPMApiService +import io.reactivex.Single + +class WGameSubjectCPMRemoteDataSource( + private val api: WGameCPMApiService = RetrofitManager.getInstance().wGameCPMApi +) { + + fun getRecommendCPMList(page: Int, pageSize: Int = 10): Single> { + val meta = MetaUtil.getMeta() + val request = mapOf( + "head" to mapOf( + "busiAppid" to Config.WGAME_CPM_BUSIAPPID, + "oaid" to (meta.oaid ?: ""), + "manufacturer" to (meta.manufacturer ?: ""), + "mode" to (meta.model ?: ""), + "androidId" to (MetaUtil.getAndroidId()), + "imei" to (MetaUtil.getIMEI()) + ), + "body" to mapOf( + "page" to page - 1, + "pageSize" to pageSize, + ) + ) + return api.getUserRecommendList(request.toRequestBody()) + .map { + if (it.ret == 0) { + it.appInfoList.map { info -> + GameEntity( + mName = info.appName, + mIcon = info.logo, + mBrief = info.briefIntro, + miniGameUid = info.appID, + miniGameAppId = info.userName, + miniGameType = Constants.WECHAT_MINI_GAME_CPM, + miniGameAppStatus = 2, + miniGameAppPath = info.wechatAppPath, + miniGameExtData = info.extData, + miniGameRecommendId = info.recommendID, + mTagStyle = arrayListOf( + TagStyleEntity(name = info.categoryName), + TagStyleEntity(name = info.subcategoryName) + ) + ) + }.toMutableList() + } else { + mutableListOf() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/minigame/wechat/WGameSubjectCPMRepository.kt b/app/src/main/java/com/gh/gamecenter/minigame/wechat/WGameSubjectCPMRepository.kt new file mode 100644 index 0000000000..dd61e81f34 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/minigame/wechat/WGameSubjectCPMRepository.kt @@ -0,0 +1,17 @@ +package com.gh.gamecenter.minigame.wechat + +import com.gh.gamecenter.entity.SubjectSettingEntity +import com.gh.gamecenter.subject.ISubjectRepository +import io.reactivex.Observable +import okhttp3.MediaType +import okhttp3.ResponseBody + +class WGameSubjectCPMRepository : ISubjectRepository { + override fun getColumnSettings(column_id: String?): Observable { + return Observable.just(SubjectSettingEntity()) + } + + override fun getSubjectName(column_id: String?): Observable { + return Observable.just(ResponseBody.create(MediaType.parse("application/json"), "{\"name\": \"专题\"}")) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/qa/editor/GameDefaultAdapter.kt b/app/src/main/java/com/gh/gamecenter/qa/editor/GameDefaultAdapter.kt index 06fd013821..95b3b0c47e 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/editor/GameDefaultAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/editor/GameDefaultAdapter.kt @@ -40,7 +40,7 @@ class GameDefaultAdapter( val intent = Intent() intent.putExtra( GameEntity::class.java.simpleName, - GameEntity(id = entity.gameId, mIcon = entity.gameIcon, mName = entity.gameName, mCategory = entity.category) + GameEntity(_id = entity.gameId, mIcon = entity.gameIcon, mName = entity.gameName, mCategory = entity.category) ) (mContext as Activity).setResult(Activity.RESULT_OK, intent) (mContext as Activity).finish() diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/RetrofitManager.java b/app/src/main/java/com/gh/gamecenter/retrofit/RetrofitManager.java index 7d8f3fb14e..d9d6c37ce6 100644 --- a/app/src/main/java/com/gh/gamecenter/retrofit/RetrofitManager.java +++ b/app/src/main/java/com/gh/gamecenter/retrofit/RetrofitManager.java @@ -4,6 +4,7 @@ import android.content.Context; import com.gh.common.constant.Config; import com.gh.gamecenter.common.retrofit.BaseRetrofitManager; +import com.gh.gamecenter.feature.retrofit.WGameCPMApiService; import com.gh.gamecenter.retrofit.service.ApiService; import com.gh.gamecenter.retrofit.service.VApiService; import com.halo.assistant.HaloApp; @@ -20,6 +21,7 @@ public class RetrofitManager extends BaseRetrofitManager { private final ApiService mNewApiService; private final ApiService mUploadApiService; private final VApiService mVApiService; + private final WGameCPMApiService mWGameCPMApiService; private RetrofitManager() { Context context = HaloApp.getInstance().getApplicationContext(); @@ -27,7 +29,8 @@ public class RetrofitManager extends BaseRetrofitManager { mApiService = provideService(okHttpNormalConfig, Config.API_HOST, ApiService.class); mNewApiService = provideService(okHttpNormalConfig, Config.NEW_API_HOST, ApiService.class); mUploadApiService = provideService(getOkHttpConfig(context, UPLOAD_CALL_TIME_OUT, 1), Config.API_HOST, ApiService.class); - mVApiService = provideService(okHttpNormalConfig, Config.VAPI_HOST, VApiService.class);; + mVApiService = provideService(okHttpNormalConfig, Config.VAPI_HOST, VApiService.class); + mWGameCPMApiService = provideService(okHttpNormalConfig, Config.WGAME_CPM_API_HOST, WGameCPMApiService.class); } public static RetrofitManager getInstance() { @@ -50,6 +53,10 @@ public class RetrofitManager extends BaseRetrofitManager { return mVApiService; } + public WGameCPMApiService getWGameCPMApi() { + return mWGameCPMApiService; + } + private static class SingletonHolder { private static final RetrofitManager INSTANCE = new RetrofitManager(); } diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java index 4fee92cc4c..27156754cc 100644 --- a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java +++ b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java @@ -3153,7 +3153,7 @@ public interface ApiService { /** * QQ小游戏-专题-换一换 */ - @GET("games/qq_mini/columns/{column_id}/games?page=1&page_size=30") + @GET("games/qq_mini/columns/{column_id}/games?page=2&page_size=30") Observable> getSubjectQGame(@Path("column_id") String columnId); /** @@ -3186,7 +3186,7 @@ public interface ApiService { /** * 微信小游戏-专题-换一换 */ - @GET("wechat_game/columns/{column_id}/games?page=1&page_size=30") + @GET("wechat_game/columns/{column_id}/games?page=2&page_size=30") Observable> getSubjectWGame(@Path("column_id") String columnId); /** diff --git a/app/src/main/java/com/gh/gamecenter/search/ISearchGameResultRepository.kt b/app/src/main/java/com/gh/gamecenter/search/ISearchGameResultRepository.kt index da9535d736..8fe78d65b0 100644 --- a/app/src/main/java/com/gh/gamecenter/search/ISearchGameResultRepository.kt +++ b/app/src/main/java/com/gh/gamecenter/search/ISearchGameResultRepository.kt @@ -3,9 +3,12 @@ package com.gh.gamecenter.search import com.gh.gamecenter.entity.SearchSubjectEntity import com.gh.gamecenter.feature.entity.GameEntity import io.reactivex.Observable +import io.reactivex.Single interface ISearchGameResultRepository { fun getSearchGame(key: String?, page: Int): Observable> fun getSearchSubject(key: String?, page: Int): Observable> + + fun getWGameCPMGameList(): Single> } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexItemViewHolder.kt index c776a1818c..78f0b890bc 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexItemViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexItemViewHolder.kt @@ -13,6 +13,7 @@ import com.gh.gamecenter.common.view.DrawableView import com.gh.gamecenter.databinding.SearchGameIndexItemBinding import com.gh.gamecenter.databinding.SearchSubjectItemBinding import com.gh.gamecenter.db.ISearchHistoryDao +import com.gh.gamecenter.entity.SubjectData import com.gh.gamecenter.feature.databinding.GameItemBinding import com.gh.gamecenter.feature.entity.GameEntity import com.gh.gamecenter.feature.exposure.ExposureEvent @@ -85,7 +86,7 @@ class SearchSubjectItemViewHolder(var binding: SearchSubjectItemBinding) : Recyc binding.run { subjectRv.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false) - subjectRv.adapter = SearchSubjectAdapter(context, entity.getFilterGame(), "($type-专题)") { + subjectRv.adapter = SearchSubjectAdapter(context, entity.getFilterGame(), "($type-专题)", key) { dao?.add(key) if (itemData.adConfig != null) { NewFlatLogUtils.logClickGameAd( @@ -119,7 +120,17 @@ class SearchSubjectItemViewHolder(var binding: SearchSubjectItemBinding) : Recyc headContainer.headActionTv.setOnClickListener { dao?.add(key) if (entity.columnId.isNotEmpty()) { - DirectUtils.directToSubject(context, entity.columnId, entity.name, "($type-专题)") + DirectUtils.directToSubject( + context, + entity.columnId, + entity.name, + "($type-专题)", + subjectType = if (entity.isWGameSubjectCPM) { + SubjectData.SubjectType.WECHAT_GAME_CPM + } else { + SubjectData.SubjectType.NORMAL + } + ) } else if (entity.adId.isNotEmpty() && entity.codeId.isNotEmpty()) { SubjectActivity.startAdSubjectActivity( context, 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 85ae8618b3..c4467320de 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameResultAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameResultAdapter.kt @@ -752,7 +752,7 @@ class SearchGameResultAdapter( gameEntity.name ?: "", gameEntity.categoryChinese ) - MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType) + MiniGameItemHelper.launchMiniGame(gameEntity) MiniGameItemHelper.trackMiniGameClick( gameEntity = gameEntity, location = "小游戏搜索结果列表", diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchGameResultRepository.kt b/app/src/main/java/com/gh/gamecenter/search/SearchGameResultRepository.kt index c0c1505931..5812acef8c 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameResultRepository.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameResultRepository.kt @@ -4,14 +4,17 @@ import com.gh.common.constant.Config import com.gh.gamecenter.BuildConfig import com.gh.gamecenter.entity.SearchSubjectEntity import com.gh.gamecenter.feature.entity.GameEntity +import com.gh.gamecenter.minigame.wechat.WGameSubjectCPMRemoteDataSource import com.gh.gamecenter.retrofit.RetrofitManager import com.gh.gamecenter.retrofit.service.ApiService import com.halo.assistant.HaloApp import io.reactivex.Observable +import io.reactivex.Single import java.net.URLEncoder class SearchGameResultRepository( - private val mApi: ApiService = RetrofitManager.getInstance().api + private val mApi: ApiService = RetrofitManager.getInstance().api, + private val mWGameSubjectCPMDataSource: WGameSubjectCPMRemoteDataSource = WGameSubjectCPMRemoteDataSource() ) : ISearchGameResultRepository { override fun getSearchGame( @@ -31,4 +34,8 @@ class SearchGameResultRepository( override fun getSearchSubject(key: String?, page: Int): Observable> { return mApi.getSearchSubject(key, page) } + + override fun getWGameCPMGameList(): Single> { + return mWGameSubjectCPMDataSource.getRecommendCPMList(1) + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchGameResultViewModel.kt b/app/src/main/java/com/gh/gamecenter/search/SearchGameResultViewModel.kt index 28c71384e3..4f23b81793 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameResultViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameResultViewModel.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModelProvider import com.gh.ad.AdDelegateHelper import com.gh.common.filter.RegionSettingHelper import com.gh.common.util.PackageHelper +import com.gh.gamecenter.SearchActivity import com.gh.gamecenter.common.base.GlobalActivityManager import com.gh.gamecenter.common.baselist.ListViewModel import com.gh.gamecenter.common.baselist.LoadParams @@ -22,7 +23,6 @@ import com.gh.gamecenter.entity.SearchSubjectEntity import com.gh.gamecenter.feature.entity.GameEntity import com.gh.gamecenter.minigame.MiniGameSearchResultRepository import com.gh.gamecenter.retrofit.RetrofitManager -import com.gh.gamecenter.SearchActivity import io.reactivex.Observable import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers @@ -58,10 +58,6 @@ class SearchGameResultViewModel( mSearchSubjects.clear() } - override fun loadData() { - super.loadData() - } - override fun mergeResultLiveData() { mResultLiveData.addSource(mListLiveData) { list -> mGameEntityList = ArrayList(list) @@ -80,31 +76,40 @@ class SearchGameResultViewModel( refreshWrongInstallStatus() repository.getSearchSubject(mSearchKey, mPage) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ mutableList -> - mSearchSubjects.addAll(mutableList) + .map { dataList -> + mSearchSubjects.addAll(dataList) + var cpmSearchSubject: SearchSubjectEntity? = null mSearchSubjects.forEach { - val item = SearchItemData(subject = it) - if (it.location <= 0 || it.location > itemDataList.size) { - itemDataList.add(item) + // 微信小游戏CPM专题需要等搜索广告位插入完成后再插入 + if (it.location == WGAME_CPM_SUBJECT_POSITION) { + cpmSearchSubject = it.apply { isWGameSubjectCPM = true } } else { - itemDataList.add(it.location - 1, item) + val item = SearchItemData(subject = it) + if (it.location <= 0 || it.location > itemDataList.size) { + itemDataList.add(item) + } else { + itemDataList.add(it.location - 1, item) + } } } + cpmSearchSubject to dataList + } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ result -> // 处理初始化列表且游戏列表size为0的情况 handleLoadStatusWhenGameListIsEmpty(list, itemDataList) if (mIsManuallySearch) { if (mSearchKey == AdDelegateHelper.gameSearchKeyword) { - updateAdConfigAndDecorateList(itemDataList, list) + updateAdConfigAndDecorateList(itemDataList, list, result.first) } else { AdDelegateHelper.requestAdConfig(false, mSearchKey ?: "") { - updateAdConfigAndDecorateList(itemDataList, list) + updateAdConfigAndDecorateList(itemDataList, list, result.first) } } } else { - postResultList(itemDataList, list) + decorateWithWGameSubjectCPM(itemDataList, list, result.first) } }, { it.printStackTrace() @@ -114,7 +119,11 @@ class SearchGameResultViewModel( } @SuppressLint("CheckResult") - private fun updateAdConfigAndDecorateList(itemDataList: ArrayList, list: MutableList) { + private fun updateAdConfigAndDecorateList( + itemDataList: ArrayList, + list: MutableList, + cpmSubjectEntity: SearchSubjectEntity? + ) { mGameSearchAdList = AdDelegateHelper.getGameSearchAdList().filter { AdDelegateHelper.shouldShowGameSearchAd(it) }.toArrayList() .apply { sortBy { it.position } } @@ -166,18 +175,18 @@ class SearchGameResultViewModel( Single.zip(requestSingleList) {} .compose(singleToMain()) .subscribe({ - decorateListWithAd(itemDataList, decoratedItemDataList, list) + decorateListWithAd(itemDataList, decoratedItemDataList, list, cpmSubjectEntity) }, { - decorateListWithAd(itemDataList, decoratedItemDataList, list) + decorateListWithAd(itemDataList, decoratedItemDataList, list, cpmSubjectEntity) }) } else { - decorateListWithAd(itemDataList, decoratedItemDataList, list) + decorateListWithAd(itemDataList, decoratedItemDataList, list, cpmSubjectEntity) } } else { - decorateListWithThirdPartyAdOnly(decoratedItemDataList, thirdPartyAdList, list) + decorateListWithThirdPartyAdOnly(decoratedItemDataList, thirdPartyAdList, list, cpmSubjectEntity) } } else { - postResultList(itemDataList, list) + decorateWithWGameSubjectCPM(itemDataList, list, cpmSubjectEntity) } } @@ -190,19 +199,21 @@ class SearchGameResultViewModel( private fun decorateListWithThirdPartyAdOnly( decoratedItemDataList: ArrayList, thirdPartyAdList: List, - list: List + list: List, + cpmSubjectEntity: SearchSubjectEntity? ) { thirdPartyAdList.forEach { 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) + decorateWithWGameSubjectCPM(decoratedItemDataList, list, cpmSubjectEntity) } private fun decorateListWithAd( itemDataList: ArrayList, decoratedItemDataList: ArrayList, - list: List + list: List, + cpmSubjectEntity: SearchSubjectEntity? ) { val adGameOneIdSet = HashSet() // 展示样式为单个游戏时记录游戏ID,避免重复 for ((index, position) in mAdPositionSet!!.withIndex()) { @@ -270,7 +281,41 @@ class SearchGameResultViewModel( break } } - postResultList(decoratedItemDataList, list) + decorateWithWGameSubjectCPM(decoratedItemDataList, list, cpmSubjectEntity) + } + + @SuppressLint("CheckResult") + private fun decorateWithWGameSubjectCPM( + resultList: ArrayList, + list: List, + cpmSubjectEntity: SearchSubjectEntity? + ) { + // 微信小游戏CPM专题搜索结果存在,则请求CPM接口获取微信小游戏列表数据,并将列表数据插入缓存的CPM专题中, + // 再根据location的值(固定为4)将CPM专题插入搜索结果列表中 + // 相关需求:https://jira.shanqu.cc/browse/GHZSCY-6710 + cpmSubjectEntity?.let { subject -> + if (subject.games.isNotEmpty()) { + Single.just(subject.games.toMutableList()) + } else { + repository.getWGameCPMGameList() + .onErrorReturnItem(mutableListOf()) + } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { + val cpmSearchItemData = SearchItemData(subject = subject.apply { games = it }) + if (subject.location <= 0 || subject.location > resultList.size) { + resultList.add(cpmSearchItemData) + } else { + resultList.add(subject.location - 1, cpmSearchItemData) + } + postResultList(resultList, list) + }, + { + postResultList(resultList, list) + }) + } ?: postResultList(resultList, list) } @SuppressLint("CheckResult") @@ -386,6 +431,7 @@ class SearchGameResultViewModel( companion object { const val AD_SUBJECT_GAME_MAX_COUNT = 8 + const val WGAME_CPM_SUBJECT_POSITION = 4 } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchSubjectAdapter.kt b/app/src/main/java/com/gh/gamecenter/search/SearchSubjectAdapter.kt index c03c9212dc..7e54d0ae79 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchSubjectAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchSubjectAdapter.kt @@ -6,6 +6,7 @@ import com.gh.gamecenter.GameDetailActivity import com.gh.gamecenter.common.utils.dip2px import com.gh.gamecenter.common.utils.toBinding import com.gh.gamecenter.feature.entity.GameEntity +import com.gh.gamecenter.feature.minigame.MiniGameItemHelper import com.gh.gamecenter.game.horizontal.GameHorizontalSimpleItemViewHolder import com.lightgame.adapter.BaseRecyclerAdapter @@ -13,6 +14,7 @@ class SearchSubjectAdapter( context: Context, private val mList: List, private val mEntrance: String, + private val mKey: String, private val clickCallback: ((GameEntity) -> Unit) ) : BaseRecyclerAdapter(context) { @@ -34,7 +36,16 @@ class SearchSubjectAdapter( GameHorizontalSimpleItemViewHolder.setHorizontalNameAndGravity(gameName, gameEntity.name) root.setOnClickListener { clickCallback.invoke(gameEntity) - GameDetailActivity.startGameDetailActivity(mContext, gameEntity.id, mEntrance, gameEntity.exposureEvent) + if (gameEntity.isMiniGame()) { + MiniGameItemHelper.launchMiniGame(gameEntity) + MiniGameItemHelper.trackMiniGameClick( + gameEntity = gameEntity, + location = "小游戏搜索结果列表", + searchContent = mKey, + ) + } else { + GameDetailActivity.startGameDetailActivity(mContext, gameEntity.id, mEntrance, gameEntity.exposureEvent) + } } } } diff --git a/app/src/main/java/com/gh/gamecenter/subject/SubjectAdapter.kt b/app/src/main/java/com/gh/gamecenter/subject/SubjectAdapter.kt index 0951768a9b..72be7dc82a 100644 --- a/app/src/main/java/com/gh/gamecenter/subject/SubjectAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/subject/SubjectAdapter.kt @@ -228,7 +228,7 @@ class SubjectAdapter( DataCollectionUtils.uploadClick(mContext, "列表", subjectData.subjectName, gameEntity.name) if (gameEntity.isMiniGame()) { - MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType) + MiniGameItemHelper.launchMiniGame(gameEntity) val pageLocation = mViewModel.pageLocation MiniGameItemHelper.trackMiniGameClick( gameEntity = gameEntity, diff --git a/app/src/main/java/com/gh/gamecenter/subject/SubjectRepositoryFactory.kt b/app/src/main/java/com/gh/gamecenter/subject/SubjectRepositoryFactory.kt index e1033b6f60..085e5890f6 100644 --- a/app/src/main/java/com/gh/gamecenter/subject/SubjectRepositoryFactory.kt +++ b/app/src/main/java/com/gh/gamecenter/subject/SubjectRepositoryFactory.kt @@ -3,6 +3,8 @@ package com.gh.gamecenter.subject import com.gh.gamecenter.entity.SubjectData import com.gh.gamecenter.minigame.qq.QGameSubjectListRepository import com.gh.gamecenter.minigame.qq.QGameSubjectRepository +import com.gh.gamecenter.minigame.wechat.WGameSubjectCPMListRepository +import com.gh.gamecenter.minigame.wechat.WGameSubjectCPMRepository import com.gh.gamecenter.minigame.wechat.WGameSubjectListRepository import com.gh.gamecenter.minigame.wechat.WGameSubjectRepository @@ -10,12 +12,14 @@ object SubjectRepositoryFactory { fun createRepo(subjectType: SubjectData.SubjectType): ISubjectRepository = when(subjectType) { SubjectData.SubjectType.QQ_GAME -> QGameSubjectRepository() SubjectData.SubjectType.WECHAT_GAME -> WGameSubjectRepository() + SubjectData.SubjectType.WECHAT_GAME_CPM -> WGameSubjectCPMRepository() else -> SubjectRepository() } fun createListRepo(subjectType: SubjectData.SubjectType): ISubjectListRepository = when(subjectType) { SubjectData.SubjectType.QQ_GAME -> QGameSubjectListRepository() SubjectData.SubjectType.WECHAT_GAME -> WGameSubjectListRepository() + SubjectData.SubjectType.WECHAT_GAME_CPM -> WGameSubjectCPMListRepository() else -> SubjectListRepository() } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 6a2ed63af4..6836ecaf40 100644 --- a/gradle.properties +++ b/gradle.properties @@ -59,6 +59,9 @@ LOG_HUB_PROJECT_GAT=ghzs-global DEV_CSJ_APPID=5410486 CSJ_APPID=5429125 +WGAME_CPM_BUSIAPPID=dl5b0ccbd8 +WGAME_CPM_API_HOST=https://mrj.20130123.com/dlwxgame/api/ + # hosts DEV_API_HOST=https\://dev-and-api.ghzs6.com/v5d5d0/ API_HOST=https\://and-api.ghzs6.com/v5d5d0/ diff --git a/module_common/src/main/java/com/gh/gamecenter/common/constant/Constants.java b/module_common/src/main/java/com/gh/gamecenter/common/constant/Constants.java index b31a615502..8e3d3c21fc 100644 --- a/module_common/src/main/java/com/gh/gamecenter/common/constant/Constants.java +++ b/module_common/src/main/java/com/gh/gamecenter/common/constant/Constants.java @@ -78,6 +78,7 @@ public class Constants { public static final String QQ_MINI_GAME = "qq"; public static final String WECHAT_MINI_GAME = "wechat"; + public static final String WECHAT_MINI_GAME_CPM = "wechat_cpm"; /** * 微信小游戏PCS参数 */ diff --git a/module_common/src/main/java/com/gh/gamecenter/common/entity/ExposureEntity.kt b/module_common/src/main/java/com/gh/gamecenter/common/entity/ExposureEntity.kt index 2143ad9344..903853c491 100644 --- a/module_common/src/main/java/com/gh/gamecenter/common/entity/ExposureEntity.kt +++ b/module_common/src/main/java/com/gh/gamecenter/common/entity/ExposureEntity.kt @@ -30,10 +30,14 @@ data class ExposureEntity( val displayType: String? = "", @SerializedName("is_platform_recommend") val isPlatformRecommend: Boolean? = false, + @SerializedName("mini_game_uid") + val miniGameUid: String? = "", @SerializedName("mini_game_id") val miniGameId: String? = "",// 小游戏ID @SerializedName("mini_game_type") val miniGameType: String? = "",// 小游戏类型:QQ小游戏:qq 微信小游戏:wechat + @SerializedName("mini_game_recommend_id") + val miniGameRecommendId: String? = "", var speed: Long = 0, var certification: Int? = null, // 0表示未实名,1表示未成年,2表示成年 diff --git a/module_common/src/main/java/com/gh/gamecenter/common/utils/EnvHelper.kt b/module_common/src/main/java/com/gh/gamecenter/common/utils/EnvHelper.kt index 754f649467..bd25c31955 100644 --- a/module_common/src/main/java/com/gh/gamecenter/common/utils/EnvHelper.kt +++ b/module_common/src/main/java/com/gh/gamecenter/common/utils/EnvHelper.kt @@ -92,6 +92,21 @@ object EnvHelper { } } + @JvmStatic + fun getWGameCPMHost(): String { + val buildConfig = + ARouter.getInstance().build(RouteConsts.provider.buildConfig).navigation() as? IBuildConfigProvider + return buildConfig?.getWGameCPMApiHost() ?: "" + } + + @JvmStatic + fun getWGameCPMBusiAppId(): String { + val buildConfig = + ARouter.getInstance().build(RouteConsts.provider.buildConfig).navigation() as? IBuildConfigProvider + return buildConfig?.getWGameCPMBusiAppId() ?: "" + } + + fun showChangeChannelDialog(context: Context, restartAfterChanges: Boolean = false) { val appProvider = ARouter.getInstance().build(RouteConsts.provider.app).navigation() as? IAppProvider val layout = LinearLayout(context).apply { diff --git a/module_core/src/main/java/com/gh/gamecenter/core/provider/IBuildConfigProvider.kt b/module_core/src/main/java/com/gh/gamecenter/core/provider/IBuildConfigProvider.kt index e6f939da66..ca4fe430e6 100644 --- a/module_core/src/main/java/com/gh/gamecenter/core/provider/IBuildConfigProvider.kt +++ b/module_core/src/main/java/com/gh/gamecenter/core/provider/IBuildConfigProvider.kt @@ -25,5 +25,9 @@ interface IBuildConfigProvider : IProvider { fun getVDevApiHost(): String + fun getWGameCPMApiHost(): String + fun getLogProducerProject(): String + + fun getWGameCPMBusiAppId(): String } \ No newline at end of file diff --git a/module_core/src/main/java/com/gh/gamecenter/core/provider/IDirectProvider.kt b/module_core/src/main/java/com/gh/gamecenter/core/provider/IDirectProvider.kt index 1329142080..0b9cea9431 100644 --- a/module_core/src/main/java/com/gh/gamecenter/core/provider/IDirectProvider.kt +++ b/module_core/src/main/java/com/gh/gamecenter/core/provider/IDirectProvider.kt @@ -56,5 +56,10 @@ interface IDirectProvider : IProvider { fun directToQQGameById(activity: Activity, qqAppId: String) - fun directToWechatGameById(activity: Activity, qqAppId: String) + fun directToWechatGameById( + activity: Activity, + wechatAppId: String, + wechatAppPath: String, + wechatAppExtData: String + ) } \ No newline at end of file diff --git a/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/GameEntity.kt b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/GameEntity.kt index d8246f7ad3..84555979ee 100644 --- a/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/GameEntity.kt +++ b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/GameEntity.kt @@ -27,7 +27,7 @@ import java.util.* @Parcelize data class GameEntity( @SerializedName("_id") - var id: String = "", + private var _id: String = "", @SerializedName("icon") private var mIcon: String? = null, @SerializedName("ori_icon") @@ -284,18 +284,26 @@ data class GameEntity( @SerializedName("message_private_id") var messageId: String = "", + // 小游戏服务商ID,目前仅用于微信小游戏CPM + var miniGameUid: String = "", // 小游戏ID,仅用于小游戏 @SerializedName("appid") var miniGameAppId: String = "", // 小游戏状态(1:下架 2:秒玩),仅用于小游戏 @SerializedName("app_status") var miniGameAppStatus: Int = 0, - // 小游戏类型(qq/wechat),仅用于小游戏 + // 小游戏类型(qq/wechat/wechat_cpm),仅用于小游戏 @SerializedName("game_type") var miniGameType: String = "", // 小游戏链接URL,仅用于小游戏 @SerializedName("appidLink") var miniGameAppLink: String = "", + // 小游戏跳转path,目前仅用于微信小游戏CPM + var miniGameAppPath: String = "", + // 小游戏跳转extData,目前仅用于微信小游戏CPM + var miniGameExtData: String = "", + // 小游戏广告推荐ID,目前仅用于微信小游戏CPM + var miniGameRecommendId: String = "", // 使用人数,仅用于微信小游戏 var usage: Int = 0, // 游戏封面图,仅用于微信小游戏 @@ -380,11 +388,11 @@ data class GameEntity( ) : Parcelable { constructor(id: String?) : this() { - this.id = id ?: "empty gameId" + this._id = id ?: "empty gameId" } constructor(id: String?, name: String?) : this() { - this.id = id ?: "empty gameId, it's name is $name" + this._id = id ?: "empty gameId, it's name is $name" this.mName = name } @@ -399,6 +407,10 @@ data class GameEntity( val assignRemark: AssignRemark get() = _assignRemark ?: AssignRemark() + var id: String + set(value) { _id = value } + get() = if (isWechatMiniGameCPM()) miniGameAppId else _id + @IgnoredOnParcel private var entryMap: androidx.collection.ArrayMap? = androidx.collection.ArrayMap() @@ -447,7 +459,7 @@ data class GameEntity( .build(RouteConsts.provider.regionSettingHelper) .navigation() as? IRegionSettingHelperProvider - return when (regionSettingProvider?.getMirrorPosition(id)) { + return when (regionSettingProvider?.getMirrorPosition(_id)) { 1 -> mMirrorData 2 -> mMirrorData2 else -> null @@ -456,7 +468,7 @@ data class GameEntity( @IgnoredOnParcel var recommendText: String - get() = if (isWechatMiniGame()) { + get() = if (isWechatMiniGame() || isWechatMiniGameCPM()) { brief ?: "" } else { _recommendText @@ -800,6 +812,11 @@ data class GameEntity( */ fun isWechatMiniGame(): Boolean = isMiniGame() && miniGameType == Constants.WECHAT_MINI_GAME + /** + * 当前游戏是否为微信小游戏CPM + */ + fun isWechatMiniGameCPM(): Boolean = isMiniGame() && miniGameType == Constants.WECHAT_MINI_GAME_CPM + /** * 当前小游戏是否下架 */ @@ -827,7 +844,7 @@ data class GameEntity( val provider = ARouter.getInstance().build(RouteConsts.provider.regionSettingHelper) .navigation() as? IRegionSettingHelperProvider useMirrorInfo = - (mirrorStatus == "on" || mirrorStatus2 == "on") && provider?.shouldThisGameDisplayMirrorInfo(id) == true + (mirrorStatus == "on" || mirrorStatus2 == "on") && provider?.shouldThisGameDisplayMirrorInfo(_id) == true } return useMirrorInfo @@ -841,7 +858,7 @@ data class GameEntity( val provider = ARouter.getInstance().build(RouteConsts.provider.regionSettingHelper) .navigation() as? IRegionSettingHelperProvider - return provider?.getMirrorPosition(id) ?: -1 + return provider?.getMirrorPosition(_id) ?: -1 } /** @@ -972,7 +989,7 @@ data class GameEntity( fun isSpecialDownload(): Boolean { val provider = ARouter.getInstance().build(RouteConsts.provider.regionSettingHelper) .navigation() as? IRegionSettingHelperProvider - return provider?.shouldThisGameShowSpecialDownload(id) == true + return provider?.shouldThisGameShowSpecialDownload(_id) == true } /** @@ -1014,7 +1031,7 @@ data class GameEntity( fun toSimpleGame(): SimpleGame { val simpleGame = SimpleGame() - simpleGame.id = id + simpleGame.id = _id simpleGame.mName = mName simpleGame.mIcon = mIcon simpleGame.mRawIcon = mRawIcon @@ -1027,7 +1044,7 @@ data class GameEntity( fun convertSimulatorGameRecordEntity(): SimulatorGameRecordEntity { val entity = SimulatorGameRecordEntity() - entity.id = id + entity.id = _id entity.brief = brief entity.des = des entity.icon = rawIcon diff --git a/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/WXMiniGameCPMEntity.kt b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/WXMiniGameCPMEntity.kt new file mode 100644 index 0000000000..33e192b638 --- /dev/null +++ b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/WXMiniGameCPMEntity.kt @@ -0,0 +1,91 @@ +package com.gh.gamecenter.feature.entity + +/** + * 微信小游戏CPM响应实体 + */ +data class WXMiniGameCPMEntity( + + /** + * 服务器响应状态码 + * 0-成功 + * 101-业务appid有误 + * 102-数量超限 + * 103-列表为空 + * -1-请求数据错误 + * -2-服务内部错误 + * -3-后端服务错误 + */ + val ret: Int = 0, + + /** + * 微信小游戏列表 + */ + val appInfoList: List = emptyList() + +) { + + /** + * 微信小游戏信息 + */ + data class AppInfoList( + /** + * 游戏ID,如"wx******" + */ + val appID: String = "", + + /** + * 游戏原始ID,如"gh_***",用于sdk跳转 + */ + val userName: String = "", + + /** + * 游戏名称 + */ + val appName: String = "", + + /** + * 游戏简介 + */ + val briefIntro: String = "", + + /** + * 游戏logo + */ + val logo: String = "", + + /** + * 游戏圆形logo + */ + val logoSquare: String = "", + + /** + * 评分,5分制 + */ + val score: Float = 0F, + + /** + * XX人玩过的枚举值1:数量<100000;2:<数量1000000;3:数量>=1000000 + */ + val actInfo: Int = 0, + + /** + * 小游戏跳转path,用于sdk跳转 + */ + val wechatAppPath: String = "", + + /** + * 游戏跳转extData,JSON格式,用于sdk跳转 + */ + val extData: String = "", + + /** + * 广告计费串,用于曝光/点击上报接 + */ + val recommendID: String = "", + + val categoryName: String = "", + + val subcategoryName: String = "" + ) + +} \ No newline at end of file diff --git a/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/WXMiniGameCPMResponse.kt b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/WXMiniGameCPMResponse.kt new file mode 100644 index 0000000000..a08a05b176 --- /dev/null +++ b/module_core_feature/src/main/java/com/gh/gamecenter/feature/entity/WXMiniGameCPMResponse.kt @@ -0,0 +1,6 @@ +package com.gh.gamecenter.feature.entity + +data class WXMiniGameCPMResponse( + val ret: Int = 0, + val msg: String = "" +) \ No newline at end of file diff --git a/module_core_feature/src/main/java/com/gh/gamecenter/feature/exposure/ExposureEvent.kt b/module_core_feature/src/main/java/com/gh/gamecenter/feature/exposure/ExposureEvent.kt index e07bc864ab..95e06db239 100644 --- a/module_core_feature/src/main/java/com/gh/gamecenter/feature/exposure/ExposureEvent.kt +++ b/module_core_feature/src/main/java/com/gh/gamecenter/feature/exposure/ExposureEvent.kt @@ -112,8 +112,10 @@ data class ExposureEvent( controlLinkDesc = firstTracePayload?.controlLinkDesc, controlLinkName = firstTracePayload?.controlLinkName, controlLinkType = firstTracePayload?.controlLinkType, + miniGameUid = gameEntity?.miniGameUid ?: "", miniGameId = gameEntity?.miniGameAppId ?: "", miniGameType = gameEntity?.miniGameType ?: "", + miniGameRecommendId = gameEntity?.miniGameRecommendId ?: "", additional = gameEntity?.customPageTrackData?.toKV() ) this.id = UUID.randomUUID().toString() diff --git a/module_core_feature/src/main/java/com/gh/gamecenter/feature/minigame/MiniGameItemHelper.kt b/module_core_feature/src/main/java/com/gh/gamecenter/feature/minigame/MiniGameItemHelper.kt index 8dbd609965..80f03217cb 100644 --- a/module_core_feature/src/main/java/com/gh/gamecenter/feature/minigame/MiniGameItemHelper.kt +++ b/module_core_feature/src/main/java/com/gh/gamecenter/feature/minigame/MiniGameItemHelper.kt @@ -9,6 +9,7 @@ import com.gh.gamecenter.common.constant.RouteConsts import com.gh.gamecenter.common.utils.SensorsBridge import com.gh.gamecenter.core.provider.IDirectProvider import com.gh.gamecenter.feature.entity.GameEntity +import com.gh.gamecenter.feature.minigame.wechat.WGameSubjectCPMListReportHelper import com.gh.gamecenter.feature.utils.NewFlatLogUtils object MiniGameItemHelper { @@ -32,7 +33,16 @@ object MiniGameItemHelper { } } - fun launchMiniGame(miniAppId: String, miniAppType: String) { + fun launchMiniGame(gameEntity: GameEntity) { + launchMiniGame( + gameEntity.miniGameAppId, + gameEntity.miniGameType, + gameEntity.miniGameAppPath, + gameEntity.miniGameExtData + ) + } + + fun launchMiniGame(miniAppId: String, miniAppType: String, miniAppPath: String = "", miniAppExtData: String = "") { GlobalActivityManager.currentActivity?.let { activity -> val directProvider = ARouter .getInstance() @@ -41,7 +51,7 @@ object MiniGameItemHelper { if (miniAppType == Constants.QQ_MINI_GAME) { directProvider.directToQQGameById(activity, miniAppId) } else { - directProvider.directToWechatGameById(activity, miniAppId) + directProvider.directToWechatGameById(activity, miniAppId, miniAppPath, miniAppExtData) } } } @@ -61,42 +71,52 @@ object MiniGameItemHelper { columnPattern: String = "", searchContent: String = "", ) { - if (gameEntity.miniGameType == Constants.QQ_MINI_GAME) { - NewFlatLogUtils.logQGameClick(gameEntity.miniGameAppId, gameEntity.name) - SensorsBridge.trackQQGameClick( - bottomTab = bottomTab, - multiTabId = multiTabId, - multiTabName = multiTabName, - position = position, - tabContent = tabContent, - customPageId = customPageId, - customPageName = customPageName, - gameColumnId = gameColumnId, - gameColumnName = gameColumnName, - location = location, - columnPattern = columnPattern, - searchContent = searchContent, - gameId = gameEntity.id, - gameName = gameEntity.name ?: "", - ) - } else { - SensorsBridge.trackWechatGameClick( - bottomTab = bottomTab, - multiTabId = multiTabId, - multiTabName = multiTabName, - position = position, - tabContent = tabContent, - customPageId = customPageId, - customPageName = customPageName, - gameColumnId = gameColumnId, - gameColumnName = gameColumnName, - location = location, - columnPattern = columnPattern, - searchContent = searchContent, - gameId = gameEntity.id, - gameName = gameEntity.name ?: "" - ) + when (gameEntity.miniGameType) { + Constants.QQ_MINI_GAME -> { + NewFlatLogUtils.logQGameClick(gameEntity.miniGameAppId, gameEntity.name) + SensorsBridge.trackQQGameClick( + bottomTab = bottomTab, + multiTabId = multiTabId, + multiTabName = multiTabName, + position = position, + tabContent = tabContent, + customPageId = customPageId, + customPageName = customPageName, + gameColumnId = gameColumnId, + gameColumnName = gameColumnName, + location = location, + columnPattern = columnPattern, + searchContent = searchContent, + gameId = gameEntity.id, + gameName = gameEntity.name ?: "", + ) + } + else -> { + SensorsBridge.trackWechatGameClick( + bottomTab = bottomTab, + multiTabId = multiTabId, + multiTabName = multiTabName, + position = position, + tabContent = tabContent, + customPageId = customPageId, + customPageName = customPageName, + gameColumnId = gameColumnId, + gameColumnName = gameColumnName, + location = location, + columnPattern = columnPattern, + searchContent = searchContent, + gameId = gameEntity.id, + gameName = gameEntity.name ?: "" + ) + if (gameEntity.miniGameType == Constants.WECHAT_MINI_GAME_CPM) { + WGameSubjectCPMListReportHelper.reportClick( + miniAppUid = gameEntity.miniGameUid, + gameName = gameEntity.name ?: "", + operateTime = System.currentTimeMillis() / 1000, + recommendId = gameEntity.miniGameRecommendId + ) + } + } } - } } \ No newline at end of file diff --git a/module_core_feature/src/main/java/com/gh/gamecenter/feature/minigame/wechat/WGameSubjectCPMListReportHelper.kt b/module_core_feature/src/main/java/com/gh/gamecenter/feature/minigame/wechat/WGameSubjectCPMListReportHelper.kt new file mode 100644 index 0000000000..c08c6a8812 --- /dev/null +++ b/module_core_feature/src/main/java/com/gh/gamecenter/feature/minigame/wechat/WGameSubjectCPMListReportHelper.kt @@ -0,0 +1,176 @@ +package com.gh.gamecenter.feature.minigame.wechat + +import android.annotation.SuppressLint +import com.gh.gamecenter.common.exposure.meta.MetaUtil +import com.gh.gamecenter.common.retrofit.BiResponse +import com.gh.gamecenter.common.utils.EnvHelper +import com.gh.gamecenter.common.utils.FixedSizeLinkedHashSet +import com.gh.gamecenter.common.utils.toRequestBody +import com.gh.gamecenter.core.AppExecutor +import com.gh.gamecenter.feature.entity.WXMiniGameCPMResponse +import com.gh.gamecenter.feature.exposure.ExposureEvent +import com.gh.gamecenter.feature.retrofit.RetrofitManager +import com.lightgame.utils.Utils +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers + +object WGameSubjectCPMListReportHelper { + + private val clickSet by lazy { hashSetOf() } + + private val exposureSet by lazy { hashSetOf>() } + private val exposureRequestSet by lazy { hashSetOf() } + private val exposureCacheSet by lazy { FixedSizeLinkedHashSet(100) } + + fun reportClick( + miniAppUid: String, + gameName: String, + operateTime: Long, + recommendId: String + ) { + AppExecutor.logExecutor.execute { + clickSet.add( + WGSubjectReport( + appId = miniAppUid, + gameName = gameName, + operateTime = operateTime, + recommendId = recommendId, + posCard = 0, + posInCard = 0 + ) + ) + if (exposureRequestSet.contains(recommendId)) { + Utils.log( + "WXGameCPMReport", + "当前微信CPM小游戏点击事件对应的曝光事件处于提交状态,将延迟到曝光事件提交后上报:$gameName, $recommendId" + ) + } + commitReportClick() + } + + } + + @SuppressLint("CheckResult") + private fun commitReportClick() { + AppExecutor.logExecutor.execute { + val reportClickSet = clickSet + .filterNot { + exposureRequestSet.contains(it.recommendId) + } + report( + reportClickSet.map { + Utils.log( + "WXGameCPMReport", + "将微信CPM小游戏加入点击事件队列:${it.gameName}, ${it.recommendId}" + ) + mapOf( + "appID" to it.appId, + "operateTime" to it.operateTime, + "recommendID" to it.recommendId, + "posCard" to it.posCard, + "posInCard" to it.posInCard + ) + }, + WGSubjectCPMReportType.CLICK + ) + clickSet.removeAll(reportClickSet.toSet()) + } + } + + fun reportExposure(exposure: ExposureEvent) { + val recommendId = exposure.payload.miniGameRecommendId ?: return + val gameName = exposure.payload.gameName ?: "" + if (exposureCacheSet.contains(recommendId)) { + Utils.log("WXGameCPMReport", "过滤重复曝光的微信CPM小游戏:$gameName, $recommendId") + return + } + exposureSet.add( + mapOf( + "appID" to (exposure.payload.miniGameUid ?: ""), + "operateTime" to exposure.timeInMillisecond / 1000, + "recommendID" to recommendId, + "posCard" to 0, + "posInCard" to 0 + ) + ) + exposureRequestSet.add(recommendId) + exposureCacheSet.add(recommendId) + Utils.log("WXGameCPMReport", "将微信CPM小游戏加入曝光事件队列:$gameName, $recommendId") + commitReportExposure() + } + + fun reportExposure(exposureSet: Set) { + exposureSet.forEach { reportExposure(it) } + } + + @SuppressLint("CheckResult") + private fun commitReportExposure() { + AppExecutor.logExecutor.execute { + if (exposureSet.isEmpty()) { + return@execute + } + report( + exposureSet.toList(), + WGSubjectCPMReportType.EXPOSURE + ) + exposureSet.clear() + } + } + + @SuppressLint("CheckResult") + private fun report(list: List>, type: WGSubjectCPMReportType) { + if (list.isEmpty()) return + val meta = MetaUtil.getMeta() + val request = mapOf( + "head" to mapOf( + "busiAppid" to EnvHelper.getWGameCPMBusiAppId(), + "oaid" to (meta.oaid ?: ""), + "manufacturer" to (meta.manufacturer ?: ""), + "mode" to (meta.model ?: ""), + "androidId" to (MetaUtil.getAndroidId()), + "imei" to (MetaUtil.getIMEI()) + ), + "body" to mapOf( + "appList" to list + ) + ) + val observable = if (type == WGSubjectCPMReportType.EXPOSURE) { + RetrofitManager.getInstance() + .wGameCPMApiService + .reportExposure(request.toRequestBody()) + .doOnSuccess { + val requestExposureIdSet = list.map { + it["recommendID"].toString() + }.toSet() + exposureRequestSet.removeAll(requestExposureIdSet) + commitReportClick() // 上报所有延迟提交的点击事件 + } + } else { + RetrofitManager.getInstance() + .wGameCPMApiService + .reportClick(request.toRequestBody()) + } + observable + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: WXMiniGameCPMResponse) { + if (data.ret == 0) { + val eventType = if (type == WGSubjectCPMReportType.CLICK) "点击" else "曝光" + Utils.log("WXGameCPMReport", "提交了${list.size}条${eventType}事件记录") + } + } + }) + } + + enum class WGSubjectCPMReportType { EXPOSURE, CLICK } + + class WGSubjectReport( + val appId: String = "", + val gameName: String = "", + val operateTime: Long = 0, + val recommendId: String = "", + val posCard: Int = 0, + val posInCard: Int = 0 + ) +} \ No newline at end of file diff --git a/module_core_feature/src/main/java/com/gh/gamecenter/feature/retrofit/RetrofitManager.kt b/module_core_feature/src/main/java/com/gh/gamecenter/feature/retrofit/RetrofitManager.kt index 2a0dea95ad..834335f675 100644 --- a/module_core_feature/src/main/java/com/gh/gamecenter/feature/retrofit/RetrofitManager.kt +++ b/module_core_feature/src/main/java/com/gh/gamecenter/feature/retrofit/RetrofitManager.kt @@ -9,12 +9,14 @@ class RetrofitManager private constructor() : BaseRetrofitManager() { val api: ApiService val newApi: ApiService + val wGameCPMApiService: WGameCPMApiService init { val context = HaloApp.getInstance().applicationContext val okHttpNormalConfig = getOkHttpConfig(context, 0, 2) api = provideService(okHttpNormalConfig, EnvHelper.getHost(), ApiService::class.java) newApi = provideService(okHttpNormalConfig, EnvHelper.getNewHost(), ApiService::class.java) + wGameCPMApiService = provideService(okHttpNormalConfig, EnvHelper.getWGameCPMHost(), WGameCPMApiService::class.java) } companion object : SingletonHolder(::RetrofitManager) diff --git a/module_core_feature/src/main/java/com/gh/gamecenter/feature/retrofit/WGameCPMApiService.kt b/module_core_feature/src/main/java/com/gh/gamecenter/feature/retrofit/WGameCPMApiService.kt new file mode 100644 index 0000000000..d5eee0606c --- /dev/null +++ b/module_core_feature/src/main/java/com/gh/gamecenter/feature/retrofit/WGameCPMApiService.kt @@ -0,0 +1,21 @@ +package com.gh.gamecenter.feature.retrofit + +import com.gh.gamecenter.feature.entity.WXMiniGameCPMEntity +import com.gh.gamecenter.feature.entity.WXMiniGameCPMResponse +import io.reactivex.Single +import okhttp3.RequestBody +import retrofit2.http.Body +import retrofit2.http.POST + +interface WGameCPMApiService { + + @POST("getuserrecommend") + fun getUserRecommendList(@Body body: RequestBody): Single + + @POST("reportclick") + fun reportClick(@Body body: RequestBody): Single + + @POST("reportexposure") + fun reportExposure(@Body body: RequestBody): Single + +} \ No newline at end of file