添加简单的更新控制

This commit is contained in:
juntao
2022-05-26 16:56:28 +08:00
parent 8e0dcd74e5
commit 26b0f33f1c
7 changed files with 131 additions and 50 deletions

View File

@ -22,13 +22,18 @@ import com.android.apksig.ApkVerifier;
import com.android.apksig.internal.apk.ApkSigningBlockUtilsLite;
import com.g00fy2.versioncompare.Version;
import com.gh.common.xapk.XapkInstaller;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.core.utils.SentryHelper;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.manager.PackagesManager;
import com.gh.vspace.VHelper;
import com.halo.assistant.HaloApp;
import com.lightgame.download.DownloadEntity;
import com.lightgame.utils.Utils;
import net.dongliu.apk.parser.ApkFile;
@ -113,6 +118,19 @@ public class PackageUtils {
// 根据版本判断是否需要更新
shouldShowUpdate = new Version(versionFromRequest).isHigherThan(versionFromInstalledApp);
// 畅玩游戏根据 md5 是否一致确定是否需要更新
if (gameEntity.isVGame()) {
DownloadEntity entity = VHelper.getVGameSnapshot(apkEntity.getPackageName());
if (entity != null) {
String md5FromInstalledVGame = ExtensionsKt.getMetaExtra(entity, Constants.APK_MD5);
String md5FromRequest = apkEntity.getMd5();
if (md5FromRequest!= null && md5FromRequest.equals(md5FromInstalledVGame)) {
shouldShowUpdate = true;
}
}
}
// versionName 没法判定的时候尝试使用 versionCode 去判断
if (!shouldShowUpdate && versionCodeFromRequest != 0) {
shouldShowUpdate = versionCodeFromRequest > versionCodeFromInstalledApp;
@ -130,6 +148,8 @@ public class PackageUtils {
updateEntity.setUrl(apkEntity.getUrl());
updateEntity.setPlatform(apkEntity.getPlatform());
updateEntity.setEtag(apkEntity.getEtag());
updateEntity.setMd5(apkEntity.getMd5());
updateEntity.setDownloadStatus(gameEntity.getDownloadStatus());
updateEntity.setBrief(gameEntity.getBrief());
updateEntity.setTagStyle(gameEntity.getTagStyle());
updateEntity.setIndexPlugin(gameEntity.getIndexPlugin());

View File

@ -323,6 +323,7 @@ public class DownloadManager implements DownloadStatusListener {
downloadEntity.setEntrance(entrance);
downloadEntity.setLocation(location);
downloadEntity.setVersionName(apkEntity.getVersion());
ExtensionsKt.addMetaExtra(downloadEntity, Constants.APK_MD5, apkEntity.getMd5());
ExtensionsKt.addMetaExtra(downloadEntity, Constants.DOWNLOAD_ID, downloadId);
ExtensionsKt.addMetaExtra(downloadEntity, Constants.RAW_GAME_ICON, gameEntity.getRawIcon());
ExtensionsKt.addMetaExtra(downloadEntity, Constants.GAME_ICON_SUBSCRIPT, gameEntity.getIconSubscript());
@ -652,7 +653,7 @@ public class DownloadManager implements DownloadStatusListener {
/**
* 获取下载列表中的畅玩下载任务
*/
public List<DownloadEntity> getAllVDownloadTask() {
public ArrayList<DownloadEntity> getAllVDownloadTask() {
List<DownloadEntity> downloadList = getAllDownloadEntity();
ArrayList<DownloadEntity> filteredDownloadEntityList = new ArrayList<>();

View File

@ -3,27 +3,31 @@ package com.gh.gamecenter.download
import android.app.Application
import android.view.View
import androidx.lifecycle.*
import com.gh.gamecenter.common.base.BaseSimpleDao
import com.gh.gamecenter.common.constant.Constants
import com.gh.common.exposure.ExposureUtils
import com.gh.common.exposure.ExposureUtils.logADownloadExposureEvent
import com.gh.common.history.HistoryHelper.insertGameEntity
import com.gh.common.util.*
import com.gh.gamecenter.core.utils.GsonUtils.toJson
import com.gh.common.util.ApkActiveUtils
import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.PackageInstaller.createDownloadId
import com.gh.common.util.PackageInstaller.getDownloadPathWithId
import com.gh.common.util.PackageUtils
import com.gh.common.util.PlatformUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.common.base.BaseSimpleDao
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.addMetaExtra
import com.gh.gamecenter.common.utils.secondOrNull
import com.gh.gamecenter.common.utils.toProperReadableSize
import com.gh.gamecenter.common.utils.tryCatchInRelease
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.core.utils.GsonUtils.toJson
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.UrlFilterUtils
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.GameUpdateEntity
import com.gh.gamecenter.entity.PluginLocation
import com.gh.gamecenter.eventbus.EBDownloadChanged
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
@ -32,7 +36,6 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.greenrobot.eventbus.EventBus
import java.util.*
import kotlin.collections.ArrayList
class UpdatableGameViewModel(
application: Application,
@ -72,7 +75,7 @@ class UpdatableGameViewModel(
// 有闪退日志说这个 update 实体可能为空,实在看不原因 (
if (update == null) continue
// 筛选仅下载管理出现的插件化更新
if (update.isShowPlugin(PluginLocation.only_index)) {
if (update.isShowPlugin(PluginLocation.only_index) && update.downloadStatus != "smooth") {
val platform =
PlatformUtils.getInstance(getApplication()).getPlatformName(update.platform)
if (!platform.isNullOrEmpty() && "官方版" != platform) {
@ -580,6 +583,7 @@ class UpdatableGameViewModel(
downloadEntity.addMetaExtra(Constants.RAW_GAME_ICON, update.rawIcon)
downloadEntity.addMetaExtra(Constants.GAME_ICON_SUBSCRIPT, update.iconSubscript)
downloadEntity.addMetaExtra(Constants.DOWNLOAD_ID, downloadId)
downloadEntity.addMetaExtra(Constants.APK_MD5, update.md5)
val platform = PlatformUtils.getInstance(getApplication()).getPlatformName(update.platform)
if ("官方版" != platform) {

View File

@ -40,7 +40,9 @@ data class GameUpdateEntity(
var pluggableCollection: GameCollectionEntity? = null, // 插件化包所在的合集
var format: String = "",
var signature: String? = "",
var category: String? = ""
var category: String? = "",
var md5: String? = "",
var downloadStatus: String? = ""
) {
fun isShowPlugin(location: PluginLocation): Boolean {

View File

@ -14,6 +14,7 @@ import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.EmptyCallback
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.entity.ApkEntity
@ -34,6 +35,7 @@ object VHelper {
private val mDelegateManager by lazy { VirtualAppManager.get() }
private var mInstalledInfoList: List<AppInstallerInfo> = arrayListOf()
private val mInstallationLiveData by lazy { MutableLiveData<String>() }
private var mInstalledEntitySnapshotList: ArrayList<DownloadEntity>? = null // 畅玩游戏的列表快照,不保证完全即时,但获取信息应该够用了
private val mPackageObserver by lazy {
PackageObserver.PackageChangeListener {
val vaConfig = Config.getVSettingEntity()?.va ?: return@PackageChangeListener
@ -43,7 +45,8 @@ object VHelper {
if (!isVSpace) return@PackageChangeListener
if (it.type == "安装") {
connectService()
// 即时调用大概率调不起来,我也不知道为什么,只能延迟大法了
AppExecutor.uiExecutor.executeWithDelay({ connectService() }, 500)
} else if (it.type == "卸载") {
// TODO 执行卸载逻辑
}
@ -51,8 +54,13 @@ object VHelper {
}
@JvmStatic
fun init() {
connectService()
fun init(context: Context) {
val config = Config.getVSettingEntity()?.va
if (config != null
&& PackageUtils.isInstalled(context, config.arch32?.packageName)
) {
connectService()
}
PackageObserver.registerPackageChangeChangeListener(mPackageObserver)
}
@ -64,6 +72,9 @@ object VHelper {
override fun onServiceConnectionSuccessed() {
Utils.log(LOG_TAG, "V 服务连接成功")
mInstalledInfoList = getInstalledList()
updateVGameSnapshot()
PackageRepository.addInstalledGames(getInstalledPackageList())
callbackClosure?.invoke()
@ -120,7 +131,7 @@ object VHelper {
// 检查更新
val containsUpdate =
vaConfig32?.versionCode ?: 0 == PackageUtils.getVersionCodeByPackageName(vaConfig32?.packageName)
vaConfig32?.versionCode ?: 0 > PackageUtils.getVersionCodeByPackageName(vaConfig32?.packageName)
if (containsUpdate) {
// 触发更新弹窗
@ -183,28 +194,29 @@ object VHelper {
return ArrayList(list)
}
/**
* 是否已经授予了游戏空间存储权限
*/
fun isStoragePermissionGranted(): Boolean {
return mDelegateManager.checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
}
/**
* 检查存储权限,若已授予直接执行后续逻辑
*/
private fun checkStoragePermissionBeforeAction(context: Context, callback: () -> Unit) {
try {
val isStoragePermissionGranted =
mDelegateManager.checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
if (isStoragePermissionGranted) {
callback.invoke()
} else {
context.startActivity(mDelegateManager.requestPermissionIntent)
val checkClosure: () -> Unit = {
try {
val isStoragePermissionGranted =
mDelegateManager.checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
if (isStoragePermissionGranted) {
callback.invoke()
} else {
context.startActivity(mDelegateManager.requestPermissionIntent)
}
} catch (e: RuntimeException) {
e.printStackTrace()
Utils.log(LOG_TAG, "检查存储权限失败 ${e.localizedMessage}")
}
} catch (e: RuntimeException) {
e.printStackTrace()
Utils.log(LOG_TAG, "检查存储权限失败 ${e.localizedMessage}")
}
if (mDelegateManager.isConnectAidlInterface) {
checkClosure.invoke()
} else {
connectService(checkClosure)
}
}
@ -224,10 +236,18 @@ object VHelper {
AppExecutor.ioExecutor.execute {
val result = VirtualAppManager.get().installGame(filePath)
if (result.status == 0) {
updateVGameSnapshot()
updateInstalledList()
showFloatingWindow(result.packageName)
PackageObserver.onPackageChanged(EBPackage("安装", result.packageName, "unknown"))
PackageObserver.onPackageChanged(
EBPackage(
"安装",
result.packageName,
"unknown"
)
)
}
mInstallationLiveData.postValue(result.packageName)
Utils.log(LOG_TAG, "安装新应用结果 -> " + result.status)
}
@ -252,12 +272,20 @@ object VHelper {
return
}
try {
val intent = mDelegateManager.getStartGameIntent(packageName)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
activity.startActivity(intent)
} catch (e: Exception) {
ToastUtils.toast(e.localizedMessage ?: "")
val launchClosure: () -> Unit = {
try {
val intent = mDelegateManager.getStartGameIntent(packageName)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
activity.startActivity(intent)
} catch (e: Exception) {
ToastUtils.toast(e.localizedMessage ?: "")
}
}
if (mDelegateManager.isConnectAidlInterface) {
launchClosure.invoke()
} else {
connectService(launchClosure)
}
}
@ -265,15 +293,25 @@ object VHelper {
* 卸载应用
*/
fun uninstall(packageName: String?) {
try {
val result = VirtualAppManager.get().uninstallGame(packageName)
if (result) {
updateInstalledList()
PackageObserver.onPackageChanged(EBPackage("卸载", packageName, "unknown"))
val uninstallClosure: () -> Unit = {
try {
val result = VirtualAppManager.get().uninstallGame(packageName)
if (result) {
updateVGameSnapshot()
updateInstalledList()
PackageObserver.onPackageChanged(EBPackage("卸载", packageName, "unknown"))
}
Utils.log(LOG_TAG, "安装新应用结果 -> $result")
} catch (e: Exception) {
ToastUtils.toast(e.localizedMessage ?: "")
}
Utils.log(LOG_TAG, "安装新应用结果 -> $result")
} catch (e: Exception) {
ToastUtils.toast(e.localizedMessage ?: "")
}
if (mDelegateManager.isConnectAidlInterface) {
uninstallClosure.invoke()
} else {
connectService(uninstallClosure)
}
}
@ -296,7 +334,7 @@ object VHelper {
* 如果已安装或配置为空返回 true
* 未安装的情况下会弹弹窗
*/
private fun showDialogIfVSpaceIsNeeded(context: Context) : Boolean {
private fun showDialogIfVSpaceIsNeeded(context: Context): Boolean {
val vaConfig = Config.getVSettingEntity()?.va ?: return true
// TODO 检测 64 位
@ -308,6 +346,22 @@ object VHelper {
return false
}
private fun updateVGameSnapshot() {
runOnIoThread {
mInstalledEntitySnapshotList = ArrayList(DownloadManager.getInstance().allVDownloadTask)
}
}
/**
* 获取数据库中已安装的畅玩游戏的快照
*/
@JvmStatic
fun getVGameSnapshot(packageName: String): DownloadEntity? {
return mInstalledEntitySnapshotList?.firstOrNull {
it.packageName == packageName
}
}
fun toGameEntity(downloadEntity: DownloadEntity): GameEntity {
return GameEntity(id = downloadEntity.gameId, name = downloadEntity.name).apply {
setApk(

View File

@ -441,9 +441,7 @@ public class HaloApp extends MultiDexApplication implements Configuration.Provid
}
private void retrieveVGameInfoIfNeeded() {
// if (SPUtils.getBoolean(Constants.SP_IS_VSPACE_USED)) {
VHelper.init();
// }
VHelper.init(this);
}
public boolean isEmulator() {