Compare commits

...

17 Commits

Author SHA1 Message Date
8c7acae10f refactor: 更新shadow版本至 1.0.3 2023-12-29 11:24:06 +08:00
7519612347 refactor: 更新maven拉取顺序 2023-12-19 14:16:05 +08:00
5966d4ab0d refactor: 更新apk文件路径 2023-12-19 11:47:11 +08:00
1f264cdced refactor: 下载插件到assets目录 2023-12-19 11:33:10 +08:00
c5af23caab refactor: 更新打包脚本 2023-12-19 11:29:44 +08:00
e7a46a03f7 refactor: update vasdk commit id. 2023-12-19 11:28:08 +08:00
8f7df48d4c feat: 展示64位va插件版本信息 https://jira.shanqu.cc/browse/GHZS-3885 2023-12-13 19:18:53 +08:00
32a0b64572 refactor: update vasdk commit id. 2023-12-13 15:14:10 +08:00
7578c109d6 fix: 过滤va项目的配置&修复错误的assets添加脚步 2023-12-13 15:13:44 +08:00
943c938af7 feat: 光环助手va组件兼容旧版畅玩助手游戏业务 2023-12-12 19:32:13 +08:00
490b4055da refactor: update vasdk commmit id 2023-12-04 10:27:59 +08:00
0203566bbc feat: 接入vasdk编译通过 2023-12-02 16:38:38 +08:00
7f38cdfb01 refactor: va模块引用 2023-12-02 15:53:38 +08:00
8f8feddb5c Merge branch 'release' into feat/CWZS-113 2023-12-02 14:04:08 +08:00
b5e1bf9124 feat: 加速器模块占用空间太大,给ci/cd集成增加时间成本,考虑到加速器变更频繁度较低,改为maven引用 2023-12-02 13:58:37 +08:00
811fb33ac3 feat: 同步vasdk的代码 2023-10-19 15:15:47 +08:00
bf2c359e95 feat: 接入va模块 2023-10-17 18:03:14 +08:00
21 changed files with 551 additions and 179 deletions

3
.gitmodules vendored
View File

@ -11,3 +11,6 @@
[submodule "ndownload"]
path = ndownload
url = ../../../android/ndownload.git
[submodule "vasdk"]
path = vasdk
url = ../../../sdg/android/vasdk.git

View File

@ -73,7 +73,7 @@ android {
versionName rootProject.ext.versionName
applicationId rootProject.ext.applicationId
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt'
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt', rootProject.ext.va_proguard_rules
String CORE_EVENT_GAME_CATEGORY = ""
@ -160,6 +160,9 @@ android {
flavorDimensions("env")
sourceSets {
main {
assets.srcDir("${rootProject.buildDir}/plugin")
}
publish {
java.srcDirs = ['src/main/java', "src/default/java"]
}
@ -325,9 +328,9 @@ dependencies {
kapt "com.alibaba:arouter-compiler:$arouterVersion"
implementation project(':ndownload')
implementation project(':vspace-bridge:vspace')
implementation project(':vspace-bridge')
implementation (project(':module_common')) {
implementation(project(':module_common')) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(':module_login')) {
@ -365,6 +368,12 @@ dependencies {
exclude group: 'androidx.swiperefreshlayout'
}
internalImplementation(project(':module_internal_test'))
implementation(project(':va-main')) {
exclude group: 'androidx.swiperefreshlayout'
}
debugImplementation "com.bytedance.tools.codelocator:codelocator-core:2.0.3"
compileOnly project(":va-core")
compileOnly project(":va-plugin-host-lib")
}
File propFile = file('sign.properties')
@ -606,4 +615,14 @@ project.afterEvaluate {
}
}
}
}
def copyArtifacts = tasks.create("copyArtifacts", Copy) {
from new File(rootProject.buildDir, "artifacts.zip")
into new File(rootProject.buildDir, "plugin")
}.dependsOn(":va-plugin-floating:generateDebugArtifacts")
tasks.whenTaskAdded { Task task ->
if (task.name == "preInternalDebugBuild" || task.name == "prePublishDebugBuild") {
task.dependsOn(copyArtifacts)
}
}

View File

@ -84,7 +84,30 @@
com.tencent.qqmini,
com.tencent.qqmini.minigame.external,
com.tencent.qqmini.minigame.opensdk,
com.tencent.qqmini.union.ad" />
com.tencent.qqmini.union.ad,
com.lg.vspace,
io.lg.va.common,
com.va.floating,
com.lg.cloud,
com.lg.archive,
com.lg.vclient,
com.va.realname,
com.lg.vspace.flavor,
com.lg.update,
com.lg.login,
com.lg.accelerator,
com.lody.virtual,
com.lg.core,
com.lg.ads,
com.lg.common,
com.lg.vspace.network,
com.lody.virtual.lib.res,
com.va.host,
com.lg.vspace.plugin.host,
com.lg.plugin.constant,
com.bytedance.tools.codelocator,
org.chickenhook.restrictionbypass,
com.lody.virtual.sandhook" />
<!-- 去掉 SDK 一些流氓权限 -->
<uses-permission
@ -782,7 +805,8 @@
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}"
android:exported="false"
android:grantUriPermissions="true">
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />

