Merge branch 'feat/cw-apk-udpate' into 'release'

feat: 优化畅玩游戏更新逻辑

See merge request halo/android/assistant-android!1790
This commit is contained in:
陈君陶
2024-08-13 15:19:22 +08:00
6 changed files with 122 additions and 67 deletions

View File

@ -90,7 +90,7 @@ object PackageChangeHelper : DefaultLifecycleObserver {
pendingPackageTriple = null
pendingGhId = null
PackageRepository.addInstalledGame(packageName)
PackageRepository.addInstalledGame(PackageRepository.packageFilterManager, packageName)
// 添加到额外的包名白名单,下次启动同时查询此包的安装情况
PackageHelper.updateAdditionalWhiteListPackageName(packageName = packageName, isAdd = true)

View File

@ -546,6 +546,7 @@ object PackageHelper {
Utils.log(TAG, "addInstalledButMissingPackages 需要请求接口获取的包数量为 ${installedPackageNameSet.size}")
PackageRepository.addInstalledGames(
packageFilterManager = PackageRepository.packageFilterManager,
pkgNameList = ArrayList(installedPackageNameSet),
updateInstallStatus = true
)

View File

@ -11,11 +11,9 @@ import com.gh.gamecenter.room.AppDatabase
import com.halo.assistant.HaloApp
import io.reactivex.schedulers.Schedulers
object PackageFilterManager {
class PackageFilterManager {
private var mPackageKey = "" // 用于下次获取包名-游戏信息的 key
private val mPendingPackageNameSet by lazy { hashSetOf<String>() } // 因遇到异常而等待下次操作更新的包名列表
private val mValidPackageNameSet by lazy { hashSetOf<String>() } // 已被收录的游戏包名列表
val packageKey: String
get() = mPackageKey
@ -34,7 +32,7 @@ object PackageFilterManager {
) {
if (appendOnly) {
// 添加因为异常而没能正常更新的包名列表
packageList.addAll(mPendingPackageNameSet)
packageList.addAll(PackageRepository.mPendingPackageNameSet)
}
RetrofitManager.getInstance()
@ -44,12 +42,12 @@ object PackageFilterManager {
.subscribe(object : BiResponse<PackageFilter>() {
override fun onSuccess(data: PackageFilter) {
mPackageKey = data.key
mPendingPackageNameSet.clear()
PackageRepository.mPendingPackageNameSet.clear()
val partialPackageList = arrayListOf<String>()
if (!appendOnly) {
mValidPackageNameSet.clear()
PackageRepository.mValidPackageNameSet.clear()
tryWithDefaultCatch {
AppDatabase.getInstance().packageFilterDao().deleteAllPackageName()
}
@ -63,13 +61,13 @@ object PackageFilterManager {
}
partialPackageList.add(packageName)
mValidPackageNameSet.add(packageName)
PackageRepository.mValidPackageNameSet.add(packageName)
}
if (appendOnly) {
callbackClosure?.invoke(ArrayList(partialPackageList))
} else {
callbackClosure?.invoke(ArrayList(mValidPackageNameSet))
callbackClosure?.invoke(ArrayList(PackageRepository.mValidPackageNameSet))
}
}
@ -77,7 +75,7 @@ object PackageFilterManager {
super.onFailure(exception)
if (appendOnly) {
mPendingPackageNameSet.addAll(packageList)
PackageRepository.mPendingPackageNameSet.addAll(packageList)
} else {
if (exception is retrofit2.HttpException && exception.code() == 403) {
// 403 代表 key 过期,需要重新获取
@ -91,28 +89,13 @@ object PackageFilterManager {
for (packageEntity in packageEntityList) {
// 依然为已安装状态才加入到有效包名列表中
if (PackageUtils.isInstalled(HaloApp.getInstance(), packageEntity.packageName)) {
mValidPackageNameSet.add(packageEntity.packageName)
PackageRepository.mValidPackageNameSet.add(packageEntity.packageName)
}
}
callbackClosure?.invoke(ArrayList(mValidPackageNameSet))
callbackClosure?.invoke(ArrayList(PackageRepository.mValidPackageNameSet))
}
}
})
}
/**
* 该包名是否有效 (即是否已被光环收录)
*/
fun isPackageValid(packageName: String): Boolean {
return mValidPackageNameSet.contains(packageName)
}
/**
* 是否存在因为接口异常而导致没有查询收录情况的包名列表
*/
fun hasPendingPackage(): Boolean {
return mPendingPackageNameSet.isEmpty()
}
}

View File

@ -6,7 +6,6 @@ import android.text.TextUtils
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.gh.common.filter.RegionSettingHelper
import com.gh.gamecenter.feature.utils.ApkActiveUtils
import com.gh.common.util.GameUtils
import com.gh.common.util.PackageUtils
import com.gh.gamecenter.R
@ -16,19 +15,29 @@ import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.retrofit.ObservableUtil
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.secondOrNull
import com.gh.gamecenter.common.utils.toArrayList
import com.gh.gamecenter.common.utils.tryCatchInRelease
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.entity.AppEntity
import com.gh.gamecenter.entity.GameUpdateEntity
import com.gh.gamecenter.entity.PackageGame
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.GameInstall
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.feature.utils.ApkActiveUtils
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.packagehelper.PackageRepository.gameInstalled
import com.gh.gamecenter.packagehelper.PackageRepository.gameUpdate
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import io.reactivex.Single
import io.reactivex.SingleObserver
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import org.greenrobot.eventbus.EventBus
import org.json.JSONException
@ -74,6 +83,10 @@ object PackageRepository {
fun changeRecentVaPlayed() {
_recentVaPlayedChanged.postValue(Unit)
}
val packageFilterManager = PackageFilterManager()
var mPendingPackageNameSet = hashSetOf<String>() // 因遇到异常而等待下次操作更新的包名列表
var mValidPackageNameSet = hashSetOf<String>() // 已被收录的游戏包名列表
/**
* 预留方法,如果想手动初始化可以调用
@ -89,18 +102,52 @@ object PackageRepository {
if (gameUpdate.isNotEmpty()) gameUpdate.clear()
if (mInstalledPkgSet.isNotEmpty()) mInstalledPkgSet.clear()
val list = PackageUtils.getAllPackageName(mApplication)
Single.zip<Result<Any?>, Result<Any?>, Result<Any?>>(
Single.create { emitter ->
val list = PackageUtils.getAllPackageName(mApplication)
uploadAppList()
initFilterPackage(list) { filteredList ->
emitter.onSuccess(Result.success(null))
uploadAppList()
mInstalledPkgSet.addAll(filteredList)
notifyInstallPkgData()
loadInstalledGameDigestAndNotifyData(packageFilterManager.packageKey, filteredList)
}
initFilterPackage(list) { filteredList ->
mIsInitialisingData = false
mInstalledPkgSet.addAll(filteredList)
notifyInstallPkgData()
},
Single.create { emitter ->
// 畅玩游戏更新
var allGames = VHelper.getAllVGameSnapshots()
if (allGames.isEmpty()) {
VHelper.refreshVGameSnapshot()
allGames = VHelper.getAllVGameSnapshots()
}
val allGamePkgNames = allGames.map { it.packageName }.toArrayList()
if (allGamePkgNames.isNotEmpty()) {
val packageFilterManager = PackageFilterManager()
updateFilterPackage(packageFilterManager, allGamePkgNames) {
emitter.onSuccess(Result.success(null))
loadInstalledGameDigestAndNotifyData(
packageKey = packageFilterManager.packageKey,
filteredList = allGamePkgNames,
onWorkerThreadOnly = false,
isVGame = true
)
}
}
}
) { t1, t2 -> Result.success(null) }.subscribe(object : SingleObserver<Result<Any?>> {
override fun onSubscribe(d: Disposable) {
}
loadInstalledGameDigestAndNotifyData(filteredList)
}
override fun onSuccess(t: Result<Any?>) {
mIsInitialisingData = false
}
override fun onError(e: Throwable) {
}
})
loadGhzsUpdate()
}
@ -113,18 +160,15 @@ object PackageRepository {
list: MutableList<String>,
callbackClosure: ((list: ArrayList<String>) -> Unit)? = null
) {
PackageFilterManager.updateFilterPackages(list, false) {
callbackClosure?.invoke(it)
}
packageFilterManager.updateFilterPackages(list, false, callbackClosure)
}
private fun updateFilterPackage(
packageFilterManager: PackageFilterManager,
list: MutableList<String>,
callbackClosure: ((list: ArrayList<String>) -> Unit)? = null
) {
PackageFilterManager.updateFilterPackages(list, true) {
callbackClosure?.invoke(it)
}
packageFilterManager.updateFilterPackages(list, true, callbackClosure)
}
/**
@ -135,7 +179,8 @@ object PackageRepository {
PackageUtils.getGhVersionName(),
PackageUtils.getGhVersionCode(),
HaloApp.getInstance().channel,
Build.VERSION.SDK_INT)
Build.VERSION.SDK_INT
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<AppEntity>() {
@ -208,6 +253,7 @@ object PackageRepository {
*/
@SuppressLint("CheckResult")
private fun loadInstalledGameDigestAndNotifyData(
packageKey: String,
filteredList: ArrayList<String>,
isVGame: Boolean = false,
updateInstallStatus: Boolean = false
@ -222,7 +268,7 @@ object PackageRepository {
}, Any())
while (++page <= maxPageCount) {
var observable = mNewApi.getPackageGames(PackageFilterManager.packageKey, page, PAGE_SIZE)
var observable = mNewApi.getPackageGames(packageKey, page, PAGE_SIZE)
.subscribeOn(Schedulers.io())
observable.subscribe(object : BiResponse<List<PackageGame>>() {
@ -238,7 +284,8 @@ object PackageRepository {
}
for (game in validGames) {
val shouldNotifyChanges = validateGameAndPostChanges(gh_id, game, pkgName, isVGame, updateInstallStatus)
val shouldNotifyChanges =
validateGameAndPostChanges(gh_id, game, pkgName, isVGame, updateInstallStatus)
if (!isNotifyUpdate && shouldNotifyChanges) {
isNotifyUpdate = true
}
@ -259,11 +306,13 @@ object PackageRepository {
/**
* 验证游戏并且更新数据
*/
private fun validateGameAndPostChanges(ghId: Any?,
game: GameEntity,
pkgName: String,
isVGame: Boolean,
updateInstallStatus: Boolean): Boolean {
private fun validateGameAndPostChanges(
ghId: Any?,
game: GameEntity,
pkgName: String,
isVGame: Boolean,
updateInstallStatus: Boolean
): Boolean {
if (ghId == null || ghId == game.id) {
gameInstalled.add(GameInstall.transformGameInstall(game, pkgName, isVGame))
mInstalledGameList.add(game)
@ -272,7 +321,8 @@ object PackageRepository {
addCurrentlyInstalledVersionIfValid(game)
if (updateInstallStatus) {
EventBus.getDefault().post(EBPackage(EBPackage.TYPE_INSTALLED, pkgName, game.getApk().firstOrNull()?.version))
EventBus.getDefault()
.post(EBPackage(EBPackage.TYPE_INSTALLED, pkgName, game.getApk().firstOrNull()?.version))
}
if (isCanUpdate || isCanPluggable) {
@ -356,7 +406,8 @@ object PackageRepository {
) {
// 使用了镜像的游戏;插件化关闭的游戏;无需插件化
if (game.shouldUseMirrorInfo()
|| apk.plugin == "close") {
|| apk.plugin == "close"
) {
return false
}
@ -416,8 +467,11 @@ object PackageRepository {
* @param pkgName 已安装的游戏包名
* @param cachedGameEntity 缓存的游戏实体,若存在免去再请求接口的过程
*/
fun addInstalledGame(pkgName: String,
cachedGameEntity: GameEntity? = null) {
fun addInstalledGame(
packageFilterManager: PackageFilterManager,
pkgName: String,
cachedGameEntity: GameEntity? = null
) {
mInstalledPkgSet.add(pkgName)
notifyInstallPkgData()
@ -428,7 +482,8 @@ object PackageRepository {
game = cachedGameEntity,
pkgName = pkgName,
isVGame = false,
updateInstallStatus = false)
updateInstallStatus = false
)
if (containsUpdate) {
notifyGameUpdateData()
@ -436,8 +491,9 @@ object PackageRepository {
} else {
val list = arrayListOf(pkgName)
updateFilterPackage(list) {
updateFilterPackage(packageFilterManager, list) {
loadInstalledGameDigestAndNotifyData(
packageKey = packageFilterManager.packageKey,
filteredList = list,
updateInstallStatus = false
)
@ -453,9 +509,11 @@ object PackageRepository {
* @param isVGame 是否为畅玩游戏
* @param updateInstallStatus 是否更新安装状态
*/
fun addInstalledGames(pkgNameList: ArrayList<String>,
isVGame: Boolean = false,
updateInstallStatus: Boolean = false,
fun addInstalledGames(
packageFilterManager: PackageFilterManager,
pkgNameList: ArrayList<String>,
isVGame: Boolean = false,
updateInstallStatus: Boolean = false,
) {
// 畅玩游戏不添加至本地的已安装包名列表中
if (!isVGame) {
@ -465,8 +523,9 @@ object PackageRepository {
}
notifyInstallPkgData()
updateFilterPackage(pkgNameList) {
updateFilterPackage(packageFilterManager, pkgNameList) {
loadInstalledGameDigestAndNotifyData(
packageKey = packageFilterManager.packageKey,
filteredList = pkgNameList,
isVGame = isVGame,
updateInstallStatus = updateInstallStatus
@ -526,6 +585,13 @@ object PackageRepository {
changeRecentVaPlayed()
}
/**
* 是否存在因为接口异常而导致没有查询收录情况的包名列表
*/
fun hasPendingPackage(): Boolean {
return mPendingPackageNameSet.isEmpty()
}
private fun notifyGameInstallData() {
PackagesManager.initGameInstall(ArrayList(gameInstalled))
gameInstalledLiveData.postValue(ArrayList(gameInstalled))

View File

@ -63,7 +63,13 @@ class PackageViewModel(
* @param cachedGameEntity 缓存的游戏实体
*/
fun addInstalledGame(pkgName: String?, cachedGameEntity: GameEntity? = null) {
if (!TextUtils.isEmpty(pkgName)) mRepository.addInstalledGame(pkgName!!, cachedGameEntity)
if (!TextUtils.isEmpty(pkgName)) {
mRepository.addInstalledGame(
mRepository.packageFilterManager,
pkgName!!,
cachedGameEntity
)
}
}
/**
@ -81,9 +87,7 @@ class PackageViewModel(
// 未同意获取已安装应用权限时不进行数据初始化
if (!PackageHelper.isGetInstalledPackagesAgreed()) return
if (mRepository.gameInstalled.size == 0
|| PackageFilterManager.hasPendingPackage()
) {
if (mRepository.gameInstalled.size == 0 || mRepository.hasPendingPackage()) {
PackageHelper.initPackageRelatedData();
}
}

View File

@ -56,6 +56,7 @@ import com.gh.gamecenter.history.HistoryActivity
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.mygame.MyGameActivity
import com.gh.gamecenter.packagehelper.PackageFilterManager
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.subject.SubjectActivity
@ -1997,7 +1998,7 @@ object VHelper {
validInstalledPackageList.add(packageName)
}
}
PackageRepository.addInstalledGames(validInstalledPackageList, true)
PackageRepository.addInstalledGames(PackageFilterManager(), validInstalledPackageList, true)
}
/**