feat: 光环助手va组件兼容旧版畅玩助手游戏业务

This commit is contained in:
yangfei
2023-12-12 19:32:13 +08:00
parent 6c191bf77a
commit a557d61dde
10 changed files with 253 additions and 201 deletions

View File

@ -15,8 +15,10 @@ import com.gh.gamecenter.SplashScreenActivity
import com.gh.gamecenter.authorization.AuthorizationActivity
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.utils.PackageFlavorHelper
import com.gh.gamecenter.login.view.LoginActivity
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lg.vspace.ui.launcher.LaunchActivity
// TODO移动到对应的模块
class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
@ -73,6 +75,8 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
}
if (activity is AppCompatActivity
&& activity !is LaunchActivity
&& activity !is LoginActivity
&& activity !is SplashScreenActivity
&& activity !is SkipActivity
&& activity !is AuthorizationActivity

View File

@ -140,6 +140,8 @@ import io.reactivex.SingleSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
@ -724,14 +726,11 @@ public class MainActivity extends BaseActivity {
ToastUtils.showToast("游戏启动中,请稍后~");
handler.postDelayed(() -> {
VHelper.postOnInitialized(() -> {
if (VHelper.isInstalled(gamePackageName)) {
VHelper.launch(this, gamePackageName, false, true);
} else {
ToastUtils.showToast("应用已被卸载!");
}
return null;
});
if (VHelper.isLegacyGame(gamePackageName)) {
VHelper.postOnInitialized(launchGame(gamePackageName));
} else {
launchGame(gamePackageName).invoke();
}
}, 500);
break;
case KEY_MARKET_DETAILS:
@ -749,6 +748,18 @@ public class MainActivity extends BaseActivity {
}, 500);
}
@NonNull
private Function0<Unit> launchGame(String gamePackageName) {
return () -> {
if (!VHelper.isInnerInstalled(gamePackageName) && !VHelper.isInstalled(gamePackageName)) {
ToastUtils.showToast("应用已被卸载!");
} else {
VHelper.launch(this, gamePackageName, false, true);
}
return null;
};
}
/**
* 应用跳转
*/

View File