View File

@ -13,8 +13,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 {
@ -56,6 +58,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

@ -8,6 +8,7 @@ import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IAppProvider
import com.gh.gamecenter.core.provider.IFlavorProvider
import com.halo.assistant.HaloApp
import com.va.host.HostUtils
@Route(path = RouteConsts.provider.app, name = "Application暴露服务")
class AppProviderImpl : IAppProvider {
@ -82,4 +83,6 @@ class AppProviderImpl : IAppProvider {
override fun getIsBrandNewInstall(): Boolean {
return HaloApp.getInstance().isBrandNewInstall
}
override fun getPluginVersion(): String = HostUtils.getPluginVersion()
}

View File

@ -142,6 +142,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;
@ -726,14 +728,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:
@ -751,6 +750,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
@ -44,10 +45,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
@ -58,6 +62,7 @@ import org.greenrobot.eventbus.EventBus
import java.io.File
import java.util.*
import java.util.concurrent.CopyOnWriteArrayList
import kotlin.collections.ArrayList
object VHelper {
@ -286,7 +291,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()
}
@ -442,7 +454,7 @@ object VHelper {
}
/**
* 是否已安装此包名的畅玩游戏
* 旧版畅玩组件是否已安装此包名的畅玩游戏
*/
@JvmStatic
fun isInstalled(packageName: String?): Boolean {
@ -466,6 +478,10 @@ object VHelper {
return isInstalled
}
@JvmStatic
fun isInnerInstalled(packageName: String?) =
VaApp.get().appManager.installedGamesInfo.any { it.packageName == packageName }
/**
* 启动成功,五秒内退出才显示反馈弹框
*/
@ -491,11 +507,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)
}
}
@ -503,6 +523,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 ?: "",
@ -654,6 +684,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 ?: "启动游戏异常,请稍候再试")
}
}
}
}
/**
* 安装新游戏
* 正常的游戏使用这个方法来安装,内部有重试处理
@ -664,74 +714,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()
}
}
@ -758,43 +819,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)
}
}
/**
@ -813,7 +863,7 @@ object VHelper {
* 安装完成回调
*/
fun onInstallFinished(packageName: String, result: VGameInstallerResult) {
if(PackageFlavorHelper.IS_TEST_FLAVOR) {
if (PackageFlavorHelper.IS_TEST_FLAVOR) {
callSite.onNext(callSiteOnInstallComplet)
}
runOnIoThread {
@ -837,7 +887,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
@ -858,7 +911,9 @@ object VHelper {
} else {
// downloadEntity 为空,可能是框架类的安装 (走另外一个下载管理)
if (result.status == 0) {
updateInstalledList()
if (mIsServiceConnected) {
updateInstalledList()
}
} else {
ToastUtils.toast("安装出现异常, ${result.status}")
}
@ -946,9 +1001,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 {
@ -963,7 +1020,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(
@ -992,7 +1049,7 @@ object VHelper {
gameEntity: GameEntity,
location: String? = null
) {
Utils.log(LOG_TAG, "检测是需要安装还是启动 ${gameEntity.id}")
Utils.log(LOG_TAG, "检测是需要安装还是启动(GameEntity) ${gameEntity.id}")
installOrLaunch(
context,
@ -1030,29 +1087,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("该游戏已损坏,请重新下载")
}
}
}
@ -1069,7 +1121,7 @@ object VHelper {
showLoading: Boolean = true
) {
Utils.log(LOG_TAG, "尝试打开应用 $packageName")
val isLegacyGame = isLegacyGame(packageName)
// 置空下载挂起回调(能 launch 游戏说明畅玩组件已安装)
mPendingDownloadCallback = null
@ -1078,9 +1130,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 ?: return
GAppsDownloadDialogFragment
@ -1106,10 +1162,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)
@ -1215,7 +1284,7 @@ object VHelper {
// 卸载的时候移除已安装的包名历史
mPackageInstalledLiveData.postValue("")
}
if(PackageFlavorHelper.IS_TEST_FLAVOR) {
if (PackageFlavorHelper.IS_TEST_FLAVOR) {
callSite.onNext(callSiteUninstall)
}
Utils.log(LOG_TAG, "卸载应用结果 -> $result")
@ -1678,9 +1747,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

@ -74,6 +74,7 @@ import com.gh.vspace.VHelper;
import com.github.piasy.biv.BigImageViewer;
import com.github.piasy.biv.loader.fresco.FrescoImageLoader;
import com.lg.ndownload.DownloadDbManager;
import com.lg.vspace.VaApp;
import com.lightgame.utils.Utils;
import com.llew.huawei.verifier.LoadedApkHuaWei;
import com.shuyu.gsyvideoplayer.cache.CacheFactory;
@ -90,6 +91,7 @@ import tv.danmaku.ijk.media.exo2.ExoPlayerCacheManager;
public class HaloApp extends MultiDexApplication {
private static HaloApp mInstance;
private static final ArrayMap<String, Object> sObjectMap = new ArrayMap<>();
private String mChannel;
@ -196,6 +198,7 @@ public class HaloApp extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
VaApp.get().onCreate(this);
initArouter();
if (!Injection.appInit(this)) {
@ -357,6 +360,7 @@ public class HaloApp extends MultiDexApplication {
});
}
}, delay);
VaApp.get().startSensorLogService();
}
private void initArouter() {
@ -541,6 +545,7 @@ public class HaloApp extends MultiDexApplication {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
VaApp.get().attachBaseContext(this, base);
for (IApplication application : mApplicationList) {
application.attachBaseContext();
}

View File

@ -5,21 +5,30 @@ apply from: 'vspace-bridge/config.gradle'
buildscript {
ext.kotlin_version = '1.7.20'
ext.shadow_version = '1.0.3'
repositories {
google()
jcenter()
mavenCentral()
maven {
url "https://nexus.shanqu.cc/repository/lightgame-public/"
credentials {
username("lg_android")
password("u9gZYH4MQEwLLQZK")
}
}
maven { url 'https://jitpack.io' }
maven { url "https://maven.google.com" }
}
dependencies {
classpath "com.android.tools.build:gradle:7.2.2"
classpath "com.android.tools.build:gradle:7.3.0"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// 使用了 1.2.21 在蓝叠模拟器上无法进入首页? 但是不使用又会出现触发 V3 签名...
classpath 'io.github.leon406:AndResGuard-gradle-plugin:1.2.22.6'
classpath 'com.sensorsdata.analytics.android:android-gradle-plugin2:3.5.3'
classpath "com.lg.shadow.core:gradle-plugin:$shadow_version"
}
}
@ -37,15 +46,17 @@ allprojects {
mavenCentral()
maven { url 'https://jitpack.io' }
maven { url 'https://maven.aliyun.com/nexus/content/repositories/releases/' }
maven { url 'https://artifact.bytedance.com/repository/Volcengine/'}
maven { url 'https://artifact.bytedance.com/repository/Volcengine/' }
maven { url 'https://artifact.bytedance.com/repository/pangle' }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
subprojects {
subproject ->
afterEvaluate {
if ((subproject.plugins.hasPlugin('android') || subproject.plugins.hasPlugin('android-library'))) {
if (!project.name.startsWith("va-") && (subproject.plugins.hasPlugin('android') || subproject.plugins.hasPlugin('android-library'))) {
if (!android.compileSdkVersion) {
android {
compileSdkVersion rootProject.ext.compileSdkVersion
@ -58,10 +69,8 @@ subprojects {
minSdkVersion rootProject.ext.minSdkVersion
// for those defined in AndroidManifest.xml
manifestPlaceholders = [
manifestApplicationId: "${applicationId}",
tencentAppId : "${TENCENT_APPID}",
]
manifestPlaceholders.put("manifestApplicationId", "${applicationId}")
manifestPlaceholders.put("tencentAppId", "${TENCENT_APPID}")
}
lintOptions.abortOnError false

View File

@ -140,4 +140,6 @@ ext {
qGameVersion = "1.57.14"
qGameAdVersion = "4.520.1390"
}
}
apply from: 'dependencies_vasdk.gradle'

62
dependencies_vasdk.gradle Normal file
View File

@ -0,0 +1,62 @@
ext {
vaCompileSdkVersion = 33
vaMinSdkVersion = 21
vaTargetSdkVersion = 28
}
ext {
PACKAGE_NAME = "com.gh.gamecenter"
EXT_PACKAGE_NAME = "com.gh.gamecenter.addon"
VA_MAIN_PACKAGE_32BIT = false
VA_ACCESS_PERMISSION_NAME = "com.gh.gamecenter.permission.SAFE_ACCESS"
VA_AUTHORITY_PREFIX = "com.gh.gamecenter"
VA_EXT_AUTHORITY_PREFIX = "com.gh.gamecenter.ext"
INSTALL_EXT_AUTHORITY_PREFIX = "com.gh.gamecenter.install_external_app" // 在va环境内安装外部应用authority属性
// version test
VA_VERSION = '1.6.5'
VA_VERSION_CODE = 100605
VA_FULL_EXT = true
signing_storeFile = "${rootDir}/app/gh.keystore"
signing_storePassword = "20150318"
signing_keyAlias = "gh.keystore"
signing_keyPassword = "20150318"
va_proguard_rules = "${rootDir}/vasdk/proguard/proguard-rules.pro"
AIDL_CLIENT_PACKAGE_NAME = "com.gh.gamecenter"
// 是否启用媒体存储重定向,开启必须使用共享UID模式!!!
VA_ENABLE_MEDIA_REDIRECT = false
// 媒体存储重定向的插件包名
MEDIA_PACKAGE_NAME = "com.gh.gamecenter.media.module"
PLUGIN_VERSION = '1.0.0'
PLUGIN_VERSION_CODE = 1_00_00
PLUGIN_APPLICATION_ID = "com.gh.gamecenter"
PLUGIN_APK_PATH_PREFIX = "vasdk/"
PLUGIN_MANGER_APK_PATH = "${PLUGIN_APK_PATH_PREFIX}plugin/manager"
PLUGIN_LOADER_APK_PATH = "${PLUGIN_APK_PATH_PREFIX}plugin/loader"
PLUGIN_RUNTIME_APK_PATH = "${PLUGIN_APK_PATH_PREFIX}plugin/runtime"
}
// android dependencies
// 光环助手dependencies.gradle已经有的就不用重复定义了
ext {
shadow_version = "1.0.3"
swipeRefresh = "1.1.0"
glide = "4.12.0"
mmkv = "1.2.8"
flycoTablayout = "3.0.0"
smartRefresh = "2.0.3"
versionCompare = "1.4.1"
boltsTasks = "1.4.0"
utilcodex = "com.blankj:utilcodex:1.30.4"
}

View File

@ -81,3 +81,5 @@ android.injected.testOnly = false
# 动态配置插件
isRelease = true
useVaSdk = true
isSplitVa = false

View File

@ -37,4 +37,6 @@ interface IAppProvider : IProvider {
fun getFlavor(): String
fun getIsBrandNewInstall(): Boolean
fun getPluginVersion(): String
}

View File

@ -99,6 +99,16 @@ class AboutFragment : ToolbarFragment() {
}
}
}
mBinding.aboutTvVersion.setOnLongClickListener {
appProvider?.let {
val pluginVersion = it.getPluginVersion()
if(pluginVersion.isNotEmpty()) {
toast("插件V${pluginVersion}")
}
}
false
}
}
@SuppressLint("SetTextI18n")

View File

@ -2,12 +2,16 @@
# @author juntao
# @2023.03.06
git_sha=`git rev-parse --short HEAD`
git_sha=$(git rev-parse --short HEAD)
versionName=$(awk -v FS="versionName = " 'NF>1{print $2}' dependencies.gradle | sed "s/\"//g")
versionCode=$(awk -v FS="versionCode = " 'NF>1{print $2}' dependencies.gradle | sed "s/\"//g")
build_time=$(TZ=Asia/Shanghai date +'%Y-%m%d-%H%M')
cwd=$(cd "$(dirname "$0")"; pwd)
PACKAGE_NAME=$(sed -n "$(sed -n "/^[[:blank:]]*applicationId/=" dependencies.gradle)p" dependencies.gradle | awk -F '=' '{print $NF}' | sed "s/[[:blank:]]*[\"']*//g")
MODULE_VERSION=$(sed -n "$(sed -n "/^[[:blank:]]*VA_VERSION[^_]/=" dependencies_vasdk.gradle)p" dependencies_vasdk.gradle | awk -F '=' '{print $NF}' | sed "s/[[:blank:]]*[\"']*//g")
cwd=$(
cd "$(dirname "$0")"
pwd
)
apk_release_path=""
# 重置 app build.gradle
@ -19,41 +23,109 @@ git checkout module_sensors_data/build.gradle
# 开启 mapping 上传
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' '1 a plugins { id "io.sentry.android.gradle" version "2.1.5" }' app/build.gradle
sed -i '' 's/var isTestBuild = true/var isTestBuild = false/g' module_sensors_data/build.gradle
sed -i '' '1 a plugins { id "io.sentry.android.gradle" version "2.1.5" }' app/build.gradle
sed -i '' 's/var isTestBuild = true/var isTestBuild = false/g' module_sensors_data/build.gradle
else
sed -i '1 a plugins { id "io.sentry.android.gradle" version "2.1.5" }' app/build.gradle
sed -i 's/var isTestBuild = true/var isTestBuild = false/g' module_sensors_data/build.gradle
sed -i '1 a plugins { id "io.sentry.android.gradle" version "2.1.5" }' app/build.gradle
sed -i 's/var isTestBuild = true/var isTestBuild = false/g' module_sensors_data/build.gradle
fi
./gradlew --stop
./gradlew clean
mkdir -p release/
OPTIONS=$(getopt -o '' -l config_id:,sdk_platform:,sdk_version:,app_id:,app_name:,channel:,activate_reporting_ratio:,first_launch_jump:,output:,unix_timestamp:,sdk_type:,keypoint_action_reporting:, -- "$@")
OPTIONS=$(getopt -o '' -l config_id:,sdk_platform:,sdk_version:,app_id:,app_name:,channel:,activate_reporting_ratio:,first_launch_jump:,output:,unix_timestamp:,sdk_type:,keypoint_action_reporting:,va_version:,va_url:, -- "$@")
eval set -- "$OPTIONS"
while true; do
case "$1" in
--config_id) config_id="$2"; shift 2;;
--sdk_platform) sdk_platform="$2"; shift 2;;
--sdk_version) sdk_version="$2"; shift 2;;
--channel) channel="$2"; shift 2;;
--activate_reporting_ratio) activate_reporting_ratio="$2"; shift 2;;
--first_launch_jump) first_launch_jump="$2"; shift 2;;
--output) output="$2"; shift 2;;
--unix_timestamp) unix_timestamp="$2"; shift 2;;
--app_id) app_id="$2"; shift 2;;
--app_name) app_name="$2"; shift 2;;
--sdk_type) sdk_type="$2"; shift 2;;
--keypoint_action_reporting) keypoint_action_reporting="$2"; shift 2;;
--) shift; break;;
*) echo "Invalid option: $1" >&2; exit 1;;
esac
case "$1" in
--config_id)
config_id="$2"
shift 2
;;
--sdk_platform)
sdk_platform="$2"
shift 2
;;
--sdk_version)
sdk_version="$2"
shift 2
;;
--channel)
channel="$2"
shift 2
;;
--activate_reporting_ratio)
activate_reporting_ratio="$2"
shift 2
;;
--first_launch_jump)
first_launch_jump="$2"
shift 2
;;
--output)
output="$2"
shift 2
;;
--unix_timestamp)
unix_timestamp="$2"
shift 2
;;
--app_id)
app_id="$2"
shift 2
;;
--app_name)
app_name="$2"
shift 2
;;
--sdk_type)
sdk_type="$2"
shift 2
;;
--keypoint_action_reporting)
keypoint_action_reporting="$2"
shift 2
;;
--va_version)
va_version="$2"
shift 2
;;
--va_url)
va_url="$2"
shift 2
;;
--)
shift
break
;;
*)
echo "Invalid option: $1" >&2
exit 1
;;
esac
done
echo "==================== 打包配置的一些变量 ============================="
echo "git_sha=$git_sha"
echo "versionName=$versionName"
echo "versionCode=$versionCode"
echo "build_time=$build_time"
echo "PACKAGE_NAME=$PACKAGE_NAME"
echo "MODULE_VERSION=$MODULE_VERSION 这个是va组件版本号"
echo "va_version=$va_version 这个是va插件版本"
echo "cwd=$cwd"
echo "=================================================================="
if [ "${va_url}" != "" ]; then
echo "======================== 下载插件 =================================="
curl -o app/src/main/assets/artifacts.zip "$va_url"
echo "=================================================================="
fi
mkdir -p $output
function updateChannelIfNeeded {
if [ "${channel}" != "" ]; then
java -jar ${cwd}/ApkChannelPackage.jar put -c $channel $1 release
@ -63,10 +135,7 @@ function updateChannelIfNeeded {
fi
}
# 保存 output 文件名
if [ "${output}" != "" ]; then
apk_release_path="$output"
fi
# 保存 config_id
if [ "${config_id}" != "" ]; then
@ -100,10 +169,11 @@ fi
# 是否选择了 sdk 类型
if [ "${sdk_platform}" != "" ]; then
apk_release_path="${output}/${PACKAGE_NAME}_${versionName}_${versionCode}_${channel}_${MODULE_VERSION}_${va_version}_${sdk_type}_${sdk_platform}_${sdk_version}_${unix_timestamp}.apk"
if [ "${activate_reporting_ratio}" == "" ]; then
activate_reporting_ratio="100"
fi
# 调整上报比例
# 调整上报比例
sed -i "s/int ACTIVATE_REPORTING_RATIO = 100/int ACTIVATE_REPORTING_RATIO = ${activate_reporting_ratio}/g" app/build.gradle
sed -i "s/String SDK_VERSION = \"\"/String SDK_VERSION = \"${sdk_version}\"/g" app/build.gradle
@ -118,30 +188,35 @@ if [ "${sdk_platform}" != "" ]; then
sed -i "s/bytedanceApplog = \"6.15.4\"/bytedanceApplog = \"${sdk_version}\"/g" dependencies.gradle
fi
./gradlew aTR -I init.gradle
./gradlew :app:aTR -I init.gradle
echo "${sdk_version}_${activate_reporting_ratio}_光环助手_${versionName}_${versionCode}_头条推广包_${git_sha}_${build_time}"
cp -R app/build/outputs/apk/tea/release/app-tea-release.apk "${apk_release_path}"
fi
fi
# 广点通包
if [ "${sdk_platform}" == "guangdiantong" ]; then
# 广点通 SDK 执行 ASM 后处理后会有问题
./gradlew aGR
./gradlew :app:aGR
echo "光环助手_${versionName}_${versionCode}_广点通推广包_${git_sha}_${build_time}"
cp -R app/build/outputs/apk/gdt/release/app-gdt-release.apk "${apk_release_path}"
fi
# 快手包
if [ "${sdk_platform}" == "kuaishou" ]; then
./gradlew aKR -I init.gradle
./gradlew :app:aKR -I init.gradle
echo "光环助手_${versionName}_${versionCode}_快手推广包_${git_sha}_${build_time}"
cp -R app/build/outputs/apk/kuaishou/release/app-kuaishou-release.apk "${apk_release_path}"
fi
updateChannelIfNeeded ${apk_release_path}
updateChannelIfNeeded "${output}/${apk_release_path}"
else
apk_release_path="${output}/${PACKAGE_NAME}_${versionName}_${versionCode}_${MODULE_VERSION}_${va_version}_${unix_timestamp}.apk"
./gradlew :app:assemblePublishRelease -I init.gradle
cp -R app/build/outputs/apk/publish/release/app-publish-release.apk "${apk_release_path}"
fi
# 重置 app build.gradle
@ -149,4 +224,4 @@ git checkout app/build.gradle
# 重置 module_common build.gradle
git checkout module_common/build.gradle
# 重置 module_sensors_data build.gradle
git checkout module_sensors_data/build.gradle
git checkout module_sensors_data/build.gradle

57
setting_vasdk.gradle Normal file
View File

@ -0,0 +1,57 @@
include "va-main"
project(":va-main").projectDir = file("vasdk/app")
include "va-lib"
project(":va-lib").projectDir = file("vasdk/lib")
include "va-lib-res"
project(":va-lib-res").projectDir = file("vasdk/lib-res")
include "va-sandhook"
project(":va-sandhook").projectDir = file("vasdk/sandhook")
include "va-library-commons"
project(":va-library-commons").projectDir = file("vasdk/commons")
include "va-feature-realname"
project(":va-feature-realname").projectDir = file("vasdk/feature/realname-window")
include ":ndownload"
include "va-feature-update"
project(":va-feature-update").projectDir = file("vasdk/feature/update")
include "va-feature-cloud"
project(":va-feature-cloud").projectDir = file("vasdk/feature/cloud")
include "va-feature-login"
project(":va-feature-login").projectDir = file("vasdk/feature/login")
include "va-feature-ads"
project(":va-feature-ads").projectDir = file("vasdk/feature/ads")
include "va-feature-floatingwindow"
project(":va-feature-floatingwindow").projectDir = file("vasdk/feature/floating-window")
include "va-core"
project(":va-core").projectDir = file("vasdk/core")
include "va-common"
project(":va-common").projectDir = file("vasdk/common")
include "va-flavor"
project(":va-flavor").projectDir = file("vasdk/flavor")
include "va-feature-archive"
project(":va-feature-archive").projectDir = file("vasdk/feature/archive")
include "va-library-network"
project(":va-library-network").projectDir = file("vasdk/library/network")
include "aar-beizi_ad_sdk"
project(":aar-beizi_ad_sdk").projectDir = file("vasdk/aar/beizi_ad_sdk")
include "aar-beizi_fusion_sdk"
project(":aar-beizi_fusion_sdk").projectDir = file("vasdk/aar/beizi_fusion_sdk")
include "va-plugin-host-lib"
project(":va-plugin-host-lib").projectDir = file("vasdk/plugin/host-lib")
include "va-plugin-floating"
project(":va-plugin-floating").projectDir = file("vasdk/plugin/floating")
include "va-plugin-manager"
project(":va-plugin-manager").projectDir = file("vasdk/plugin/manager")
include "va-plugin-constant"
project(":va-plugin-constant").projectDir = file("vasdk/plugin/constant")
include "va-plugin-runtime"
project(":va-plugin-runtime").projectDir = file("vasdk/plugin/runtime")
include "va-plugin-loader"
project(":va-plugin-loader").projectDir = file("vasdk/plugin/loader")
include "va-plugin-host"
project(":va-plugin-host").projectDir = file("vasdk/plugin/host")
include "va-plugin-base"
project(":va-plugin-base").projectDir = file("vasdk/plugin/base")
include "va-plugin-library-easyfloat"
project(":va-plugin-library-easyfloat").projectDir = file("vasdk/plugin/library/easyfloat")

View File

@ -2,7 +2,8 @@ include ':app'
include ':libraries:LGLibrary'
include ':libraries:QQShare'
include ':libraries:Matisse'
include ':vspace-bridge:vspace'
include "vspace-bridge"
project(":vspace-bridge").projectDir = file("vspace-bridge/vspace")
include ':module_core'
include ':module_common'
include ':module_login'
@ -25,3 +26,5 @@ include ':feature:new_feedback'
include ':feature:qq_game'
include ':feature:realname-window'
include ':module_internal_test'
apply from: 'setting_vasdk.gradle'

1
vasdk Submodule

Submodule vasdk added at e5451f9e6f