Compare commits

...

10 Commits

56 changed files with 2172 additions and 325 deletions

4
.gitignore vendored
View File

@ -9,4 +9,6 @@ build/
release-app/
test-app/
scripts/apk-channel/
app/src/test/java/com/gh/gamecenter
app/src/test/java/com/gh/gamecenter
app/src/main/assets-debug/
app/src/main/assets-release/

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

@ -75,7 +75,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 = ""
@ -164,6 +164,15 @@ android {
flavorDimensions("env", "region")
sourceSets {
debug {
assets.srcDirs += 'src/main/assets-debug'
}
release {
assets.srcDirs += 'src/main/assets-release'
}
publish {
java.srcDirs = ['src/main/java', "src/default/java"]
}
@ -368,7 +377,7 @@ dependencies {
kapt "com.alibaba:arouter-compiler:$arouterVersion"
implementation project(':ndownload')
implementation project(':vspace-bridge:vspace')
implementation project(':vspace-bridge')
implementation (project(':module_common')) {
exclude group: 'androidx.swiperefreshlayout'
@ -408,13 +417,22 @@ dependencies {
exclude group: 'androidx.swiperefreshlayout'
}
internalImplementation(project(':module_internal_test'))
// 根据BUILD_PUSH_TYPE决定使用哪个推送SDK目前默认使用阿里云推送
def pushProject = findProperty('BUILD_PUSH_TYPE') == 'jg'
? project(':feature:jg_push') : project(':feature:acloud_push')
implementation(pushProject) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(":va-lib"))
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")
implementation project(":va-plugin-host")
implementation project(":va-archive")
}
File propFile = file('sign.properties')

View File

@ -1,32 +1,79 @@
package com.gh.vspace
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.Keep
import com.gh.gamecenter.R
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.databinding.LayoutPersonalOtherItemBinding
import com.gh.vspace.installexternalgames.InstallExternalGameActivity
import com.lg.vspace.VaApp
import com.lg.vspace.plugin.host.PluginHelper
import com.lightgame.utils.Utils
import com.lightgame.utils.toast.ToastHelper
import com.lody.virtual.client.core.VirtualCore
import java.io.File
@Keep
class ExternalGameUsage : IExternalGamesUsage {
override fun addInstallExternalGameButton(viewParent: ViewGroup) {
class ExternalGameUsage : ITestCase {
private fun buttonTemplate(viewParent: ViewGroup, id: Int, fn: (LayoutPersonalOtherItemBinding) -> Unit) {
val context = viewParent.context
viewParent.findViewById<View>(R.id.install_game_from_external) ?: run {
viewParent.findViewById<View>(id) ?: run {
val binding = LayoutPersonalOtherItemBinding.inflate(LayoutInflater.from(context)).apply {
root.id = R.id.install_game_from_external
titleTv.text = context.getString(R.string.title_install_external_game)
iconIv.setImageResource(R.drawable.ic_personal_my_game)
root.setOnClickListener {
VHelper.connectService {
context.startActivity(
InstallExternalGameActivity.getIntent(context)
.apply { flags = flags or Intent.FLAG_ACTIVITY_NEW_TASK })
}
}
root.id = id
fn(this)
}
viewParent.addView(binding.root, 0)
}
}
override fun addInstallExternalGameButton(viewParent: ViewGroup) {
val context = viewParent.context
buttonTemplate(viewParent, R.id.install_game_from_external) {
it.titleTv.text = context.getString(R.string.title_install_external_game)
it.iconIv.setImageResource(R.drawable.ic_personal_my_game)
it.root.setOnClickListener {
VHelper.connectService {
context.startActivity(
InstallExternalGameActivity.getIntent(context)
.apply { flags = flags or Intent.FLAG_ACTIVITY_NEW_TASK })
}
}
}
}
override fun addInstallPluginButton(viewParent: ViewGroup) {
buttonTemplate(viewParent, R.id.install_plugin) {
it.titleTv.text = "安装64位插件"
it.root.setOnClickListener {
val file = File("/data/local/tmp/gh-plugins/artifacts.zip")
if (file.exists()) {
Utils.log(VHelper.LOG_TAG, "有本地更新文件: 64位插件")
// TODO: 补充debug插件更新
ToastUtils.showToast("暂未实现debug功能")
} else {
ToastUtils.showToast("data/local/tmp没有push文件")
}
}
}
}
override fun addInstallPlugin32Button(viewParent: ViewGroup) {
buttonTemplate(viewParent, R.id.install_plugin_32) {
it.titleTv.text = "安装32位插件"
it.root.setOnClickListener {
val file = File("/data/local/tmp/gh-plugins/artifacts32.zip")
if (file.exists()) {
// TODO: 补充debug插件更新
ToastUtils.showToast("暂未实现debug功能")
} else {
ToastUtils.showToast("data/local/tmp没有push文件")
}
}
}
}
}

View File

@ -25,6 +25,11 @@ class ExternalGameAdapter(private val games: List<ExternalGameUiState>, private
路径:${item.apkPath}
""".trimIndent()
}
holder.update.setOnClickListener {
onItemClickListener.onItemClick(item, OnItemClickListener.ClickType.CLICK_INSTALL)
}
holder.install.goneIf(item.isInstalled) {
holder.install.setOnClickListener {
onItemClickListener.onItemClick(item, OnItemClickListener.ClickType.CLICK_INSTALL)

View File

@ -8,4 +8,5 @@ class ExternalGameViewHolder(binding: LayoutExternalGameItemBinding) : RecyclerV
val install = binding.btnInstall
val uninstall = binding.btnUninstall
val start = binding.btnStart
val update = binding.btnUpdate
}

View File

@ -16,6 +16,7 @@ import com.gh.gamecenter.databinding.FragmentInstallExternalGamesBinding
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lg.vspace.VirtualAppManager
import com.lightgame.download.DownloadEntity
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
@ -105,6 +106,15 @@ class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
private fun install(externalGameUiState: ExternalGameUiState) {
val bit =
externalGameUiState.externalGameEntity.cpuAbi.let { if (it.size == 1 && it.contains("armeabi-v7a")) "32" else "64" }
VHelper.install(requireContext(), DownloadEntity().apply {
externalGameUiState.externalGameEntity.apply {
packageName = apkPackageName
path = apkPath
}
}, true)
if (VHelper.showDialogIfVSpaceIsNeeded(
requireContext(),
"",
@ -144,7 +154,9 @@ class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
com.gh.gamecenter.BuildConfig.VERSION_NAME,
HaloApp.getInstance().channel,
"",
""
"",
com.lg.core.BuildConfig.VERSION_NAME,
HaloApp.getInstance().oaid
)
requireActivity().startActivity(intent)
}

View File

@ -24,6 +24,14 @@
android:visibility="gone"
tools:visibility="visible" />
<Button
android:id="@+id/btn_update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_update"
android:visibility="visible"
tools:visibility="visible" />
<Button
android:id="@+id/btn_uninstall"
android:layout_width="wrap_content"

View File

@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="install_game_from_external" type="id" />
<item name="install_plugin" type="id" />
<item name="install_plugin_32" type="id" />
</resources>

View File

@ -2,6 +2,7 @@
<resources>
<string name="title_install_external_game">从SD卡安装</string>
<string name="text_install">安装</string>
<string name="text_update">更新</string>
<string name="text_uninstall">卸载</string>
<string name="text_start">启动</string>
</resources>

View File

@ -86,7 +86,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,com.lg.vspace.common" />
<!-- 去掉 SDK 一些流氓权限 -->
<uses-permission
@ -777,7 +800,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

@ -203,6 +203,10 @@ object AdDelegateHelper {
return mDownloadManagerAd != null && !isMatchAdFreeRule(mDownloadManagerAd) && isMatchDownloadManagerAdDisplayRule()
}
fun shouldShowHelperLaunchAd(): Boolean {
return mVGameLaunchAd != null && !isMatchAdFreeRule(mVGameLaunchAd) && isMatchAdDisplayRule(mVGameLaunchAd, Constants.SP_LAST_HELPER_LAUNCH_AD_SHOW_TIME)
}
/**
* 是否需要显示游戏搜索广告
*/
@ -247,10 +251,11 @@ object AdDelegateHelper {
/**
* 是否大于广告管理展示间隔时长
*/
private fun isMatchDownloadManagerAdDisplayRule(): Boolean {
mDownloadManagerAd?.displayRule?.run {
private fun isMatchDownloadManagerAdDisplayRule(): Boolean = isMatchAdDisplayRule(mDownloadManagerAd, Constants.SP_LAST_DOWNLOAD_MANAGER_AD_SHOW_TIME)
private fun isMatchAdDisplayRule(adConfig: AdConfig?, spKey: String): Boolean {
adConfig?.displayRule?.run {
if (adDisplayInterval > 0) {
val lastShowTime = SPUtils.getLong(Constants.SP_LAST_DOWNLOAD_MANAGER_AD_SHOW_TIME, 0L)
val lastShowTime = SPUtils.getLong(spKey, 0L)
val durationInMinutes = (System.currentTimeMillis() - lastShowTime).toFloat() / 1000 / 60
return durationInMinutes > adDisplayInterval
} else {

View File

@ -0,0 +1,44 @@
package com.gh.ad
import android.content.Context
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.lg.vspace.ui.launcher.ILaunchAd
@Route(path = RouteConsts.provider.vaAd, name = "畅玩启动页广告")
class LaunchAdImpl : ILaunchAd {
override fun init(context: Context?) {
}
override fun requestAd(fragment: Fragment, container: ViewGroup, maskView: View) {
if (AdDelegateHelper.shouldShowHelperLaunchAd()) {
val launchAd = AdDelegateHelper.vGameLaunchAd
val showThirdPartyAd = launchAd?.displayRule?.adSource == AdDelegateHelper.AD_TYPE_SDK
val thirdPartyAd = launchAd?.thirdPartyAd
if (showThirdPartyAd && thirdPartyAd != null) {
AdDelegateHelper.requestThirdPartyBannerAd(
fragment,
container,
thirdPartyAd,
DisplayUtils.getScreenWidthInDp(fragment.requireActivity()),
) { isSuccess ->
maskView.goneIf(!isSuccess)
if (isSuccess) {
SPUtils.setLong(Constants.SP_LAST_HELPER_LAUNCH_AD_SHOW_TIME, System.currentTimeMillis())
}
}
}
}
}
}

View File

@ -15,8 +15,11 @@ 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.feedback.view.suggest.SuggestionActivity
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 {
@ -37,6 +40,7 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
&& activity !is SkipActivity
&& activity !is AuthorizationActivity
&& activity !is SplashAdActivity
&& activity !is SuggestionActivity
) {
activity.startActivity(SplashAdActivity.getIntent(activity))
}
@ -73,6 +77,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

@ -220,7 +220,7 @@ class DefaultJsApi(
runOnUiThread {
// 若畅玩列表中安装了,优先启动畅玩游戏
if (VHelper.isInstalled(packageName)) {
if (!VHelper.showDialogIfVSpaceIsNeeded(context, "", "", "", "")) {
VHelper.validateVSpaceBeforeAction(context, packageName, null) {
VHelper.launch(context, packageName)
}
} else {

View File

@ -16,7 +16,7 @@ class ValidateVSpaceHandler : DownloadChainHandler() {
}
if (asVGame) {
VHelper.validateVSpaceBeforeAction(context, gameEntity) {
VHelper.validateVSpaceBeforeAction(context,gameEntity.getUniquePackageName(), gameEntity) {
closure.invoke()
}
} else {

View File

@ -21,14 +21,17 @@ import com.gh.gamecenter.common.utils.EnvHelper;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.core.utils.UrlFilterUtils;
import com.gh.gamecenter.entity.AppEntity;
import com.gh.gamecenter.entity.GameGuidePopupEntity;
import com.gh.gamecenter.entity.NewApiSettingsEntity;
import com.gh.gamecenter.entity.NewSettingsEntity;
import com.gh.gamecenter.entity.VNewSetting;
import com.gh.gamecenter.entity.VSetting;
import com.gh.gamecenter.feature.entity.SettingsEntity;
import com.gh.gamecenter.feature.entity.SimulatorEntity;
import com.gh.gamecenter.feature.utils.ContentBlockedHelper;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.gh.gamecenter.retrofit.service.VApiService;
import com.gh.vspace.VHelper;
import com.halo.assistant.HaloApp;
@ -39,8 +42,12 @@ import org.json.JSONObject;
import java.io.IOException;
import java.util.Locale;
import io.reactivex.Single;
import io.reactivex.SingleSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.BehaviorSubject;
import okhttp3.ResponseBody;
public class Config {
@ -69,6 +76,10 @@ public class Config {
private static NewApiSettingsEntity.NightMode mNightModeSetting;
private static SimulatorEntity mNewSimulatorEntity;
private static VSetting mVSetting;
private static VNewSetting mVNewSetting;
private static AppEntity mNew32UpdateEntity;
public static BehaviorSubject<VNewSetting> vNewSettingSubject = BehaviorSubject.create();
private static GameGuidePopupEntity mGameGuidePopupEntity;
private static SharedPreferences mDefaultSharedPreferences;
@ -197,6 +208,27 @@ public class Config {
return mVSetting;
}
@Nullable
public static VNewSetting getVNewSettingEntity() {
if (mVNewSetting == null) {
try {
String json = SPUtils.getString(Constants.SP_V_NEW_SETTINGS);
if (!TextUtils.isEmpty(json)) {
mVNewSetting = GsonUtils.fromJson(json, VNewSetting.class);
vNewSettingSubject.onNext(mVNewSetting);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return mVNewSetting;
}
@Nullable
public static AppEntity getNew32UpdateEntity() {
return mNew32UpdateEntity;
}
/**
* 请求网络数据,尝试刷新畅玩相关配置
*/
@ -217,6 +249,36 @@ public class Config {
});
}
@SuppressLint("CheckResult")
public static void getNewSetting() {
VApiService vApi = RetrofitManager.getInstance().getVApi();
vApi.getNewSettings(BuildConfig.VERSION_NAME, Build.VERSION.SDK_INT).flatMap(new Function<VNewSetting, SingleSource<AppEntity>>() {
@Override
public SingleSource<AppEntity> apply(VNewSetting data) throws Exception {
mVNewSetting = data;
vNewSettingSubject.onNext(mVNewSetting);
SPUtils.setString(Constants.SP_V_NEW_SETTINGS, GsonUtils.toJson(data));
if (data.getVa() != null && data.getVa().getArch32() != null) {
String versionNameByPackageName = PackageUtils.getVersionNameByPackageName(data.getVa().getArch32().getPackageName());
return vApi.getNewPackageUpdate(
BuildConfig.VERSION_NAME,
versionNameByPackageName != null ? versionNameByPackageName : "",
HaloApp.getInstance().getChannel()
);
}
return Single.error(new IllegalStateException("VNewSetting entity is not expected"));
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BiResponse<AppEntity>() {
@Override
public void onSuccess(AppEntity data) {
mNew32UpdateEntity = data;
}
});
}
@Nullable
public static GameGuidePopupEntity getGameGuidePopupEntity() {
return mGameGuidePopupEntity;
@ -271,6 +333,7 @@ public class Config {
});
refreshVSettingEntity();
getNewSetting();
RetrofitManager.getInstance()
.getApi().getGameGuidePopup(Build.MANUFACTURER, Build.VERSION.RELEASE, Build.MODEL, channel, BuildConfig.VERSION_NAME)

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 {
@ -86,4 +87,6 @@ class AppProviderImpl : IAppProvider {
override fun setSkippingThirdParty(isSkippingThirdParty: Boolean) {
HaloApp.getInstance().isSkippingThirdParty = isSkippingThirdParty
}
override fun getPluginVersion(): String = HostUtils.getPluginVersion()
}

View File

@ -50,8 +50,6 @@ object ArchiveDownloadButtonHelper {
}
downloadBtn.setOnClickListener {
when {
// 检查是否已安装畅玩助手
!VHelper.isVSpaceInstalled(context) -> showVSpaceTipDialog(context, gameEntity)
// 检查是否已安装游戏
!VHelper.isInstalled(packageName) -> {
// 检查游戏是否在安装中

View File

@ -508,11 +508,18 @@ object DownloadObserver {
"space_schema_type",
if (downloadEntity.packageName == VHelper.VSPACE_32BIT_PACKAGENAME) "32位" else "64位"
)
} else if(downloadEntity.gameId == Constants.HALO_FUN_NEW_32_GAME_ID) {
SensorsBridge.trackEvent(
"HaloFunDownloadDone",
"space_schema_type",
"32位(新)"
)
}
if (downloadEntity.gameId != Constants.GHZS_GAME_ID
&& downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) != Constants.SIMULATOR_DOWNLOAD
&& downloadEntity.gameId != Constants.HALO_FUN_GAME_ID
&& downloadEntity.gameId != Constants.HALO_FUN_NEW_32_GAME_ID
) {
val trackJson = downloadEntity.customPageTrackDataJson
val kvs = if (!trackJson.isNullOrBlank()) {

View File

@ -282,7 +282,7 @@ object GameActivityDownloadHelper {
location: String,
traceEvent: ExposureEvent
) {
VHelper.validateVSpaceBeforeAction(context, gameEntity) {
VHelper.validateVSpaceBeforeAction(context,gameEntity.getUniquePackageName(), gameEntity) {
GamePermissionDialogFragment.show((context as AppCompatActivity), gameEntity, gameEntity.info) {
DialogUtils.checkDownload(
context,

View File

@ -93,12 +93,13 @@ object NewFlatLogUtils {
// 畅玩助手更新弹窗展示事件
@JvmStatic
fun logHaloFunUpdateDialogShow(gameId: String, gameName: String, gameArchitecture: String) {
fun logHaloFunUpdateDialogShow(gameId: String, gameName: String, gameArchitecture: String, targetVaVersion: String) {
val json = json {
KEY_EVENT to "halo_fun_update_dialog_show"
"game_id" to gameId
"game_name" to gameName
"game_architecture" to gameArchitecture
"target_va_version" to targetVaVersion
parseAndPutMeta().invoke(this)
}
log(json)
@ -142,12 +143,13 @@ object NewFlatLogUtils {
// 畅玩助手更新弹窗点击事件
@JvmStatic
fun logHaloFunUpdateDialogClick(dialogType: String, buttonType: String, architecture: String) {
fun logHaloFunUpdateDialogClick(dialogType: String, buttonType: String, architecture: String, targetVaVersion: String) {
val json = json {
KEY_EVENT to "halo_fun_update_dialog_click"
"dialog_type" to dialogType
KEY_BUTTON_TYPE to buttonType
"architecture" to architecture
"target_va_version" to targetVaVersion
parseAndPutMeta().invoke(this)
}
log(json)

View File

@ -137,6 +137,9 @@ 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;
import retrofit2.HttpException;
@ -282,6 +285,8 @@ public class MainActivity extends BaseActivity {
Config.getGhzsSettings();
} else if (Config.getVSettingEntity() == null) {
Config.refreshVSettingEntity();
} else if (Config.getVNewSettingEntity() == null) {
Config.getNewSetting();
}
// 耗时操作
@ -737,14 +742,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.isInnerInstalled(gamePackageName)) {
launchGame(gamePackageName).invoke();
} else {
VHelper.postOnInitialized(launchGame(gamePackageName));
}
}, 500);
break;
case KEY_MARKET_DETAILS:
@ -762,6 +764,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;
};
}
/**
* 应用跳转
*/
@ -929,6 +943,8 @@ public class MainActivity extends BaseActivity {
Config.getGhzsSettings();
} else if (Config.getVSettingEntity() == null) {
Config.refreshVSettingEntity();
} else if (Config.getVNewSettingEntity() == null) {
Config.getNewSetting();
}
mPackageViewModel.checkData();
@ -939,8 +955,10 @@ public class MainActivity extends BaseActivity {
// 接收登录和登出更新事件统计的 Meta
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(EBReuse reuse) {
if (reuse.getType().equals(LOGIN_TAG) || reuse.getType().equals(LOGOUT_TAG)) {
boolean isLoginEvent = reuse.getType().equals(LOGIN_TAG);
if (isLoginEvent || reuse.getType().equals(LOGOUT_TAG)) {
MetaUtil.INSTANCE.refreshMeta();
VHelper.INSTANCE.updateAuthorizeInfo(isLoginEvent);
}
}

View File

@ -3,6 +3,7 @@ package com.gh.gamecenter;
import static com.gh.gamecenter.common.constant.EntranceConsts.ENTRANCE_BROWSER;
import static com.gh.gamecenter.common.constant.EntranceConsts.ENTRANCE_PUSH;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_ANSWER;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_ARCHIVE_LOGIN;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_ARTICLE;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_CATEGORY;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_COLUMN;
@ -21,6 +22,7 @@ import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QQ_GAME;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QQ_GROUP;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QQ_QUN;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_QUESTION;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_RESTART_GAME;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_SUGGESTION;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_TOOLBOX;
import static com.gh.gamecenter.common.constant.EntranceConsts.HOST_UPLOAD_VIDEO;
@ -64,8 +66,10 @@ import com.gh.gamecenter.core.utils.ToastUtils;
import com.gh.gamecenter.entity.SubjectRecommendEntity;
import com.gh.gamecenter.entity.VideoLinkEntity;
import com.gh.gamecenter.feature.utils.PlatformUtils;
import com.gh.gamecenter.login.view.LoginActivity;
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel;
import com.gh.gamecenter.video.videomanager.VideoManagerActivity;
import com.gh.vspace.VHelper;
import com.gh.vspace.shortcut.OnCreateShortcutResult;
import com.gh.vspace.shortcut.ShortcutManager;
import com.gh.vspace.shortcut.ShortcutPermissionTipsDialog;
@ -405,6 +409,27 @@ public class SkipActivity extends BaseActivity {
} catch (JSONException ignored) {
}
break;
case HOST_ARCHIVE_LOGIN:
String gamePkg = uri.getQueryParameter(EntranceConsts.KEY_GAME_PKG);
if(CheckLoginUtils.isLogin()) {
VHelper.INSTANCE.updateAuthorizeInfo(true);
} else {
Bundle newBundle = new Bundle();
newBundle.putString(EntranceConsts.KEY_TO, LoginActivity.class.getName());
EntranceUtils.jumpActivity(this, null, newBundle, (resultCode, data) -> {
if(CheckLoginUtils.isLogin()) {
VHelper.INSTANCE.updateAuthorizeInfo(true);
}
VHelper.launch(this, gamePkg, false, false);
finish();
});
return;
}
break;
case HOST_RESTART_GAME:
String restartGamePkg = uri.getQueryParameter(EntranceConsts.KEY_GAME_PKG);
VHelper.launch(this, restartGamePkg, false, true);
break;
default:
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页
return;

View File

@ -34,7 +34,9 @@ class AppEntity(
*/
var alert: String? = null,
// 关联64位更新
var relation: AppEntity? = null
var relation: AppEntity? = null,
@SerializedName("_id")
var id: String? = null
) : Parcelable {
fun isAlertEveryTime() = alert == "EVERY_TIME_OPEN"

View File

@ -0,0 +1,42 @@
package com.gh.gamecenter.entity
import com.google.gson.annotations.SerializedName
class VNewSetting {
@SerializedName("va")
var va: Va? = null
@SerializedName("va_plugin")
var vaPlugin: VaPlugin? = null
class Va(
@SerializedName("32-bit")
val arch32: VaArch? = null,
)
class VaArch(
val size: String,
@SerializedName("package")
val packageName: String,
@SerializedName("version")
val versionName: String,
@SerializedName("version_code")
val versionCode: Int,
val url: String
)
data class VaPlugin(
@SerializedName("_id")
val id: String?,
@SerializedName("version_name")
val versionName: String?,
@SerializedName("change_log")
var changeLog: String?,
@SerializedName("url_32")
val url32: String?,
@SerializedName("url_64")
val url64: String?,
)
}

View File

@ -16,6 +16,7 @@ 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
@ -26,6 +27,7 @@ import com.gh.gamecenter.livedata.Event
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
@ -58,6 +60,8 @@ object PackageRepository {
@Volatile
private var mIsInitialisingData = false
var installedPkgRefreshed = false
var vaPkgRefreshed = false
val gameUpdateLiveData = MutableLiveData<List<GameUpdateEntity>>()
val gameInstalledLiveData = MutableLiveData<List<GameInstall>>()
@ -79,13 +83,20 @@ object PackageRepository {
*/
@JvmStatic
fun initData() {
Utils.log("xxx", "PackageRepository::initData::mIsInitialisingData = $mIsInitialisingData")
if (mIsInitialisingData) return
mIsInitialisingData = true
installedPkgRefreshed = false
vaPkgRefreshed = false
runOnIoThread {
if (gameInstalled.isNotEmpty()) gameInstalled.clear()
if (mInstalledGameList.isNotEmpty()) mInstalledGameList.clear()
if (gameUpdate.isNotEmpty()) gameUpdate.clear()
if (gameUpdate.isNotEmpty()) {
gameUpdate.clear()
Utils.log("xxx", "清除更新数据")
}
if (mInstalledPkgList.isNotEmpty()) mInstalledPkgList.clear()
val list = PackageUtils.getAllPackageName(mApplication)
@ -93,15 +104,38 @@ object PackageRepository {
uploadAppList()
initFilterPackage(list) { filteredList ->
mIsInitialisingData = false
mInstalledPkgList.addAll(filteredList)
notifyInstallPkgData()
loadInstalledGameDigestAndNotifyData(filteredList)
Utils.log("xxx", "PackageRepository::filteredList::${filteredList}")
loadInstalledGameDigestAndNotifyData(filteredList) {
installedPkgRefreshed = true
mIsInitialisingData = !(installedPkgRefreshed && vaPkgRefreshed)
}
}
loadGhzsUpdate()
// 畅玩游戏更新
var allGames = VHelper.getAllVGameSnapshots()
if (allGames.isNullOrEmpty()) {
VHelper.refreshVGameSnapshot()
allGames = VHelper.getAllVGameSnapshots()
}
val allGamePkgNames = allGames.map { it.packageName }.toArrayList()
if (allGamePkgNames.isNotEmpty()) {
notifyInstallPkgData()
updateFilterPackage(allGamePkgNames) {
Utils.log("xxx", "PackageRepository::filteredList::${allGamePkgNames}")
loadInstalledGameDigestAndNotifyData(
filteredList = allGamePkgNames,
onWorkerThreadOnly = false,
isVGame = true
) {
vaPkgRefreshed = true
mIsInitialisingData = !(installedPkgRefreshed && vaPkgRefreshed)
}
}
}
}
}
@ -134,7 +168,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>() {
@ -209,6 +244,7 @@ object PackageRepository {
filteredList: ArrayList<String>,
onWorkerThreadOnly: Boolean = false,
isVGame: Boolean = false,
loadFinishCallback: (() -> Unit)? = null
) {
var isNotifyUpdate = false
val maxPageCount = (filteredList.size / PAGE_SIZE) + 1
@ -217,6 +253,7 @@ object PackageRepository {
val latch = ObservableUtil.latch(maxPageCount, {
if (isNotifyUpdate || gameUpdateLiveData.value == null) notifyGameUpdateData()
notifyGameInstallData()
loadFinishCallback?.invoke()
}, Any())
while (++page <= maxPageCount) {

View File

@ -3,9 +3,10 @@ package com.gh.gamecenter.packagehelper
import android.app.Application
import android.text.TextUtils
import androidx.lifecycle.*
import com.gh.gamecenter.feature.entity.GameInstall
import com.gh.gamecenter.entity.GameUpdateEntity
import com.gh.gamecenter.feature.entity.GameInstall
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import kotlin.collections.set
class PackageViewModel(
@ -79,6 +80,7 @@ class PackageViewModel(
if (mRepository.gameInstalled.size == 0
|| PackageFilterManager.hasPendingPackage()
) {
Utils.log("xxx", "PackageViewModel call initData")
mRepository.initData()
}
}

View File

@ -60,7 +60,7 @@ import com.gh.gamecenter.room.AppDatabase
import com.gh.gamecenter.setting.SettingBridge
import com.gh.gamecenter.wrapper.MainWrapperFragment
import com.gh.gamecenter.wrapper.MainWrapperViewModel
import com.gh.vspace.IExternalGamesUsage
import com.gh.vspace.ITestCase
import com.google.android.material.appbar.AppBarLayout
import com.halo.assistant.HaloApp
import com.jakewharton.rxbinding2.view.RxView
@ -695,7 +695,11 @@ class HaloPersonalFragment : BaseLazyFragment() {
(try {
Class.forName("com.gh.vspace.ExternalGameUsage")?.newInstance()
} catch (e: Exception) {
} as? IExternalGamesUsage)?.addInstallExternalGameButton(mStubBinding.otherItems)
} as? ITestCase)?.apply {
addInstallExternalGameButton(mStubBinding.otherItems)
addInstallPluginButton(mStubBinding.otherItems)
addInstallPlugin32Button(mStubBinding.otherItems)
}
}
mStubBinding.settingItem.run {

View File

@ -1,9 +1,11 @@
package com.gh.gamecenter.retrofit.service
import com.gh.gamecenter.entity.AppEntity
import com.gh.gamecenter.entity.VNewSetting
import com.gh.gamecenter.entity.VSetting
import io.reactivex.Single
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Query
interface VApiService {
@ -24,4 +26,16 @@ interface VApiService {
@GET("setting")
fun getSettings(@Query("version") version: String?, @Query("android") androidSdkVersion: Int): Single<VSetting>
@GET("new/setting")
fun getNewSettings(
@Query("version") version: String?,
@Query("android") androidSdkVersion: Int,
): Single<VNewSetting>
@GET("new/upgrade")
fun getNewPackageUpdate(
@Query("version") version: String?,
@Query("va_version") vaVersion: String?,
@Query("channel") channel: String,
): Single<AppEntity>
}

View File

@ -4,8 +4,10 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
public interface IExternalGamesUsage {
public interface ITestCase {
void addInstallExternalGameButton(@NonNull ViewGroup viewParent);
void addInstallPluginButton(@NonNull ViewGroup viewParent);
void addInstallPlugin32Button(@NonNull ViewGroup viewParent);
}

View File

@ -2,8 +2,11 @@ package com.gh.vspace
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.database.sqlite.SQLiteDiskIOException
import android.os.*
import androidx.annotation.WorkerThread
import com.blankj.utilcode.util.LogUtils
import com.gh.download.simple.DownloadMessageHandler
import com.gh.download.simple.SimpleDownloadManager
import com.gh.gamecenter.common.retrofit.BiResponse
@ -22,7 +25,11 @@ import com.lg.download.DownloadStatus
import com.lg.download.httpclient.DefaultHttpClient
import com.lg.ndownload.DownloadConfigBuilder
import com.lg.vspace.VirtualAppManager
import com.lg.vspace.archive.data.Const
import com.lg.vspace.archive.ui.ArchiveManager
import com.lg.vspace.archive.ui.interfaces.ArchiveProgressPageListener
import com.lightgame.utils.Utils
import com.lody.virtual.client.core.VirtualCore
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import java.io.File
@ -43,6 +50,31 @@ object VArchiveHelper {
// 本地存档存放的位置
val archivePath by lazy { HaloApp.getInstance().filesDir.absolutePath + File.separator }
private var messenger: Messenger? = null
private val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
when (msg.what) {
Const.MSG_USE_ARCHIVE -> {
msg.data?.let {
onApplyGameArchiveFinished(
packageName = it.getString(Const.EXTRA_PACKAGE_NAME, ""),
isSuccess = it.getBoolean(Const.EXTRA_IS_SUCCESS, false)
)
}
}
Const.MSG_GENERATE_ARCHIVE -> {
msg.data?.let {
onSaveGameArchiveFinished(
packageName = it.getString(Const.EXTRA_PACKAGE_NAME, ""),
isSuccess = it.getBoolean(Const.EXTRA_IS_SUCCESS, false)
)
}
}
}
messenger = null
}
}
fun init() {
DownloadMessageHandler.registerGlobalStatusChangedListener { simpleDownloadEntity, downloadStatus ->
when (downloadStatus) {
@ -162,8 +194,26 @@ object VArchiveHelper {
mSaveArchiveListener = saveArchiveListener
// 记录最近一次创建的存档文件
mLatestArchiveFile = archiveFile
val intent = VirtualAppManager.getGenerateArchiveIntent(context, config, packageName, archiveFile)
context.startActivity(intent)
if (VHelper.isLegacyInstalled(packageName)) {
val intent = VirtualAppManager.getGenerateArchiveIntent(context, config, packageName, archiveFile)
context.startActivity(intent)
} else {
if (VirtualCore.get().isRunInExtProcess(packageName)) {
val intent = VirtualAppManager.getGenerateArchiveIntent(context, config, packageName, archiveFile)
prepareExtIntent(intent)
context.startActivity(intent)
} else {
ArchiveManager.generatePackage(context, packageName, config, archiveFile,
object : ArchiveProgressPageListener {
override fun onCancel() {
}
override fun completed(isSuccess: Boolean) {
onSaveGameArchiveFinished(packageName, isSuccess)
}
})
}
}
}
/**
@ -179,8 +229,43 @@ object VArchiveHelper {
applyArchiveListener: ((String, Boolean) -> Unit)? = null
) {
mApplyArchiveListener = applyArchiveListener
val intent = VirtualAppManager.getUseArchiveIntent(context, packageName, config, archiveFile)
context.startActivity(intent)
if (VHelper.isLegacyInstalled(packageName)) {
val intent = VirtualAppManager.getUseArchiveIntent(context, packageName, config, archiveFile)
context.startActivity(intent)
} else {
if (VirtualCore.get().isRunInExtProcess(packageName)) {
val intent = VirtualAppManager.getUseArchiveIntent(context, packageName, config, archiveFile)
prepareExtIntent(intent)
context.startActivity(intent)
} else {
ArchiveManager.useArchive(context, packageName, archiveFile, config,
object : ArchiveProgressPageListener {
override fun onCancel() {
}
override fun completed(isSuccess: Boolean) {
LogUtils.d("存档使用 completed : $isSuccess")
if (applyArchiveListener != null) {
applyArchiveListener(packageName, isSuccess)
}
}
})
}
}
}
private fun prepareExtIntent(intent: Intent) {
intent.setClassName(
com.lg.vspace.BuildConfig.EXT_PACKAGE_NAME,
"com.lg.vspace.addon.launcher.RemoteGuideActivity"
)
intent.putExtra("callback", Bundle().also {
messenger = Messenger(handler)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
it.putBinder("messenger", messenger!!.binder)
}
})
}
/**

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,307 @@
package com.gh.vspace
import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.gh.common.exposure.ExposureUtils
import com.gh.common.exposure.ExposureUtils.DownloadType.DOWNLOAD
import com.gh.common.exposure.ExposureUtils.DownloadType.UPDATE
import com.gh.common.util.*
import com.gh.common.util.NewFlatLogUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.BaseDraggableDialogFragment
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.databinding.DialogVspace32NewBinding
import com.gh.gamecenter.entity.AppEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.view.DownloadButton
import com.halo.assistant.HaloApp
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadConfig
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus.*
import com.lightgame.utils.AppManager
import java.io.File
class VSpace32NewDialogFragment : BaseDraggableDialogFragment() {
private var mAppEntity: AppEntity? = null
private var mGameId: String = ""
private var mGameName: String = ""
private val mDownloadUrl by lazy { mAppEntity?.url ?: "" }
private val mBinding by lazy { DialogVspace32NewBinding.inflate(layoutInflater) }
private var mIsLogInstallShow = false
private var mIsLogAutoInstallClick = false
private var mIsClickDownloadThisTime = false // 是否本次弹出Dialog点击的下载按钮
private val mDataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
if (downloadEntity.url == mDownloadUrl && isAdded) {
updateDownloadButton(downloadEntity)
}
}
override fun onDataInit(downloadEntity: DownloadEntity) {
onDataChanged(downloadEntity)
}
}
override fun getRootView(): View = mBinding.root
override fun getDragCloseView(): View = mBinding.dragClose
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mAppEntity = arguments?.get(KEY_APP_ENTITY_32) as AppEntity
mGameId = arguments?.getString(EntranceConsts.KEY_GAME_ID) ?: ""
mGameName = arguments?.getString(EntranceConsts.KEY_GAME_NAME) ?: ""
}
@SuppressLint("ClickableViewAccessibility")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return mBinding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val mViewModel = viewModelProvider<VSpaceDialogFragment.VSpaceDialogViewModel>()
mViewModel.packageLiveData.observe(this) {
if (it.packageName == VHelper.VSPACE_32BIT_NEW_PACKAGENAME) {
dismissAllowingStateLoss()
}
}
val downloadSnapshot = DownloadManager.getInstance()
.getDownloadEntitySnapshotByPackageName(VHelper.VSPACE_32BIT_NEW_PACKAGENAME)
mBinding.downloadBtn.text = if (downloadSnapshot?.status == done) "安装" else "下载"
mBinding.downloadBtn.buttonStyle = DownloadButton.ButtonStyle.NORMAL
mBinding.descTv.text = "$mGameName》需安装完整的畅玩服务组件,安装后即可给您带来急速的畅玩体验~"
mBinding.privacyPolicyTv.setOnClickListener {
NewFlatLogUtils.logHaloFunEvent("halo_fun_download_dialog_privacy_click")
DirectUtils.directToWebView(requireContext(), Constants.SMOOTH_GAME_PRIVACY_POLICY_ADDRESS)
}
if (downloadSnapshot?.status == done) {
NewFlatLogUtils.logHaloFunEvent("halo_fun_32_install_tip_dialog_show")
SensorsBridge.trackEvent("HaloFunExpandInstallDialogShow")
mIsLogInstallShow = true
} else {
NewFlatLogUtils.logHaloFun32DialogEvent("halo_fun_32_download_tip_dialog_show", mGameId, mGameName)
SensorsBridge.trackEvent("HaloFunExpandDownloadDialogShow", "game_id", mGameId, "game_name", mGameName)
}
mBinding.downloadBtn.setOnClickListener {
if (downloadSnapshot?.status == done) {
if (!File(downloadSnapshot.path).exists()) {
ToastUtils.toast("畅玩组件已损坏,即将重新下载")
DownloadManager.getInstance().cancel(downloadSnapshot.url)
DownloadManager.getInstance().add(downloadSnapshot)
} else {
PackageInstaller.install(requireContext(), downloadSnapshot)
NewFlatLogUtils.logHaloFunEvent("halo_fun_32_install_tip_dialog_click")
SensorsBridge.trackEvent("HaloFunExpandInstallButtonClick")
}
} else {
val downloadEntity = DownloadEntity()
val name = "畅玩游戏助手V" + mAppEntity?.version
val downloadId = PackageInstaller.createDownloadId(name)
downloadEntity.url = mDownloadUrl
downloadEntity.name = name
downloadEntity.platform = "官方版"
downloadEntity.gameId = Constants.HALO_FUN_NEW_32_GAME_ID
downloadEntity.path = PackageInstaller.getDownloadPathWithId(downloadId, "apk")
downloadEntity.packageName = VHelper.VSPACE_32BIT_NEW_PACKAGENAME
downloadEntity.addMetaExtra(DownloadConfig.KEY_PROGRESS_CALLBACK_INTERVAL, "200")
val gameEntity = GameEntity(downloadEntity.gameId, downloadEntity.name)
gameEntity.gameVersion = mAppEntity?.version ?: ""
// 确定下载类型
val downloadType =
if (arguments?.getBoolean(VSpaceDialogFragment.KEY_IS_UPDATE) == true) UPDATE else DOWNLOAD
downloadEntity.exposureTrace = ExposureUtils.logADownloadExposureEvent(
gameEntity,
downloadEntity.platform,
null,
downloadType
).toJson()
mIsClickDownloadThisTime = true
AppExecutor.uiExecutor.executeWithDelay({
DownloadManager.getInstance().cancel(mDownloadUrl)
DownloadManager.getInstance().add(downloadEntity)
}, 200)
DataCollectionUtils.uploadDownload(HaloApp.getInstance(), downloadEntity, "开始")
NewFlatLogUtils.logHaloFun32DialogEvent("halo_fun_32_download_tip_dialog_click", mGameId, mGameName)
SensorsBridge.trackEvent("HaloFunExpandDownloadDialogDownloadClick")
}
}
}
override fun onStart() {
super.onStart()
DownloadManager.getInstance().addObserver(mDataWatcher)
// 上面监听安装包名变化的 LiveData 监听有可能被冲掉了
// 手动再检查一下安装状态,避免出现已安装但是没有 dismiss 弹窗的问题
if (PackageUtils.isInstalledFromAllPackage(requireContext(), VHelper.VSPACE_32BIT_NEW_PACKAGENAME)) {
dismissAllowingStateLoss()
}
}
override fun onStop() {
super.onStop()
DownloadManager.getInstance().removeObserver(mDataWatcher)
}
private fun updateDownloadButton(downloadEntity: DownloadEntity) {
val downloadBtn = mBinding.downloadBtn
downloadBtn.progress = (downloadEntity.progress * 10).toInt()
when (downloadEntity.status) {
downloading -> {
downloadBtn.setText(R.string.pause)
downloadBtn.progress = (downloadEntity.percent * 10).toInt()
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.DOWNLOADING_NORMAL
downloadBtn.setOnClickListener {
DownloadManager.getInstance().pause(mDownloadUrl)
}
}
pause -> {
downloadBtn.setText(R.string.resume)
downloadBtn.setOnClickListener {
DownloadManager.getInstance().resume(downloadEntity, true)
}
}
overflow,
timeout,
neterror,
diskisfull,
waiting,
subscribe -> {
downloadBtn.setText(R.string.waiting)
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.DOWNLOADING_NORMAL
downloadBtn.setOnClickListener {
DownloadManager.getInstance().resume(downloadEntity, false)
}
}
done -> {
downloadBtn.setText(R.string.install)
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.INSTALL_NORMAL
if (!mIsLogInstallShow) {
NewFlatLogUtils.logHaloFunEvent("halo_fun_32_install_tip_dialog_show")
NewFlatLogUtils.logHaloFunInstallTipDialogShow("32位")
SensorsBridge.trackEvent("HaloFunExpandInstallDialogShow")
mIsLogInstallShow = true
}
val isVSpace32DownloadOnly =
downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.VSPACE_32_DOWNLOAD_ONLY
val isAutoInstall = SPUtils.getBoolean(Constants.SP_AUTO_INSTALL, true)
if (!isVSpace32DownloadOnly && isAutoInstall && !mIsLogAutoInstallClick && mIsClickDownloadThisTime) {
NewFlatLogUtils.logHaloFunEvent("halo_fun_32_install_tip_dialog_click")
SensorsBridge.trackEvent("HaloFunExpandInstallButtonClick")
mIsLogAutoInstallClick = true
}
downloadBtn.setOnClickListener {
if (!File(downloadEntity.path).exists()) {
ToastUtils.toast("畅玩组件已损坏,即将重新下载")
DownloadManager.getInstance().cancel(downloadEntity.url)
DownloadManager.getInstance().add(downloadEntity)
} else {
PackageInstaller.install(requireContext(), downloadEntity)
NewFlatLogUtils.logHaloFunEvent("halo_fun_32_install_tip_dialog_click")
SensorsBridge.trackEvent("HaloFunExpandInstallButtonClick")
}
}
}
cancel,
hijack,
notfound,
uncertificated,
unqualified -> {
downloadBtn.text = "下载"
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.NORMAL
downloadBtn.setOnClickListener {
DownloadManager.getInstance().resume(downloadEntity, true)
}
}
else -> {
// do nothing
}
}
}
companion object {
const val KEY_APP_ENTITY_32 = "app_entity_32"
@JvmStatic
fun showDownloadDialog(
context: Context?,
appEntity32: AppEntity,
gameId: String = "",
gameName: String = ""
) {
val fragmentActivity: FragmentActivity = if (context is FragmentActivity) {
context
} else {
val currentActivity = AppManager.getInstance().currentActivity()
if (currentActivity is FragmentActivity) {
currentActivity
} else {
throw IllegalStateException("current activity context must be FragmentActivity")
}
}
// 防止重复弹出
if (hasDialogDisplayedInCurrentActivity(fragmentActivity)) return
val downloadDialog = VSpace32NewDialogFragment().apply {
arguments = Bundle().apply {
putParcelable(KEY_APP_ENTITY_32, appEntity32)
putString(EntranceConsts.KEY_GAME_ID, gameId)
putString(EntranceConsts.KEY_GAME_NAME, gameName)
}
}
downloadDialog.show(
fragmentActivity.supportFragmentManager,
VSpace32NewDialogFragment::class.java.name
)
}
private fun hasDialogDisplayedInCurrentActivity(fragmentActivity: FragmentActivity): Boolean {
val fragments: List<Fragment> = fragmentActivity.supportFragmentManager.fragments
fragments.forEach { fragment ->
if (fragment is VSpace32NewDialogFragment) return true
}
return false
}
}
}

View File

@ -0,0 +1,303 @@
package com.gh.vspace
import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.gh.common.exposure.ExposureUtils
import com.gh.common.exposure.ExposureUtils.DownloadType.DOWNLOAD
import com.gh.common.exposure.ExposureUtils.DownloadType.UPDATE
import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.common.util.PackageInstaller
import com.gh.common.util.PackageUtils
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.databinding.DialogVspaceUpdate32NewBinding
import com.gh.gamecenter.entity.AppEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.halo.assistant.HaloApp
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadConfig
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus.*
import com.lightgame.utils.AppManager
import java.io.File
class VSpaceUpdate32NewDialogFragment : BaseDialogFragment() {
private var mAppEntity: AppEntity? = null
private var mGameId: String = ""
private var mGameName: String = ""
private val mDownloadUrl by lazy { mAppEntity?.url ?: "" }
private val mBinding by lazy { DialogVspaceUpdate32NewBinding.inflate(layoutInflater) }
private val mDataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
if (downloadEntity.url == mDownloadUrl && isAdded) {
updateDownloadButton(downloadEntity)
}
}
override fun onDataInit(downloadEntity: DownloadEntity) {
onDataChanged(downloadEntity)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mAppEntity = arguments?.get(KEY_APP_ENTITY_32) as AppEntity
mGameId = arguments?.getString(EntranceConsts.KEY_GAME_ID) ?: ""
mGameName = arguments?.getString(EntranceConsts.KEY_GAME_NAME) ?: ""
}
@SuppressLint("ClickableViewAccessibility")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return mBinding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val mViewModel = viewModelProvider<VSpaceDialogFragment.VSpaceDialogViewModel>()
mViewModel.packageLiveData.observe(this) {
if (it.packageName == VHelper.VSPACE_32BIT_NEW_PACKAGENAME) {
dismissAllowingStateLoss()
}
}
val downloadSnapshot = DownloadManager.getInstance()
.getDownloadEntitySnapshotByPackageName(VHelper.VSPACE_32BIT_NEW_PACKAGENAME)
mBinding.downloadBtn.text = if (downloadSnapshot?.status == done) "安装" else "下载"
mBinding.downloadBtn.buttonStyle = DownloadButton.ButtonStyle.NORMAL
mBinding.contentTv.text = "$mGameName》需安装完整的畅玩服务组件,安装后即可给您带来急速的畅玩体验~"
mBinding.downloadBtn.setOnClickListener {
NewFlatLogUtils.logHaloFun32DialogEvent("halo_fun_32_update_tip_dialog_click", mGameId, mGameName)
if (downloadSnapshot?.status == done) {
if (!File(downloadSnapshot.path).exists()) {
ToastUtils.toast("畅玩组件已损坏,即将重新下载")
DownloadManager.getInstance().cancel(downloadSnapshot.url)
DownloadManager.getInstance().add(downloadSnapshot)
} else {
PackageInstaller.install(requireContext(), downloadSnapshot)
}
} else {
val downloadEntity = DownloadEntity()
val name = "畅玩游戏助手V" + mAppEntity?.version
val downloadId = PackageInstaller.createDownloadId(name)
downloadEntity.url = mDownloadUrl
downloadEntity.name = name
downloadEntity.platform = "官方版"
downloadEntity.gameId = Constants.HALO_FUN_NEW_32_GAME_ID
downloadEntity.path = PackageInstaller.getDownloadPathWithId(downloadId, "apk")
downloadEntity.packageName = VHelper.VSPACE_32BIT_NEW_PACKAGENAME
downloadEntity.addMetaExtra(DownloadConfig.KEY_PROGRESS_CALLBACK_INTERVAL, "200")
val gameEntity = GameEntity(downloadEntity.gameId, downloadEntity.name)
gameEntity.gameVersion = mAppEntity?.version ?: ""
// 确定下载类型
val downloadType =
if (arguments?.getBoolean(VSpaceDialogFragment.KEY_IS_UPDATE) == true) UPDATE else DOWNLOAD
downloadEntity.exposureTrace = ExposureUtils.logADownloadExposureEvent(
gameEntity,
downloadEntity.platform,
null,
downloadType
).toJson()
AppExecutor.uiExecutor.executeWithDelay({
DownloadManager.getInstance().cancel(mDownloadUrl)
DownloadManager.getInstance().add(downloadEntity)
}, 200)
DataCollectionUtils.uploadDownload(HaloApp.getInstance(), downloadEntity, "开始")
}
}
}
override fun onStart() {
super.onStart()
DownloadManager.getInstance().addObserver(mDataWatcher)
// 上面监听安装包名变化的 LiveData 监听有可能被冲掉了
// 手动再检查一下安装状态,避免出现已安装但是没有 dismiss 弹窗的问题
if (PackageUtils.isInstalledFromAllPackage(requireContext(), VHelper.VSPACE_32BIT_NEW_PACKAGENAME)
&& mAppEntity?.version == PackageUtils.getVersionNameByPackageName(VHelper.VSPACE_32BIT_NEW_PACKAGENAME)
) {
dismissAllowingStateLoss()
}
}
override fun onStop() {
super.onStop()
DownloadManager.getInstance().removeObserver(mDataWatcher)
}
private fun updateDownloadButton(downloadEntity: DownloadEntity) {
val downloadBtn = mBinding.downloadBtn
downloadBtn.progress = (downloadEntity.progress * 10).toInt()
when (downloadEntity.status) {
downloading -> {
downloadBtn.setText(R.string.pause)
downloadBtn.progress = (downloadEntity.percent * 10).toInt()
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.DOWNLOADING_NORMAL
downloadBtn.setOnClickListener {
DownloadManager.getInstance().pause(mDownloadUrl)
NewFlatLogUtils.logHaloFun32DialogEvent("halo_fun_32_update_tip_dialog_click", mGameId, mGameName)
}
}
pause -> {
downloadBtn.setText(R.string.resume)
downloadBtn.setOnClickListener {
DownloadManager.getInstance().resume(downloadEntity, true)
NewFlatLogUtils.logHaloFun32DialogEvent("halo_fun_32_update_tip_dialog_click", mGameId, mGameName)
}
}
overflow,
timeout,
neterror,
diskisfull,
waiting,
subscribe -> {
downloadBtn.setText(R.string.waiting)
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.DOWNLOADING_NORMAL
downloadBtn.setOnClickListener {
DownloadManager.getInstance().resume(downloadEntity, false)
NewFlatLogUtils.logHaloFun32DialogEvent("halo_fun_32_update_tip_dialog_click", mGameId, mGameName)
}
}
done -> {
downloadBtn.setText(R.string.install)
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.INSTALL_NORMAL
downloadBtn.setOnClickListener {
if (!File(downloadEntity.path).exists()) {
ToastUtils.toast("畅玩组件已损坏,即将重新下载")
DownloadManager.getInstance().cancel(downloadEntity.url)
DownloadManager.getInstance().add(downloadEntity)
} else {
PackageInstaller.install(requireContext(), downloadEntity)
NewFlatLogUtils.logHaloFun32DialogEvent(
"halo_fun_32_update_tip_dialog_click",
mGameId,
mGameName
)
}
}
}
cancel,
hijack,
notfound,
uncertificated,
unqualified -> {
downloadBtn.text = "下载"
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.NORMAL
downloadBtn.setOnClickListener {
DownloadManager.getInstance().resume(downloadEntity, true)
NewFlatLogUtils.logHaloFun32DialogEvent("halo_fun_32_update_tip_dialog_click", mGameId, mGameName)
}
}
else -> {
// do nothing
}
}
}
companion object {
const val KEY_APP_ENTITY_32 = "app_entity_32"
const val KEY_AUTO_DOWNLOAD = "auto_download"
const val KEY_IS_UPDATE = "is_update"
@JvmStatic
fun showDownloadDialog(
context: Context?,
appEntity32: AppEntity,
autoDownload: Boolean = false,
isUpdate: Boolean = false,
gameId: String = "",
gameName: String = ""
) {
val fragmentActivity: FragmentActivity = if (context is FragmentActivity) {
context
} else {
val currentActivity = AppManager.getInstance().currentActivity()
if (currentActivity is FragmentActivity) {
currentActivity
} else {
throw IllegalStateException("current activity context must be FragmentActivity")
}
}
// 防止重复弹出
if (hasDialogDisplayedInCurrentActivity(fragmentActivity)) return
NewFlatLogUtils.logHaloFun32DialogEvent("halo_fun_32_update_tip_dialog_show", gameId, gameName)
val downloadDialog = VSpaceUpdate32NewDialogFragment().apply {
arguments = Bundle().apply {
putParcelable(KEY_APP_ENTITY_32, appEntity32)
putString(EntranceConsts.KEY_GAME_ID, gameId)
putString(EntranceConsts.KEY_GAME_NAME, gameName)
putBoolean(KEY_AUTO_DOWNLOAD, autoDownload)
putBoolean(KEY_IS_UPDATE, isUpdate)
}
}
downloadDialog.show(
fragmentActivity.supportFragmentManager,
VSpaceUpdate32NewDialogFragment::class.java.name
)
}
@JvmStatic
fun showDownloadDialog(
context: Context?,
appEntity32: AppEntity,
gameEntity: GameEntity?,
autoDownload: Boolean = false,
isUpdate: Boolean = false
) {
showDownloadDialog(
context,
appEntity32,
autoDownload,
isUpdate,
gameEntity?.id ?: "",
gameEntity?.name ?: ""
)
}
private fun hasDialogDisplayedInCurrentActivity(fragmentActivity: FragmentActivity): Boolean {
val fragments: List<Fragment> = fragmentActivity.supportFragmentManager.fragments
fragments.forEach { fragment ->
if (fragment is VSpaceUpdate32NewDialogFragment) return true
}
return false
}
}
}

View File

@ -320,7 +320,7 @@ class GAppsDownloadDialogFragment : BaseBottomDialogFragment<DialogGappsDownload
context?.let {
mIsInstalling = true
VHelper.batchInstall(it, installFileMap)
VHelper.batchInstall(it, installFileMap, mTriggerPackageName)
}
runOnUiThread {

View File

@ -20,6 +20,7 @@ import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lg.core.BuildConfig
import com.lg.vspace.VirtualAppManager
import com.muugi.shortcut.core.Executor
import com.muugi.shortcut.core.Shortcut
@ -89,8 +90,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 +101,11 @@ class ShortcutManager private constructor() {
}
}
}
if (VHelper.isInnerInstalled(gamePkg)) {
createShortcutLambda.invoke()
} else {
VHelper.postOnInitialized(createShortcutLambda)
}
}
@ -185,25 +191,7 @@ class ShortcutManager private constructor() {
}
}
/**
* 获取游戏快捷方式跳转Intent
* 直接启动游戏
*/
private fun getIntent(gameEntity: GameEntity): Intent {
val intent = mDelegateManager.getStartGameIntent(
gameEntity.getUniquePackageName(),
gameEntity.id,
gameEntity.name ?: "unknown",
gameEntity.icon ?: "",
MetaUtil.getBase64EncodedAndroidId(),
HaloApp.getInstance().gid,
com.gh.gamecenter.BuildConfig.VERSION_NAME,
HaloApp.getInstance().channel,
"", ""
)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
return intent
}
/**
* 获取游戏快捷方式跳转Intent

View File

@ -81,8 +81,11 @@ import com.gh.vspace.VHelper;
import com.github.piasy.biv.BigImageViewer;
import com.github.piasy.biv.loader.fresco.FrescoImageLoader;
import com.lg.ndownload.DownloadCore;
import com.lg.ndownload.DownloadDbManager;
import com.lg.vspace.VaApp;
import com.lightgame.utils.Utils;
import com.llew.huawei.verifier.LoadedApkHuaWei;
import com.lody.virtual.client.core.VirtualCore;
import com.shuyu.gsyvideoplayer.cache.CacheFactory;
import com.shuyu.gsyvideoplayer.player.PlayerFactory;
@ -208,6 +211,7 @@ public class HaloApp extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
VaApp.get().onCreate(this);
initArouter();
mInstance = this;
@ -376,6 +380,7 @@ public class HaloApp extends MultiDexApplication {
});
}
}, delay);
VaApp.get().startSensorLogService();
}
private void initArouter() {
@ -526,6 +531,7 @@ public class HaloApp extends MultiDexApplication {
LoadedApkHuaWei.hookHuaWeiVerifier(this);
DownloadMessageHandler.INSTANCE.init(SimpleDownloadDatabase.getInstance().downloadDao());
VHelper.INSTANCE.preparePluginUpdate();
});
}
@ -617,6 +623,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

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="@drawable/background_shape_white_radius_12_top_only"
android:descendantFocusability="blocksDescendants">
<View
android:id="@+id/bgView"
android:layout_width="match_parent"
android:layout_height="98dp"
android:background="@drawable/vspace_dialog_top_background"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:layout_width="88dp"
android:layout_height="20dp"
android:layout_marginTop="39dp"
android:src="@drawable/ic_smooth_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/descTv"
android:layout_width="280dp"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:includeFontPadding="false"
android:lineSpacingExtra="4dp"
android:textColor="@color/text_subtitle"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bgView"
tools:text="《XXX》需安装完整的畅玩服务组件安装后即可给您带来急速的畅玩体验~" />
<LinearLayout
android:id="@+id/downloadContainer"
android:layout_width="280dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/descTv">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="52dp"
android:layout_marginTop="8dp"
android:background="@drawable/bg_shape_space_radius_8"
android:paddingStart="16dp"
android:paddingEnd="16dp">
<TextView
android:id="@+id/vspace32Tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="32位组件"
android:textColor="@color/text_title"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.gh.gamecenter.feature.view.DownloadButton
android:id="@+id/downloadBtn"
android:layout_width="56dp"
android:layout_height="28dp"
app:download_button_show_progress="true"
app:download_button_text_size="@dimen/secondary_size"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
<TextView
android:id="@+id/privacyPolicyTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginBottom="40dp"
android:text="《畅玩助手服务组件隐私协议》"
android:textColor="@color/theme_font"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/downloadContainer" />
<View
android:id="@+id/drag_close"
android:layout_width="match_parent"
android:layout_height="64dp"
android:clickable="false"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="@dimen/default_dialog_width"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/background_shape_white_radius_8">
<TextView
android:id="@+id/titleTv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="24dp"
android:layout_marginRight="24dp"
android:drawablePadding="4dp"
android:gravity="center"
android:text="服务工具更新提示"
android:textColor="@color/text_title"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/contentTv"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="12dp"
android:layout_marginRight="24dp"
android:lineSpacingExtra="7dp"
android:textColor="@color/text_subtitle"
android:textSize="14sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/titleTv"
tools:text="这里是正文,这里是正文,这里是正文,这里是正文,这里是正文,这里是正文,这里是正文,这里是正文,这里是正文,这里是正文,这里是正文,这里是正文,这里是正文,这里是正文,这里是正文,这里是正文,这里是正文,这里是正文。" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="24dp"
android:layout_marginRight="24dp"
android:layout_marginBottom="24dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/contentTv"
app:layout_constraintBottom_toBottomOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="52dp"
android:layout_marginTop="8dp"
android:background="@drawable/bg_shape_space_radius_8"
android:paddingStart="16dp"
android:paddingEnd="16dp">
<TextView
android:id="@+id/vspace32Tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="32位组件"
android:textColor="@color/text_title"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.gh.gamecenter.feature.view.DownloadButton
android:id="@+id/downloadBtn"
android:layout_width="56dp"
android:layout_height="28dp"
app:download_button_show_progress="true"
app:download_button_text_size="@dimen/secondary_size"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View File

@ -5,11 +5,18 @@ apply from: 'vspace-bridge/config.gradle'
buildscript {
ext.kotlin_version = '1.7.20'
ext.shadow_version = '1.0.5'
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" }
}
@ -20,6 +27,7 @@ buildscript {
// 使用了 1.2.21 在蓝叠模拟器上无法进入首页? 但是不使用又会出现触发 V3 签名...
classpath 'io.github.leon406:AndResGuard-gradle-plugin:1.2.23'
classpath 'com.sensorsdata.analytics.android:android-gradle-plugin2:3.5.3'
classpath "com.lg.shadow.core:gradle-plugin:$shadow_version"
}
}
@ -48,11 +56,13 @@ allprojects {
maven { url 'https://developer.huawei.com/repo/' }
}
}
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

View File

@ -138,4 +138,8 @@ ext {
acloudPush = "3.8.8.1"
jpushVersion = "5.2.4"
}
}
apply from: 'dependencies_vasdk.gradle'
apply from: "${pluginBasePath}/PluginConfig.gradle"
apply from: "${pluginBasePath}/VaConfig.gradle"

30
dependencies_vasdk.gradle Normal file
View File

@ -0,0 +1,30 @@
ext {
vaCompileSdkVersion = 33
vaMinSdkVersion = 21
vaTargetSdkVersion = 28
}
ext {
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"
}
// android dependencies
// 光环助手dependencies.gradle已经有的就不用重复定义了
ext {
shadow_version = '1.0.5'
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

@ -85,3 +85,4 @@ android.injected.testOnly = false
# 动态配置插件
isRelease = true
pluginBasePath=vasdk/

View File

@ -73,6 +73,7 @@ public class Constants {
public static final String GHZS_GAME_ID = "5ae4462c2924bc7936438d07";
public static final String HALO_FUN_GAME_ID = "62bd412bbbf04747cd3de539"; // 畅玩助手ID
public static final String HALO_FUN_NEW_32_GAME_ID = "eeeeeeeeeeeeeeeeeeeeeeee"; // 32位新畅玩助手ID
public static final String EXTRA_DOWNLOAD_TYPE = "extra_download_type";
public static final String EXTRA_IS_MODDED_GAME = "extra_is_modded_game"; // 是否是修改版游戏
@ -221,6 +222,10 @@ public class Constants {
// 畅玩组件的配置
public static final String SP_V_SETTINGS = "v_settings";
// 畅玩,插件的配置
public static final String SP_V_NEW_SETTINGS = "v_new_settings";
// 头像挂件ID
public static final String SP_CHOOSE_AVATAR_ID = "choose_avatar_id";
@ -523,6 +528,7 @@ public class Constants {
public static final String SP_LAST_DOWNLOAD_MANAGER_AD_SHOW_TIME = "last_download_manager_ad_show_time";
public static final String SP_LAST_GAME_SEARCH_AD_SHOW_TIME = "last_game_search_ad_show_time";
public static final String SP_LAST_HELPER_LAUNCH_AD_SHOW_TIME = "last_helper_launch_ad_show_time";
public static final String SP_NEW_FIRST_LAUNCH_VERSION = "isNewFirstLaunchV";
public static final String SP_PLUGIN_AREA_SHOWED_LAUNCH_ID = ""; // 插件化区域显示过的 launchId Tracker.launchId

View File

@ -81,6 +81,10 @@ public class EntranceConsts {
public static final String HOST_QQ_GAME = "qgame";
public static final String HOST_HOME_GAME_COLLECTION_SQUARE = "home_game_collection_square";
public static final String HOST_ARCHIVE_LOGIN = "archive_login";
public static final String HOST_RESTART_GAME = "restart_game";
public static final String KEY_DATA = "data";
public static final String KEY_MESSAGE = "message";
public static final String KEY_MESSAGE_ID = "message_id";

View File

@ -122,6 +122,8 @@ object RouteConsts {
const val push = "/push/push"
const val realName = "/realName/realName"
const val vaAd = "/vaAd/vaAd"
}
}

View File

@ -32,9 +32,9 @@
public static void logMethodWithParams(...);
}
-assumenosideeffects class com.lightgame.utils.Utils {
public static void log(...);
}
#-assumenosideeffects class com.lightgame.utils.Utils {
# public static void log(...);
#}
-assumenosideeffects class com.gh.gamecenter.core.utils.MtaHelper {
public static void onEvent(...);

View File

@ -39,4 +39,6 @@ interface IAppProvider : IProvider {
fun getIsBrandNewInstall(): Boolean
fun setSkippingThirdParty(isSkippingThirdParty: Boolean)
fun getPluginVersion(): String
}

View File

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

View File

@ -6,7 +6,8 @@ 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')
PACKAGE_NAME=$(sed -n "$(sed -n "/^[[:blank:]]*applicationId[[:blank:]]*=/=" dependencies.gradle)p" dependencies.gradle | awk -F '=' '{print $NF}' | sed "s/[[:blank:]]*[\"']*//g")
MODULE_VERSION=$(sed -n "$(sed -n "/^[[:blank:]]*VA_VERSION[^_]/=" vasdk/VaConfig.gradle)p" vasdk/VaConfig.gradle | awk -F '=' '{print $NF}' | sed "s/[[:blank:]]*[\"']*//g")
cwd=$(cd "$(dirname "$0")"; pwd)
apk_release_path=""
@ -26,12 +27,19 @@ else
sed -i 's/var isTestBuild = true/var isTestBuild = false/g' module_sensors_data/build.gradle
fi
if [[ $MODULE_VERSION == *"debug"* ]]; then
build_time_without_divider=$(TZ=Asia/Shanghai date +'%Y%m%d%H%M')L
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' 's/buildConfigField "long", "BUILD_TIME", "0"/buildConfigField "long", "BUILD_TIME", '"\"${build_time_without_divider}\""'/g' module_common/build.gradle
else
sed -i 's/buildConfigField "long", "BUILD_TIME", "0"/buildConfigField "long", "BUILD_TIME", '"\"${build_time_without_divider}\""'/g' module_common/build.gradle
fi
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"
@ -49,11 +57,33 @@ while true; do
--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 +93,7 @@ function updateChannelIfNeeded {
fi
}
# 保存 output 文件名
if [ "${output}" != "" ]; then
apk_release_path="$output"
fi
# 保存 config_id
if [ "${config_id}" != "" ]; then
@ -100,6 +127,7 @@ 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
@ -148,7 +176,19 @@ if [ "${sdk_platform}" != "" ]; then
echo "光环助手_${versionName}_${versionCode}_神马推广包_${git_sha}_${build_time}"
cp -R app/build/outputs/apk/smCn/release/app-sm-cn-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"
if [[ $MODULE_VERSION == *"debug"* ]]; then
./gradlew :app:assembleInternalCnRelease -I init.gradle
cp -R app/build/outputs/apk/internalCn/release/app-internal-cn-release.apk "${apk_release_path}"
else
./gradlew :app:assemblePublishCnRelease -I init.gradle
cp -R app/build/outputs/apk/publishCn/release/app-publish-cn-release.apk "${apk_release_path}"
fi
fi
# 重置 app 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-ext"
project(":va-ext").projectDir = file("vasdk/app-ext")
include "va-ext-lib"
project(":va-ext-lib").projectDir = file("vasdk/lib-ext")
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-cloud"
project(":va-feature-cloud").projectDir = file("vasdk/feature/cloud")
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-archive"
project(":va-archive").projectDir = file("vasdk/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/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'
@ -28,3 +29,5 @@ include ':module_internal_test'
include ':feature:jg_push'
include ':feature:jg_push_lib'
include ':feature:acloud_push'
apply from: 'setting_vasdk.gradle'

1
vasdk Submodule

Submodule vasdk added at 9f1f97e9c4