@ -193,7 +193,7 @@ class AuthorizationActivity : ToolBarActivity() {
val userAvatar = UserManager.getInstance().userInfoEntity?.icon
//授权成功,发送广播, 返回token
val intent = Intent()
intent.setClassName(remotePkgName, "$remotePkgName.AuthorizationReceiver")
intent.setClassName(remotePkgName, "com.va.host.receiver.AuthorizationReceiver")
intent.setPackage(remotePkgName)
intent.putExtra(EntranceConsts.KEY_TOKEN, token)
intent.putExtra(EntranceConsts.KEY_USER_ID, userId)

View File

@ -1,6 +1,7 @@
package com.gh.vspace
import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.ContentValues
import android.content.Context
import android.content.Intent
@ -46,10 +47,13 @@ import com.gh.vspace.db.VGameDatabase
import com.gh.vspace.db.VGameEntity
import com.gh.vspace.gapps.GAppsDownloadDialogFragment
import com.halo.assistant.HaloApp
import com.lg.vspace.VaApp
import com.lg.vspace.VirtualAppManager
import com.lg.vspace.bridge.BuildConfig
import com.lg.vspace.remote.BinderPool
import com.lg.vspace.remote.listener.RemoteConnectListener
import com.lg.vspace.remote.model.AppInstallerInfo
import com.lg.vspace.remote.model.VGameInstallerParams
import com.lg.vspace.remote.model.VGameInstallerResult
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.AppManager
@ -60,6 +64,7 @@ import org.greenrobot.eventbus.EventBus
import java.io.File
import java.util.*
import java.util.concurrent.CopyOnWriteArrayList
import kotlin.collections.ArrayList
object VHelper {
@ -288,7 +293,14 @@ object VHelper {
callbackClosure: (() -> Unit)? = null
) {
Utils.log(LOG_TAG, "尝试连接 V 服务")
val isOldCwInstalled = PackageUtils.isInstalledFromAllPackage(
HaloApp.getInstance().applicationContext,
BuildConfig.AIDL_SERVER_PACKAGE_NAME
)
if (!isOldCwInstalled) {
Utils.log(LOG_TAG, "包名[${BuildConfig.AIDL_SERVER_PACKAGE_NAME}]应用没有安装")
return
}
if (!shouldConnectSilently) {
toastIfServiceConnectTimeout()
}
@ -453,7 +465,7 @@ object VHelper {
}
/**
* 是否已安装此包名的畅玩游戏
* 旧版畅玩组件是否已安装此包名的畅玩游戏
*/
@JvmStatic
fun isInstalled(packageName: String?): Boolean {
@ -477,6 +489,10 @@ object VHelper {
return isInstalled
}
@JvmStatic
fun isInnerInstalled(packageName: String?) =
VaApp.get().appManager.installedGamesInfo.any { it.packageName == packageName }
/**
* 启动成功,五秒内退出才显示反馈弹框
*/
@ -502,11 +518,15 @@ object VHelper {
* 获取游戏占用的空间
*/
fun getAppOccupiedSpace(packageName: String): Long {
return try {
mDelegateManager.getAppOccupiedSpace(packageName)
} catch (e: Exception) {
e.printStackTrace()
0
return if (isLegacyGame(packageName)) {
try {
mDelegateManager.getAppOccupiedSpace(packageName)
} catch (e: Exception) {
e.printStackTrace()
0
}
} else {
VaApp.get().appManager.getAppOccupiedSpace(packageName)
}
}
@ -514,6 +534,16 @@ object VHelper {
* 在执行 callback 前先检查组件是否已安装,是否可下载
*/
fun validateVSpaceBeforeAction(context: Context, gameEntity: GameEntity?, callback: () -> Unit) {
if (isInstalled(gameEntity?.getUniquePackageName())) {
oldCwValidateVSpaceBeforeAction(context, gameEntity, callback)
} else {
//TODO: check new cw 32 va component
callback.invoke()
}
}
private fun oldCwValidateVSpaceBeforeAction(context: Context, gameEntity: GameEntity?, callback: () -> Unit) {
if (showDialogIfVSpaceIsNeeded(
context,
gameEntity?.id ?: "",
@ -665,6 +695,26 @@ object VHelper {
return ArrayList(list)
}
@JvmStatic
fun isLegacyGame(packageName: String) = isInstalled(packageName)
private fun gotoVspaceLoading(
context: Context,
downloadEntity: DownloadEntity,
shouldLaunchGameAfterInstallation: Boolean
) {
if (shouldLaunchGameAfterInstallation) {
runOnUiThread {
val gameEntity = toGameEntity(downloadEntity)
try {
context.startActivity(VSpaceLoadingActivity.getIntent(context, gameEntity, true))
} catch (e: Exception) {
ToastUtils.toast(e.localizedMessage ?: "启动游戏异常,请稍候再试")
}
}
}
}
/**
* 安装新游戏
* 正常的游戏使用这个方法来安装,内部有重试处理
@ -675,74 +725,85 @@ object VHelper {
isManualInstall: Boolean = false
) {
Utils.log(LOG_TAG, "尝试安装新游戏 ${downloadEntity.path}")
if (showDialogIfVSpaceIsNeeded(
context,
downloadEntity.gameId,
downloadEntity.name,
downloadEntity.getMetaExtra(Constants.GAME_CATEGORY_IN_CHINESE),
downloadEntity.getMetaExtra(KEY_BIT)
)
) return
// 如果一个游戏存在旧版畅玩助手内,此次安装就是游戏更新
val isLegacyGame = isLegacyGame(downloadEntity.packageName)
// 更新此包名对应的 gameId Map
mTempPackageNameAndGameIdMap[downloadEntity.packageName] = downloadEntity.gameId
// 当且仅当
// 1. 全局安装完成启动游戏开关打开
// 2. 服务连接不成功或是手动触发的安装
// 2. 手动触发的安装
// 3. 不需要谷歌框架或者已经安装好谷歌框架
// 才启用安装完成后自动启动游戏
val shouldLaunchGameAfterInstallation =
mShouldLaunchGameAfterInstallation
&& (!mIsServiceConnected || isManualInstall)
&& (!isGAppsRequired(downloadEntity) || isGAppsInstalled())
val shouldLaunchGameAfterInstallation: Boolean
if (isLegacyGame) {
shouldLaunchGameAfterInstallation =
mShouldLaunchGameAfterInstallation
&& (!mIsServiceConnected || isManualInstall)
&& (!isGAppsRequired(downloadEntity) || isGAppsInstalledInCwLegacy())
} else {
shouldLaunchGameAfterInstallation =
mShouldLaunchGameAfterInstallation
&& isManualInstall
&& (!isGAppsRequired(downloadEntity) || isGAppsInstalled())
}
// 恢复安装完启动游戏开关
mShouldLaunchGameAfterInstallation = true
connectService {
val installClosure: () -> Unit = {
if (shouldLaunchGameAfterInstallation) {
runOnUiThread {
val gameEntity = toGameEntity(downloadEntity)
try {
context.startActivity(VSpaceLoadingActivity.getIntent(context, gameEntity, true))
} catch (e: Exception) {
ToastUtils.toast(e.localizedMessage ?: "启动游戏异常,请稍候再试")
}
}
}
val installClosure: () -> Unit = {
gotoVspaceLoading(context, downloadEntity, shouldLaunchGameAfterInstallation)
val path = downloadEntity.path
// 正在安装中,忽略重复调用 (手动安装时强行再安装,避免安装结果没有回调时永远卡住,无法安装)
if (!mInstallingVaPathSet.contains(path)) {
try {
mInstallingVaPathSet.add(path)
val path = downloadEntity.path
// 正在安装中,忽略重复调用 (手动安装时强行再安装,避免安装结果没有回调时永远卡住,无法安装)
if (!mInstallingVaPathSet.contains(path)) {
try {
mInstallingVaPathSet.add(path)
if (isLegacyGame) {
runOnUiThread {
val intent = VirtualAppManager.getInstallIntent(context, path, downloadEntity.packageName)
Utils.log(LOG_TAG, "正在安装 ${downloadEntity.packageName}")
context.startActivity(intent)
}
} catch (e: Exception) {
ToastUtils.toast(e.localizedMessage ?: "")
} else {
runOnIoThread {
val bit = downloadEntity.getMetaExtra(KEY_BIT)
val installParams =
VGameInstallerParams(VGameInstallerParams.FLAG_INSTALL_OVERRIDE_NO_CHECK)
if (bit == "32") {
installParams.cpuAbiOverride = "armeabi-v7a"
} else {
installParams.cpuAbiOverride = "arm64-v8a"
}
val installGameResult = VaApp.get().appManager.installGame(path, installParams)
onInstallFinished(downloadEntity.packageName, installGameResult)
}
}
} catch (e: Exception) {
ToastUtils.toast(e.localizedMessage ?: "")
}
} else {
Utils.log(LOG_TAG, "$path 正在安装中,此次安装调用无效")
}
}
if (isLegacyGame) {
connectService {
if (mDelegateManager.isConnectAidlInterface) {
installClosure.invoke()
} else {
Utils.log(LOG_TAG, "$path 正在安装中,此次安装调用无效")
connectService(
shouldCheckUpdate = false,
shouldConnectSilently = false,
callbackClosure = installClosure
)
}
}
if (mDelegateManager.isConnectAidlInterface) {
installClosure.invoke()
} else {
connectService(
shouldCheckUpdate = false,
shouldConnectSilently = false,
callbackClosure = installClosure
)
}
} else {
installClosure.invoke()
}
}
@ -769,43 +830,32 @@ object VHelper {
* 安装新应用
* 不会作为游戏存储,目前仅应用于谷歌框架
* 因为是静默安装,所以不检查其它限制条件
*
* 不再安装到旧版畅玩助手
*/
private fun install(context: Context, file: File) {
Utils.log(LOG_TAG, "尝试安装新应用 ${file.name}")
val packageName = file.nameWithoutExtension
val installClosure: () -> Unit = {
val path = file.path
if (!mInstallingVaPathSet.contains(path)) {
try {
runOnUiThread {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
&& !PackageUtils.isAppOnForeground(context)
) {
mBatchInstallListener?.invoke(false, true)
Utils.log(LOG_TAG, "应用切换至后台,批量安装被打断")
return@runOnUiThread
}
mInstallingVaPathSet.add(path)
val intent = VirtualAppManager.getInstallIntent(context, path, packageName)
Utils.log(LOG_TAG, "正在安装 $packageName")
context.startActivity(intent)
}
} catch (e: Exception) {
Utils.log(LOG_TAG, "安装异常,${e.localizedMessage}")
val path = file.path
if (!mInstallingVaPathSet.contains(path)) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
&& !PackageUtils.isAppOnForeground(context)
) {
mBatchInstallListener?.invoke(false, true)
Utils.log(LOG_TAG, "应用切换至后台,批量安装被打断")
return
}
mInstallingVaPathSet.add(path)
runOnIoThread {
val installParams = VGameInstallerParams(VGameInstallerParams.FLAG_INSTALL_OVERRIDE_NO_CHECK)
val installGameResult = VaApp.get().appManager.installGame(path, installParams)
onInstallFinished(packageName, installGameResult)
}
} catch (e: Exception) {
Utils.log(LOG_TAG, "安装异常,${e.localizedMessage}")
}
}
if (mDelegateManager.isConnectAidlInterface) {
installClosure.invoke()
} else {
connectService(shouldCheckUpdate = false, shouldConnectSilently = false, callbackClosure = installClosure)
}
}
/**
@ -824,7 +874,7 @@ object VHelper {
* 安装完成回调
*/
fun onInstallFinished(packageName: String, result: VGameInstallerResult) {
if(PackageFlavorHelper.IS_TEST_FLAVOR) {
if (PackageFlavorHelper.IS_TEST_FLAVOR) {
callSite.onNext(callSiteOnInstallComplet)
}
runOnIoThread {
@ -848,7 +898,10 @@ object VHelper {
}
if (result.status == 0) {
updateInstalledList()
if (isInstalled(packageName)) {
// 存在旧版畅玩组件的游戏更新时才更新安装列表了,不再会有新的包安装到旧版的畅玩空间了
updateInstalledList()
}
PackageObserver.onPackageChanged(
EBPackage(EBPackage.TYPE_INSTALLED, result.packageName, "unknown").also {
it.gameId = downloadEntity.gameId
@ -869,7 +922,9 @@ object VHelper {
} else {
// downloadEntity 为空,可能是框架类的安装 (走另外一个下载管理)
if (result.status == 0) {
updateInstalledList()
if (mIsServiceConnected) {
updateInstalledList()
}
} else {
ToastUtils.toast("安装出现异常, ${result.status}")
}
@ -957,9 +1012,11 @@ object VHelper {
values.put("meta", GsonUtils.toJson(downloadEntity.meta))
val type = if (PackageFlavorHelper.IS_TEST_FLAVOR) "test_flavor" else ""
values.put("type", type)
val uri = Uri.parse("content://com.lg.core.provider/download_game")
val uri =
Uri.parse("content://${com.lg.vspace.BuildConfig.VA_AUTHORITY_PREFIX}.provider.download_game/download_game")
HaloApp.getInstance().contentResolver.insert(uri, values)
} catch (e: Throwable) {
Utils.log("TEST", "::insertInstalledGameToProvider, e: ${e.toString()}")
if (!fromRetry) {
insertInstalledGameToProvider(downloadEntity, true)
} else {
@ -974,7 +1031,7 @@ object VHelper {
downloadEntity: DownloadEntity,
location: String? = null
) {
Utils.log(LOG_TAG, "检测是需要安装还是启动 ${downloadEntity.gameId}")
Utils.log(LOG_TAG, "检测是需要安装还是启动(DownloadEntity) ${downloadEntity.gameId}")
if (downloadEntity.name.isNullOrEmpty()) {
SentryHelper.onEvent(
@ -1003,7 +1060,7 @@ object VHelper {
gameEntity: GameEntity,
location: String? = null
) {
Utils.log(LOG_TAG, "检测是需要安装还是启动 ${gameEntity.id}")
Utils.log(LOG_TAG, "检测是需要安装还是启动(GameEntity) ${gameEntity.id}")
installOrLaunch(
context,
@ -1041,29 +1098,24 @@ object VHelper {
category = gameType
setApk(arrayListOf(ApkEntity(packageName = packageName, bit = bit)))
}) {
if (isInstalled(packageName)) {
if (isLegacyGame(packageName) || isInnerInstalled(packageName)) {
launch(context, packageName)
} else {
// 这里重新检查一遍是否已安装,因为有可能因为上一次更新列表失败而出现重新下载的情况
if (isInstalled(packageName)) {
launch(context, packageName)
return@validateVSpaceBeforeAction
}
return@validateVSpaceBeforeAction
}
// 检查下载管理是否有下载实体,有实体表明未安装成功
val downloadEntity = getVDownloadEntity(gameId = gameId, packageName = packageName)
// 检查下载管理是否有下载实体,有实体表明未安装成功
val downloadEntity = getVDownloadEntity(gameId = gameId, packageName = packageName)
if (downloadEntity != null) {
val downloadedFile = File(downloadEntity.path)
if (downloadedFile.exists() && downloadedFile.length() == downloadEntity.size) {
install(context, downloadEntity, true)
} else {
// 重新下载
updateOrReDownload(downloadEntity, null)
}
if (downloadEntity != null) {
val downloadedFile = File(downloadEntity.path)
if (downloadedFile.exists() && downloadedFile.length() == downloadEntity.size) {
install(context, downloadEntity, true)
} else {
ToastUtils.toast("该游戏已损坏,请重新下载")
// 重新下载
updateOrReDownload(downloadEntity, null)
}
} else {
ToastUtils.toast("该游戏已损坏,请重新下载")
}
}
}
@ -1080,7 +1132,7 @@ object VHelper {
showLoading: Boolean = true
) {
Utils.log(LOG_TAG, "尝试打开应用 $packageName")
val isLegacyGame = isLegacyGame(packageName)
// 置空下载挂起回调(能 launch 游戏说明畅玩组件已安装)
mPendingDownloadCallback = null
@ -1089,9 +1141,13 @@ object VHelper {
val gameId = downloadEntity?.gameId ?: "unknown"
val gameName = downloadEntity?.name ?: "unknown"
val gameIcon = downloadEntity?.icon ?: "unknown"
// 若需要安装谷歌框架,弹谷歌框架安装弹窗
if (!ignoreGApps && isGAppsRequired(downloadEntity) && !isGAppsInstalled()) {
if (!ignoreGApps && isGAppsRequired(downloadEntity) && if (isLegacyGame) {
!isGAppsInstalledInCwLegacy()
} else {
!isGAppsInstalled()
}
) {
// show dialog
val currentActivity = CurrentActivityHolder.getCurrentActivity() as? AppCompatActivity
?: if (context is AppCompatActivity) context else return
@ -1119,10 +1175,23 @@ object VHelper {
thirdPartyAd?.slotId,
thirdPartyAd?.displaySize
)
// 覆盖字段
if (!isLegacyGame) {
intent.setComponent(
ComponentName(
com.gh.gamecenter.BuildConfig.APPLICATION_ID,
VirtualAppManager.AIDL_SERVER_REMOTE_GUIDE_ACTIVITY
)
)
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
} else {
VirtualAppManager.get().launchGame(packageName)
if (isLegacyGame(packageName)) {
VirtualAppManager.get().launchGame(packageName)
} else {
VaApp.get().appManager.launchGame(packageName)
}
}
mLastSuccessfullyLaunchedGame = Pair(System.currentTimeMillis(), packageName)
@ -1228,7 +1297,7 @@ object VHelper {
// 卸载的时候移除已安装的包名历史
mPackageInstalledLiveData.postValue("")
}
if(PackageFlavorHelper.IS_TEST_FLAVOR) {
if (PackageFlavorHelper.IS_TEST_FLAVOR) {
callSite.onNext(callSiteUninstall)
}
Utils.log(LOG_TAG, "卸载应用结果 -> $result")
@ -1714,9 +1783,15 @@ object VHelper {
}
/**
* 是否已经成功安装了 GApps
* 畅玩是否已经成功安装了 GApps
*/
fun isGAppsInstalled(): Boolean {
private fun isGAppsInstalled() = isInnerInstalled(G_GMS_PACKAGE_NAME) && isInnerInstalled(G_GSF_PACKAGE_NAME)
&& isInnerInstalled(G_VENDING_PACKAGE_NAME)
/**
* 旧版畅玩是否已经成功安装了 GApps
*/
private fun isGAppsInstalledInCwLegacy(): Boolean {
return isInstalled(G_GMS_PACKAGE_NAME)
&& isInstalled(G_GSF_PACKAGE_NAME)
&& isInstalled(G_VENDING_PACKAGE_NAME)

View File

@ -89,8 +89,8 @@ class ShortcutManager private constructor() {
* 知道游戏id和包名创建桌面图标
*/
fun tryCreateShortCut(context: Context, gameId: String, gamePkg: String, result: OnCreateShortcutResult) {
VHelper.postOnInitialized {
val downloadEntity = VHelper.getVDownloadEntitySnapshot(gameId, gamePkg)
val downloadEntity = VHelper.getVDownloadEntitySnapshot(gameId, gamePkg)
val createShortcutLambda = {
runOnUiThread {
if (downloadEntity == null) {
result.failed()
@ -100,6 +100,11 @@ class ShortcutManager private constructor() {
}
}
}
if (VHelper.isLegacyGame(gamePkg)) {
VHelper.postOnInitialized(createShortcutLambda)
} else {
createShortcutLambda.invoke()
}
}

View File

@ -388,6 +388,7 @@ public class HaloApp extends MultiDexApplication {
});
}
}, delay);
VaApp.get().startSensorLogService();
}
private void initArouter() {