Compare commits

...

47 Commits

Author SHA1 Message Date
34fafcdfa0 feat: agp 7.1.3 gradle打包产物位置有变更,考虑到插件更新逻辑已变更,不需要在编译光环助手时同步编译插件了,所以修改为手动编译插件,再copy到build/plugin目录 2024-03-01 17:28:51 +08:00
4d2606cc83 refactor: update submodule commit id 2024-03-01 15:19:15 +08:00
8f908b54c7 refactor: update submodule commit id 2024-03-01 14:49:13 +08:00
7af085df34 refactor: update ndownload commit id 2024-03-01 11:01:38 +08:00
00bdb0a3cc refactor: update vasdk commit id. 2024-03-01 10:56:36 +08:00
0d329a19b0 refactor: update vasdk commit id. 2024-03-01 10:56:36 +08:00
2edbfc505c feat: 32位组件安装插件 2024-03-01 10:56:36 +08:00
ee8748a954 refactor: update version 2024-03-01 10:56:36 +08:00
3bdd419183 fix: 插件更新逻辑 2024-03-01 10:56:36 +08:00
7c8c3a4679 refactor: update vasdk commit id. 2024-03-01 10:56:36 +08:00
8fc5be0e51 feat: 添加更新按钮。 2024-03-01 10:56:36 +08:00
6cc73d4b05 fix:修复一体化,畅玩游戏启动判断 2024-03-01 10:56:36 +08:00
fe6405fac3 fix: 修复卸载apk不生效 2024-03-01 10:56:36 +08:00
88dd3ea5ec fix:新旧版本畅玩组件isInstalled语义错误 2024-03-01 10:56:36 +08:00
0641761143 fix:新旧版本畅玩组件isInstalled语义错误 2024-03-01 10:56:36 +08:00
5adde797e1 fix:畅玩游戏无法更新的问题 2024-03-01 10:56:36 +08:00
7c346c632c refactor: update vasdk commit id 2024-03-01 10:56:35 +08:00
17b7101912 refactor: update vasdk commit id 2024-03-01 10:56:35 +08:00
7e1cafee4b refactor: update commit id 2024-03-01 10:56:35 +08:00
03df8e1012 feat: 32位组件更新下载 2024-03-01 10:56:35 +08:00
bb66f4af06 refactor!: 添加测试环境的脚本 2024-03-01 10:56:35 +08:00
6b1e92ee3d refactor!: 添加测试环境的脚本 2024-03-01 10:56:35 +08:00
ec1c92cfe0 feat: new/upgrade接口参数修改 2024-03-01 10:56:35 +08:00
89b85b115e feat: 畅玩32位和插件的更新流程 2024-03-01 10:56:35 +08:00
d4e2788d8d refactor!: 临时修改打包测试版本 2024-03-01 10:55:43 +08:00
865903d0da refactor: 优化畅玩32 debug打包步骤 2024-03-01 10:55:43 +08:00
3afebb1e38 feat: 获取32位组件和插件的接口数据 2024-03-01 10:55:43 +08:00
feab4f4f76 refactor: update commit id 2024-03-01 10:55:43 +08:00
4054f66b4b feat: 修改va配置读取 2024-03-01 10:55:43 +08:00
b5ee2679e9 feat: 修改plugin配置读取 2024-03-01 10:55:43 +08:00
c060480b23 fix: 修复头条,快手等其他flavor脚本打包出错的问题 2024-03-01 10:55:37 +08:00
26f09057ba refactor: upgrade shadow_version to 1.0.4 2024-03-01 10:53:48 +08:00
b1457f795d refactor: update vasdk commit id. 2024-03-01 10:53:48 +08:00
193e4487c9 fix: min sdk version smaller than 21. 2024-03-01 10:53:48 +08:00
32bff3836e refactor: 更新shadow版本至 1.0.3 2024-03-01 10:53:48 +08:00
64c35e9181 refactor: 更新maven拉取顺序 2024-03-01 10:53:48 +08:00
63783e374d refactor: 更新apk文件路径 2024-03-01 10:53:46 +08:00
020222a451 refactor: 下载插件到assets目录 2024-03-01 10:52:04 +08:00
15df636967 refactor: 更新打包脚本 2024-03-01 10:52:01 +08:00
aaa552ffdc feat: 展示64位va插件版本信息 https://jira.shanqu.cc/browse/GHZS-3885 2024-03-01 10:46:44 +08:00
9a372ba269 fix: 过滤va项目的配置&修复错误的assets添加脚步 2024-03-01 10:44:56 +08:00
56383b2938 feat: 光环助手va组件兼容旧版畅玩助手游戏业务 2024-03-01 10:44:56 +08:00
c6f161999d feat: 接入vasdk编译通过 2024-03-01 10:44:56 +08:00
d796739b3c refactor: va模块引用 2024-03-01 10:44:54 +08:00
922c8e5cde feat: 加速器模块占用空间太大,给ci/cd集成增加时间成本,考虑到加速器变更频繁度较低,改为maven引用 2024-03-01 10:43:00 +08:00
e0611ebfca feat: 同步vasdk的代码 2024-03-01 10:43:00 +08:00
fed1f7b90f feat: 接入va模块 2024-03-01 10:42:58 +08:00
40 changed files with 1717 additions and 185 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 = ""
@ -162,6 +162,9 @@ android {
flavorDimensions("env", "region")
sourceSets {
main {
assets.srcDir("${rootProject.buildDir}/plugin")
}
publish {
java.srcDirs = ['src/main/java', "src/default/java"]
}
@ -192,7 +195,8 @@ android {
// internal 内部测试包使用的 flavor接口包含包括测试和正式环境
internal {
dimension "env"
versionNameSuffix "-debug"
// blame_yangfei: test script lines
//versionNameSuffix "-debug"
buildConfigField "String", "DEV_API_HOST", "\"${DEV_API_HOST}\""
buildConfigField "String", "NEW_DEV_API_HOST", "\"${NEW_DEV_API_HOST}\""
@ -368,9 +372,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')) {
@ -408,6 +412,13 @@ 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")
implementation project(":va-plugin-host")
}
File propFile = file('sign.properties')

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(),
"",

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

@ -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

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

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

View File

@ -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

@ -8,7 +8,6 @@ import android.text.TextUtils;
import androidx.annotation.Nullable;
import com.gh.common.util.AdHelper;
import com.gh.common.util.PackageHelper;
import com.gh.common.util.PackageUtils;
import com.gh.gamecenter.BuildConfig;
@ -22,15 +21,18 @@ 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.NewsEntity;
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;
import com.lightgame.utils.Utils;
@ -43,8 +45,12 @@ import java.io.IOException;
import java.util.List;
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 {
@ -73,6 +79,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;
@ -306,6 +316,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;
}
/**
* 请求网络数据,尝试刷新畅玩相关配置
*/
@ -326,6 +357,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;
@ -404,6 +465,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

@ -489,11 +489,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_GAME_ID
&& downloadEntity.gameId != Constants.HALO_FUN_NEW_32_GAME_ID) {
SensorsBridge.trackEventWithExposureSource(
"DownloadProcessFinish",
exposureEvent?.source,

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) {
CertificationDialog.showCertificationDialog(context, gameEntity) {
DialogUtils.checkDownload(

View File

@ -144,6 +144,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;
@ -302,6 +304,8 @@ public class MainActivity extends BaseActivity {
Config.getGhzsSettings();
} else if (Config.getVSettingEntity() == null) {
Config.refreshVSettingEntity();
} else if (Config.getVNewSettingEntity() == null) {
Config.getNewSetting();
}
// 耗时操作
@ -735,14 +739,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:
@ -760,6 +761,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;
};
}
/**
* 应用跳转
*/
@ -937,6 +950,8 @@ public class MainActivity extends BaseActivity {
Config.getGhzsSettings();
} else if (Config.getVSettingEntity() == null) {
Config.refreshVSettingEntity();
} else if (Config.getVNewSettingEntity() == null) {
Config.getNewSetting();
}
mPackageViewModel.checkData();

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

@ -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

@ -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

@ -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
@ -14,6 +15,7 @@ import android.view.View
import androidx.annotation.WorkerThread
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.*
import com.g00fy2.versioncompare.Version
import com.gh.ad.AdDelegateHelper
import com.gh.common.constant.Config
import com.gh.common.exposure.ExposureUtils
@ -22,6 +24,9 @@ import com.gh.common.util.*
import com.gh.common.util.NewFlatLogUtils
import com.gh.download.DownloadManager
import com.gh.download.PackageObserver
import com.gh.download.simple.DownloadListener
import com.gh.download.simple.DownloadMessageHandler
import com.gh.download.simple.SimpleDownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.SplashScreenActivity
import com.gh.gamecenter.common.base.GlobalActivityManager
@ -46,20 +51,31 @@ 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.download.DownloadError
import com.lg.download.DownloadStatus
import com.lg.download.httpclient.DefaultHttpClient
import com.lg.ndownload.DownloadConfigBuilder
import com.lg.vspace.VaApp
import com.lg.vspace.VirtualAppManager
import com.lg.vspace.bridge.BuildConfig
import com.lg.vspace.plugin.host.PluginFileUtils
import com.lg.vspace.plugin.host.PluginHelper
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
import com.lightgame.utils.Utils
import com.va.host.HostUtils
import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.PublishSubject
import org.greenrobot.eventbus.EventBus
import java.io.File
import java.util.*
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.TimeUnit
object VHelper {
@ -84,6 +100,7 @@ object VHelper {
const val LOG_TAG = "VSPACE"
const val DEFAULT_VSPACE_PACKAGENAME = "com.lg.vspace"
const val VSPACE_32BIT_PACKAGENAME = "$DEFAULT_VSPACE_PACKAGENAME.addon"
const val VSPACE_32BIT_NEW_PACKAGENAME = com.lg.vspace.BuildConfig.EXT_PACKAGE_NAME
private val mDelegateManager by lazy { VirtualAppManager.get() }
private val mPackageInstalledLiveData by lazy { MutableLiveData<String>() }
@ -231,6 +248,12 @@ object VHelper {
mIsAppVisible = false
}
})
runOnIoThread {
val allGames = vGameDao.getAll().map { it.packageName }.toArrayList()
if (allGames.isNotEmpty()) {
PackageRepository.addInstalledGames(allGames, true)
}
}
}
val config = Config.getVSettingEntity()?.va
@ -288,7 +311,14 @@ object VHelper {
callbackClosure: (() -> Unit)? = null
) {
Utils.log(LOG_TAG, "尝试连接 V 服务")
val isOldCwInstalled = PackageUtils.isInstalledFromAllPackage(
HaloApp.getInstance().applicationContext,
BuildConfig.AIDL_SERVER_PACKAGE_NAME
)
if (!isOldCwInstalled) {
Utils.log(LOG_TAG, "包名[${BuildConfig.AIDL_SERVER_PACKAGE_NAME}]应用没有安装")
return
}
if (!shouldConnectSilently) {
toastIfServiceConnectTimeout()
}
@ -453,10 +483,18 @@ object VHelper {
}
/**
* 是否安装此包名的畅玩游戏
* 此语义是判断是否安装的畅玩游戏
* 畅玩组件是否已安装此包名的畅玩游戏, 包含 1. 分体式畅玩, 2. 一体式畅玩 两个地方
* 否则应该单独针对分体式和一体式判断
*/
@JvmStatic
fun isInstalled(packageName: String?): Boolean {
fun isInstalled(packageName: String?) = isInnerInstalled(packageName) || isLegacyInstalled(packageName)
/**
* 分体式畅玩是否安装了游戏
*/
@JvmStatic
fun isLegacyInstalled(packageName: String?): Boolean {
var isInstalled = mInstalledInfoList.any { it.packageName == packageName }
Utils.log(LOG_TAG, "$packageName 已安装列表里 -> $isInstalled")
@ -477,6 +515,10 @@ object VHelper {
return isInstalled
}
@JvmStatic
fun isInnerInstalled(packageName: String?) =
VaApp.get().appManager.installedGamesInfo.any { it.packageName == packageName }
/**
* 启动成功,五秒内退出才显示反馈弹框
*/
@ -502,18 +544,35 @@ object VHelper {
* 获取游戏占用的空间
*/
fun getAppOccupiedSpace(packageName: String): Long {
return try {
mDelegateManager.getAppOccupiedSpace(packageName)
} catch (e: Exception) {
e.printStackTrace()
0
return if (isInnerInstalled(packageName)) {
VaApp.get().appManager.getAppOccupiedSpace(packageName)
} else {
try {
mDelegateManager.getAppOccupiedSpace(packageName)
} catch (e: Exception) {
e.printStackTrace()
0
}
}
}
/**
* 在执行 callback 前先检查组件是否已安装,是否可下载
*/
fun validateVSpaceBeforeAction(context: Context, gameEntity: GameEntity?, callback: () -> Unit) {
fun validateVSpaceBeforeAction(
context: Context,
packageName: String?,
gameEntity: GameEntity?,
callback: () -> Unit
) {
if (isLegacyInstalled(packageName)) {
oldCwValidateVSpaceBeforeAction(context, gameEntity, callback)
} else {
newCwValidateVspaceBeforeAction(context, gameEntity, callback)
}
}
private fun oldCwValidateVSpaceBeforeAction(context: Context, gameEntity: GameEntity?, callback: () -> Unit) {
if (showDialogIfVSpaceIsNeeded(
context,
gameEntity?.id ?: "",
@ -626,6 +685,88 @@ object VHelper {
callback.invoke()
}
/**
* 判断是否需要安装32位组件64位直接callback
*/
private fun newCwValidateVspaceBeforeAction(context: Context, gameEntity: GameEntity?, callback: () -> Unit) {
val bit = gameEntity?.gameBit ?: ""
if (bit == "32") {
val vaArch32 = Config.getVNewSettingEntity()?.va?.arch32
if (vaArch32 == null) {
ToastUtils.toast("畅玩助手空间暂未上线")
return
}
val new32UpdateEntity = Config.getNew32UpdateEntity()
val is32VSpaceInstalled = PackageUtils.isInstalledFromAllPackage(context, vaArch32.packageName)
if (!is32VSpaceInstalled) {
val appEntity = AppEntity()
if (new32UpdateEntity != null && (new32UpdateEntity.versionCode > vaArch32.versionCode)) {
appEntity.versionCode = new32UpdateEntity.versionCode
appEntity.version = new32UpdateEntity.version
appEntity.url = new32UpdateEntity.url
} else {
appEntity.versionCode = vaArch32.versionCode
appEntity.version = vaArch32.versionName
appEntity.url = vaArch32.url
}
VSpace32NewDialogFragment.showDownloadDialog(
context,
appEntity,
gameId = gameEntity?.id ?: "",
gameName = gameEntity?.name ?: "",
)
return
}
if (new32UpdateEntity != null && (PackageUtils.getVersionCodeByPackageName(vaArch32.packageName) < new32UpdateEntity.versionCode)) {
val dialogType = if (new32UpdateEntity.isForce) "强制更新" else "提示更新"
NewFlatLogUtils.logHaloFunUpdateDialogShow(
gameEntity?.id ?: "",
gameEntity?.name ?: "",
"32位"
)
DialogHelper.showDialog(
context = context,
title = "服务工具更新提示",
content = new32UpdateEntity.content.toString(),
cancelText = "立即更新",
confirmText = if (new32UpdateEntity.isForce) "取消" else "继续游戏",
cancelClickCallback = {
NewFlatLogUtils.logHaloFunUpdateDialogClick(
dialogType,
"立即更新",
"32位"
)
VSpaceUpdate32NewDialogFragment.showDownloadDialog(
context,
new32UpdateEntity,
gameEntity,
autoDownload = true,
isUpdate = true
)
},
confirmClickCallback = {
NewFlatLogUtils.logHaloFunUpdateDialogClick(dialogType, "继续游戏", "")
if (!new32UpdateEntity.isForce) {
callback.invoke()
}
},
extraConfig = DialogHelper.Config(centerTitle = true),
uiModificationCallback = {
if (new32UpdateEntity.isAlertEveryTime()) {
it.confirmTv.visibility = View.GONE
it.cancelTv.setTextColor(R.color.theme_font.toColor(context))
}
it.confirmTv.setTextColor(R.color.text_subtitle.toColor(context))
}
)
return
}
}
callback.invoke()
}
/**
* 获取已安装的包名列表
*/
@ -665,6 +806,23 @@ object VHelper {
return ArrayList(list)
}
private fun gotoVspaceLoading(
context: Context,
downloadEntity: DownloadEntity,
shouldLaunchGameAfterInstallation: Boolean
) {
if (shouldLaunchGameAfterInstallation) {
runOnUiThread {
val gameEntity = toGameEntity(downloadEntity)
try {
context.startActivity(VSpaceLoadingActivity.getIntent(context, gameEntity, true))
} catch (e: Exception) {
ToastUtils.toast(e.localizedMessage ?: "启动游戏异常,请稍候再试")
}
}
}
}
/**
* 安装新游戏
* 正常的游戏使用这个方法来安装,内部有重试处理
@ -675,74 +833,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 = isLegacyInstalled(downloadEntity.packageName)
// 更新此包名对应的 gameId Map
mTempPackageNameAndGameIdMap[downloadEntity.packageName] = downloadEntity.gameId
// 当且仅当
// 1. 全局安装完成启动游戏开关打开
// 2. 服务连接不成功或是手动触发的安装
// 2. 手动触发的安装
// 3. 不需要谷歌框架或者已经安装好谷歌框架
// 才启用安装完成后自动启动游戏
val shouldLaunchGameAfterInstallation =
mShouldLaunchGameAfterInstallation
&& (!mIsServiceConnected || isManualInstall)
&& (!isGAppsRequired(downloadEntity) || isGAppsInstalled())
val shouldLaunchGameAfterInstallation: Boolean
if (isLegacyGame) {
shouldLaunchGameAfterInstallation =
mShouldLaunchGameAfterInstallation
&& (!mIsServiceConnected || isManualInstall)
&& (!isGAppsRequired(downloadEntity) || isGAppsInstalledInCwLegacy())
} else {
shouldLaunchGameAfterInstallation =
mShouldLaunchGameAfterInstallation
&& isManualInstall
&& (!isGAppsRequired(downloadEntity) || isGAppsInstalled())
}
// 恢复安装完启动游戏开关
mShouldLaunchGameAfterInstallation = true
connectService {
val installClosure: () -> Unit = {
if (shouldLaunchGameAfterInstallation) {
runOnUiThread {
val gameEntity = toGameEntity(downloadEntity)
try {
context.startActivity(VSpaceLoadingActivity.getIntent(context, gameEntity, true))
} catch (e: Exception) {
ToastUtils.toast(e.localizedMessage ?: "启动游戏异常,请稍候再试")
}
}
}
val installClosure: () -> Unit = {
gotoVspaceLoading(context, downloadEntity, shouldLaunchGameAfterInstallation)
val path = downloadEntity.path
// 正在安装中,忽略重复调用 (手动安装时强行再安装,避免安装结果没有回调时永远卡住,无法安装)
if (!mInstallingVaPathSet.contains(path)) {
try {
mInstallingVaPathSet.add(path)
val path = downloadEntity.path
// 正在安装中,忽略重复调用 (手动安装时强行再安装,避免安装结果没有回调时永远卡住,无法安装)
if (!mInstallingVaPathSet.contains(path)) {
try {
mInstallingVaPathSet.add(path)
if (isLegacyGame) {
runOnUiThread {
val intent = VirtualAppManager.getInstallIntent(context, path, downloadEntity.packageName)
Utils.log(LOG_TAG, "正在安装 ${downloadEntity.packageName}")
context.startActivity(intent)
}
} catch (e: Exception) {
ToastUtils.toast(e.localizedMessage ?: "")
} else {
runOnIoThread {
val bit = downloadEntity.getMetaExtra(KEY_BIT)
val installParams =
VGameInstallerParams(VGameInstallerParams.FLAG_INSTALL_OVERRIDE_NO_CHECK)
if (bit == "32") {
installParams.cpuAbiOverride = "armeabi-v7a"
} else {
installParams.cpuAbiOverride = "arm64-v8a"
}
val installGameResult = VaApp.get().appManager.installGame(path, installParams)
onInstallFinished(downloadEntity.packageName, installGameResult)
}
}
} catch (e: Exception) {
ToastUtils.toast(e.localizedMessage ?: "")
}
} else {
Utils.log(LOG_TAG, "$path 正在安装中,此次安装调用无效")
}
}
if (isLegacyGame) {
connectService {
if (mDelegateManager.isConnectAidlInterface) {
installClosure.invoke()
} else {
Utils.log(LOG_TAG, "$path 正在安装中,此次安装调用无效")
connectService(
shouldCheckUpdate = false,
shouldConnectSilently = false,
callbackClosure = installClosure
)
}
}
if (mDelegateManager.isConnectAidlInterface) {
installClosure.invoke()
} else {
connectService(
shouldCheckUpdate = false,
shouldConnectSilently = false,
callbackClosure = installClosure
)
}
} else {
installClosure.invoke()
}
}
@ -769,43 +938,32 @@ object VHelper {
* 安装新应用
* 不会作为游戏存储,目前仅应用于谷歌框架
* 因为是静默安装,所以不检查其它限制条件
*
* 不再安装到旧版畅玩助手
*/
private fun install(context: Context, file: File) {
Utils.log(LOG_TAG, "尝试安装新应用 ${file.name}")
val packageName = file.nameWithoutExtension
val installClosure: () -> Unit = {
val path = file.path
if (!mInstallingVaPathSet.contains(path)) {
try {
runOnUiThread {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
&& !PackageUtils.isAppOnForeground(context)
) {
mBatchInstallListener?.invoke(false, true)
Utils.log(LOG_TAG, "应用切换至后台,批量安装被打断")
return@runOnUiThread
}
mInstallingVaPathSet.add(path)
val intent = VirtualAppManager.getInstallIntent(context, path, packageName)
Utils.log(LOG_TAG, "正在安装 $packageName")
context.startActivity(intent)
}
} catch (e: Exception) {
Utils.log(LOG_TAG, "安装异常,${e.localizedMessage}")
val path = file.path
if (!mInstallingVaPathSet.contains(path)) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
&& !PackageUtils.isAppOnForeground(context)
) {
mBatchInstallListener?.invoke(false, true)
Utils.log(LOG_TAG, "应用切换至后台,批量安装被打断")
return
}
mInstallingVaPathSet.add(path)
runOnIoThread {
val installParams = VGameInstallerParams(VGameInstallerParams.FLAG_INSTALL_OVERRIDE_NO_CHECK)
val installGameResult = VaApp.get().appManager.installGame(path, installParams)
onInstallFinished(packageName, installGameResult)
}
} catch (e: Exception) {
Utils.log(LOG_TAG, "安装异常,${e.localizedMessage}")
}
}
if (mDelegateManager.isConnectAidlInterface) {
installClosure.invoke()
} else {
connectService(shouldCheckUpdate = false, shouldConnectSilently = false, callbackClosure = installClosure)
}
}
/**
@ -824,7 +982,7 @@ object VHelper {
* 安装完成回调
*/
fun onInstallFinished(packageName: String, result: VGameInstallerResult) {
if(PackageFlavorHelper.IS_TEST_FLAVOR) {
if (PackageFlavorHelper.IS_TEST_FLAVOR) {
callSite.onNext(callSiteOnInstallComplet)
}
runOnIoThread {
@ -848,7 +1006,10 @@ object VHelper {
}
if (result.status == 0) {
updateInstalledList()
if (isLegacyInstalled(packageName)) {
// 存在旧版畅玩组件的游戏更新时才更新安装列表了,不再会有新的包安装到旧版的畅玩空间了
updateInstalledList()
}
PackageObserver.onPackageChanged(
EBPackage(EBPackage.TYPE_INSTALLED, result.packageName, "unknown").also {
it.gameId = downloadEntity.gameId
@ -869,7 +1030,9 @@ object VHelper {
} else {
// downloadEntity 为空,可能是框架类的安装 (走另外一个下载管理)
if (result.status == 0) {
updateInstalledList()
if (mIsServiceConnected) {
updateInstalledList()
}
} else {
ToastUtils.toast("安装出现异常, ${result.status}")
}
@ -957,9 +1120,11 @@ object VHelper {
values.put("meta", GsonUtils.toJson(downloadEntity.meta))
val type = if (PackageFlavorHelper.IS_TEST_FLAVOR) "test_flavor" else ""
values.put("type", type)
val uri = Uri.parse("content://com.lg.core.provider/download_game")
val uri =
Uri.parse("content://${com.lg.vspace.BuildConfig.VA_AUTHORITY_PREFIX}.provider.download_game/download_game")
HaloApp.getInstance().contentResolver.insert(uri, values)
} catch (e: Throwable) {
Utils.log("TEST", "::insertInstalledGameToProvider, e: ${e.toString()}")
if (!fromRetry) {
insertInstalledGameToProvider(downloadEntity, true)
} else {
@ -974,7 +1139,7 @@ object VHelper {
downloadEntity: DownloadEntity,
location: String? = null
) {
Utils.log(LOG_TAG, "检测是需要安装还是启动 ${downloadEntity.gameId}")
Utils.log(LOG_TAG, "检测是需要安装还是启动(DownloadEntity) ${downloadEntity.gameId}")
if (downloadEntity.name.isNullOrEmpty()) {
SentryHelper.onEvent(
@ -1003,7 +1168,7 @@ object VHelper {
gameEntity: GameEntity,
location: String? = null
) {
Utils.log(LOG_TAG, "检测是需要安装还是启动 ${gameEntity.id}")
Utils.log(LOG_TAG, "检测是需要安装还是启动(GameEntity) ${gameEntity.id}")
installOrLaunch(
context,
@ -1034,7 +1199,7 @@ object VHelper {
logLaunchButtonClicked(packageName, gameId, gameName, gameType, location)
}
validateVSpaceBeforeAction(context, GameEntity().apply {
validateVSpaceBeforeAction(context, packageName, GameEntity().apply {
id = gameId
name = gameName
downloadStatus = Constants.V_GAME
@ -1043,27 +1208,22 @@ object VHelper {
}) {
if (isInstalled(packageName)) {
launch(context, packageName)
} else {
// 这里重新检查一遍是否已安装,因为有可能因为上一次更新列表失败而出现重新下载的情况
if (isInstalled(packageName)) {
launch(context, packageName)
return@validateVSpaceBeforeAction
}
return@validateVSpaceBeforeAction
}
// 检查下载管理是否有下载实体,有实体表明未安装成功
val downloadEntity = getVDownloadEntity(gameId = gameId, packageName = packageName)
// 检查下载管理是否有下载实体,有实体表明未安装成功
val downloadEntity = getVDownloadEntity(gameId = gameId, packageName = packageName)
if (downloadEntity != null) {
val downloadedFile = File(downloadEntity.path)
if (downloadedFile.exists() && downloadedFile.length() == downloadEntity.size) {
install(context, downloadEntity, true)
} else {
// 重新下载
updateOrReDownload(downloadEntity, null)
}
if (downloadEntity != null) {
val downloadedFile = File(downloadEntity.path)
if (downloadedFile.exists() && downloadedFile.length() == downloadEntity.size) {
install(context, downloadEntity, true)
} else {
ToastUtils.toast("该游戏已损坏,请重新下载")
// 重新下载
updateOrReDownload(downloadEntity, null)
}
} else {
ToastUtils.toast("该游戏已损坏,请重新下载")
}
}
}
@ -1080,7 +1240,7 @@ object VHelper {
showLoading: Boolean = true
) {
Utils.log(LOG_TAG, "尝试打开应用 $packageName")
val isLegacyGame = isLegacyInstalled(packageName)
// 置空下载挂起回调(能 launch 游戏说明畅玩组件已安装)
mPendingDownloadCallback = null
@ -1089,9 +1249,13 @@ object VHelper {
val gameId = downloadEntity?.gameId ?: "unknown"
val gameName = downloadEntity?.name ?: "unknown"
val gameIcon = downloadEntity?.icon ?: "unknown"
// 若需要安装谷歌框架,弹谷歌框架安装弹窗
if (!ignoreGApps && isGAppsRequired(downloadEntity) && !isGAppsInstalled()) {
if (!ignoreGApps && isGAppsRequired(downloadEntity) && if (isLegacyGame) {
!isGAppsInstalledInCwLegacy()
} else {
!isGAppsInstalled()
}
) {
// show dialog
val currentActivity = CurrentActivityHolder.getCurrentActivity() as? AppCompatActivity
?: if (context is AppCompatActivity) context else return
@ -1119,10 +1283,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) {
VirtualAppManager.get().launchGame(packageName)
} else {
VaApp.get().appManager.launchGame(packageName)
}
}
mLastSuccessfullyLaunchedGame = Pair(System.currentTimeMillis(), packageName)
@ -1219,16 +1396,20 @@ object VHelper {
} catch (e: SQLiteFullException) {
e.printStackTrace()
}
val isLegacyGame = isLegacyInstalled(packageName)
val uninstallClosure: () -> Unit = {
try {
val result = VirtualAppManager.get().uninstallGame(packageName)
val result = if (isLegacyGame) VirtualAppManager.get()
.uninstallGame(packageName) else VaApp.get().appManager.uninstallGame(packageName)
if (result) {
updateInstalledList()
if (isLegacyGame) {
updateInstalledList()
}
// 卸载的时候移除已安装的包名历史
mPackageInstalledLiveData.postValue("")
}
if(PackageFlavorHelper.IS_TEST_FLAVOR) {
if (PackageFlavorHelper.IS_TEST_FLAVOR) {
callSite.onNext(callSiteUninstall)
}
Utils.log(LOG_TAG, "卸载应用结果 -> $result")
@ -1237,10 +1418,18 @@ object VHelper {
}
}
if (mDelegateManager.isConnectAidlInterface) {
uninstallClosure.invoke()
if (isLegacyGame) {
if (mDelegateManager.isConnectAidlInterface) {
uninstallClosure.invoke()
} else {
connectService(
shouldCheckUpdate = false,
shouldConnectSilently = false,
callbackClosure = uninstallClosure
)
}
} else {
connectService(shouldCheckUpdate = false, shouldConnectSilently = false, callbackClosure = uninstallClosure)
uninstallClosure.invoke()
}
}
@ -1710,12 +1899,18 @@ object VHelper {
}
/**
* 是否已经成功安装了 GApps
* 畅玩是否已经成功安装了 GApps
*/
fun isGAppsInstalled(): Boolean {
return isInstalled(G_GMS_PACKAGE_NAME)
&& isInstalled(G_GSF_PACKAGE_NAME)
&& isInstalled(G_VENDING_PACKAGE_NAME)
private fun isGAppsInstalled() = isInnerInstalled(G_GMS_PACKAGE_NAME) && isInnerInstalled(G_GSF_PACKAGE_NAME)
&& isInnerInstalled(G_VENDING_PACKAGE_NAME)
/**
* 旧版畅玩是否已经成功安装了 GApps
*/
private fun isGAppsInstalledInCwLegacy(): Boolean {
return isLegacyInstalled(G_GMS_PACKAGE_NAME)
&& isLegacyInstalled(G_GSF_PACKAGE_NAME)
&& isLegacyInstalled(G_VENDING_PACKAGE_NAME)
}
/**
@ -1787,4 +1982,99 @@ object VHelper {
return sortedEntityList.take(8)
}
@SuppressLint("CheckResult")
fun preparePluginUpdate() {
Config.vNewSettingSubject.debounce(2, TimeUnit.SECONDS).doOnNext {
it?.vaPlugin?.let { vaPlugin ->
if (!vaPlugin.id.isNullOrEmpty()) {
Utils.log(LOG_TAG, "开发者需要插件更新功能请push文件到手机或者【修改插件打包的配置为debug版本然后上传推送】")
if (!vaPlugin.url64.isNullOrEmpty()) {
val installedPluginVersion = HostUtils.getPluginVersion()
// 因为服务端下发的插件都是release版本的所以开发者要调试插件更新暂时先push文件到手机更新吧
if (com.gh.gamecenter.BuildConfig.DEBUG) {
val file = File("/data/local/tmp/gh-plugins/artifacts.zip")
if (file.exists()) {
Utils.log(LOG_TAG, "有本地更新文件: 64位插件")
PluginHelper.getInstance().updatePlugin(file)
}
} else {
if (installedPluginVersion?.isNotEmpty() == true
&& !Version(vaPlugin.versionName).isEqual(installedPluginVersion)
) {
downloadPlugin(id = "${vaPlugin.id}64", url = vaPlugin.url64) {
PluginHelper.getInstance().updatePlugin(it)
}
}
}
}
if (!vaPlugin.url32.isNullOrEmpty()) {
if (com.gh.gamecenter.BuildConfig.DEBUG) {
val file = File("/data/local/tmp/gh-plugins/artifacts32.zip")
if (file.exists()) {
Utils.log(LOG_TAG, "有本地更新文件: 32位插件")
VaApp.get().appManager.updatePlugin(file.absolutePath, "${vaPlugin.id}32.zip")
}
} else {
val installedPluginVersion = VaApp.get().appManager.extPluginVersion
if (installedPluginVersion?.isNotEmpty() == true
&& !Version(vaPlugin.versionName).isEqual(installedPluginVersion)
) {
downloadPlugin(id = "${vaPlugin.id}32", url = vaPlugin.url32) {
VaApp.get().appManager.updatePlugin(it.absolutePath, "${vaPlugin.id}32.zip")
}
}
}
}
}
}
}.subscribeOn(Schedulers.io()).subscribe({}, {})
}
private fun downloadPlugin(id: String, url: String, fn: (File) -> Unit) {
val pluginFileName = "${id}.zip"
val currentPluginFile = File(HaloApp.getInstance().cacheDir, pluginFileName)
if (currentPluginFile.exists() && PluginFileUtils.isZipFile(currentPluginFile)) {
// 已经下载好了
fn(currentPluginFile)
} else {
val currentDownloadEntity = DownloadMessageHandler.findEntity(id)
if (currentDownloadEntity != null) {
SimpleDownloadManager.cancel(id)
}
SimpleDownloadManager.download(
DownloadConfigBuilder()
.setUniqueId(id)
.setFileName(pluginFileName)
.setUrl(url)
.setPathToStore(HaloApp.getInstance().cacheDir.absolutePath + File.separator)
.setHttpClient(DefaultHttpClient())
.setDownloadThreadSize(2)
.setDownloadListener(DownloadMessageHandler)
.setDownloadExecutor(AppExecutor.ioExecutor)
.build()
)
DownloadMessageHandler.registerListener(id, object : DownloadListener {
override fun onError(error: DownloadError) {
}
override fun onProgress(progress: Float) {
}
override fun onSizeReceived(fileSize: Long) {
}
override fun onStatusChanged(status: DownloadStatus) {
if (status == DownloadStatus.COMPLETED) {
fn(currentPluginFile)
DownloadMessageHandler.unregisterListener(id, this)
}
}
override fun onSpeedChanged(speed: Float) {
}
})
}
}
}

View File

@ -0,0 +1,306 @@
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")
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

@ -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.isInnerInstalled(gamePkg)) {
createShortcutLambda.invoke()
} else {
VHelper.postOnInitialized(createShortcutLambda)
}
}

View File

@ -76,6 +76,8 @@ 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.shuyu.gsyvideoplayer.cache.CacheFactory;
@ -92,6 +94,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;
@ -200,6 +203,7 @@ public class HaloApp extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
VaApp.get().onCreate(this);
initArouter();
if (!Injection.appInit(this)) {
@ -366,6 +370,7 @@ public class HaloApp extends MultiDexApplication {
});
}
}, delay);
VaApp.get().startSensorLogService();
}
private void initArouter() {
@ -454,7 +459,7 @@ public class HaloApp extends MultiDexApplication {
LoadedApkHuaWei.hookHuaWeiVerifier(this);
DownloadMessageHandler.INSTANCE.init(SimpleDownloadDatabase.getInstance().downloadDao());
VHelper.INSTANCE.preparePluginUpdate();
// 预加载游戏库图标
SubjectRecommendEntity barData = HomeBottomBarHelper.getDefaultGameBarData();
if (!TextUtils.isEmpty(barData.getIconSelect())) {
@ -549,6 +554,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,13 +5,21 @@ 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" }
}
dependencies {
@ -20,6 +28,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"
}
}
@ -41,11 +50,13 @@ allprojects {
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

@ -143,4 +143,8 @@ ext {
qGameAdVersion = "4.520.1390"
blankjUtilCodex = "1.30.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 SILENT_UPDATE = "静默更新";
@ -222,6 +223,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";

View File

@ -39,4 +39,6 @@ interface IAppProvider : IProvider {
fun getIsBrandNewInstall(): Boolean
fun setSkippingThirdParty(isSkippingThirdParty: 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

@ -6,7 +6,9 @@ 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')
build_time_without_divider=$(TZ=Asia/Shanghai date +'%Y%m%d%H%M')L
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=""
@ -26,34 +28,109 @@ else
sed -i 's/var isTestBuild = true/var isTestBuild = false/g' module_sensors_data/build.gradle
fi
# blame_yangfei: test script lines
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
./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 +140,7 @@ function updateChannelIfNeeded {
fi
}
# 保存 output 文件名
if [ "${output}" != "" ]; then
apk_release_path="$output"
fi
# 保存 config_id
if [ "${config_id}" != "" ]; then
@ -100,6 +174,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 +223,13 @@ 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"
# blame_yangfei: test script lines
./gradlew :app:assembleInternalCnRelease -I init.gradle
cp -R app/build/outputs/apk/internal/release/app-internal-release.apk "${apk_release_path}"
fi
# 重置 app build.gradle

59
setting_vasdk.gradle Normal file
View File

@ -0,0 +1,59 @@
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-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 f14431469a