Compare commits

...

69 Commits

Author SHA1 Message Date
3a15f9af33 Merge branch 'feature-GHZS-3018' into 'dev'
fix: MIUI优化关闭提示弹窗—0720测试 https://jira.shanqu.cc/browse/GHZS-3001

See merge request halo/android/assistant-android!1217
2023-07-24 11:55:52 +08:00
6920d682b2 fix: MIUI优化关闭提示弹窗—0720测试 https://jira.shanqu.cc/browse/GHZS-3001 2023-07-24 11:55:52 +08:00
b0493502e4 Merge branch 'feature-dev-cherry-pick-GHZS-2901' into 'dev'
feat: MIUI优化关闭提示弹窗—客户端 https://jira.shanqu.cc/browse/GHZS-2901

See merge request halo/android/assistant-android!1216
2023-07-24 11:39:55 +08:00
723202d4ce feat: MIUI优化关闭提示弹窗—客户端 https://jira.shanqu.cc/browse/GHZS-2901 2023-07-24 11:36:49 +08:00
6e0628b478 Merge remote-tracking branch 'origin/release' into dev 2023-07-24 10:42:53 +08:00
7f14555886 Merge branch 'hotfix/v5.28.2-912/crashes' into 'release'
修复 5.28.2 的部分线上闪退

See merge request halo/android/assistant-android!1215
2023-07-24 10:41:52 +08:00
c2477d2a3f fix: 捕抓畅玩游戏创建快捷方式时的闪退 https://sentry.shanqu.cc/organizations/lightgame/issues/300166/?project=22&query=dist%3A912+level%3Afatal&statsPeriod=14d 2023-07-24 10:24:51 +08:00
8ff4945cfa fix: 修复曝光上报时的空指针问题 https://sentry.shanqu.cc/organizations/lightgame/issues/301370/events/4fed437358844787bb532a12283205b6/?project=22 2023-07-24 10:15:21 +08:00
fcc65fdbfe fix: 修复上层下载持有错误下载状态时,暂停任务导致的空指针闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/304224/?project=22 2023-07-24 10:05:52 +08:00
d4b0ecce98 fix: 修复下载其它内容时偶发的闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/314990/?project=22 2023-07-24 09:44:52 +08:00
848ca0b5c6 Merge branch 'fix/pkg_issue' into 'dev'
fix: 修复特殊打包选择首页 tab 异常的问题

See merge request halo/android/assistant-android!1213
2023-07-21 17:58:40 +08:00
4f0c81420e fix: 修复特殊打包选择首页 tab 异常的问题 2023-07-21 17:38:32 +08:00
0c437d32bd Merge branch 'feat/GHZS-2910' into 'dev'
feat: 关于我们页面新增安装包隐藏信息提示 https://jira.shanqu.cc/browse/GHZS-2910

See merge request halo/android/assistant-android!1212
2023-07-21 14:31:53 +08:00
25d9771a3c feat: 关于我们页面新增安装包隐藏信息提示 https://jira.shanqu.cc/browse/GHZS-2910 2023-07-21 14:01:44 +08:00
668b54ac6d Merge branch 'feature-GHZS-2987' into 'dev'
fix: 【光环助手】同步正式环境问题-插件化安装弹窗 https://jira.shanqu.cc/browse/GHZS-2987

See merge request halo/android/assistant-android!1211
2023-07-21 11:40:53 +08:00
92b0f8fe73 fix: 【光环助手】同步正式环境问题-插件化安装弹窗 https://jira.shanqu.cc/browse/GHZS-2987 2023-07-21 11:39:07 +08:00
f689dfce07 Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	dependencies.gradle
2023-07-19 19:22:43 +08:00
42d5d46e53 chore: 版本更新至 5.28.2 2023-07-18 16:13:09 +08:00
cdccc35703 Merge branch 'feature-GHZS-2946' into 'release'
fix: 修复线上闪退问题 https://jira.shanqu.cc/browse/GHZS-2946

See merge request halo/android/assistant-android!1207
2023-07-18 16:08:44 +08:00
d3e2fea019 fix: 修复线上闪退问题 https://jira.shanqu.cc/browse/GHZS-2946 2023-07-18 16:08:44 +08:00
f343841233 Merge branch 'fix/GHZS-2948' into 'release'
fix: 修复线上闪退问题 https://jira.shanqu.cc/browse/GHZS-2948

See merge request halo/android/assistant-android!1206
2023-07-18 14:58:47 +08:00
f62083eff2 fix: 修复线上闪退问题 https://jira.shanqu.cc/browse/GHZS-2948 2023-07-18 14:58:47 +08:00
8594e998c2 Merge branch 'fix/vspace_dialog_dismiss_issue' into 'release'
fix: 修复畅玩弹窗在组件安装完成以后的 dismiss 问题

See merge request halo/android/assistant-android!1205
2023-07-17 17:54:15 +08:00
6865706b0f fix: 修复畅玩弹窗在组件安装完成以后的 dismiss 问题 2023-07-17 17:50:23 +08:00
bfb8b46ce8 Merge branch 'fix/GHZS-2941' into 'dev'
fix:【光环助手】畅玩助手神策数据流程优化 https://jira.shanqu.cc/browse/GHZS-2941

See merge request halo/android/assistant-android!1204
2023-07-17 17:34:40 +08:00
b6d8ca4d84 Merge branch 'feat/GHZS-2959' into 'release'
feat: 神策渠道调整 https://jira.shanqu.cc/browse/GHZS-2959

See merge request halo/android/assistant-android!1203
2023-07-17 16:14:05 +08:00
455e1f0432 feat: 神策渠道调整 https://jira.shanqu.cc/browse/GHZS-2959 2023-07-17 16:12:29 +08:00
ba27c09096 fix:【光环助手】畅玩助手神策数据流程优化 https://jira.shanqu.cc/browse/GHZS-2941 2023-07-17 15:03:16 +08:00
15276cc4b3 Merge branch 'hotfix/v5.28.1-911/crashes' into 'release'
修复部分线上闪退

See merge request halo/android/assistant-android!1202
2023-07-17 11:53:17 +08:00
130a7cdf2a fix: 修复因为混淆造成的下载数据恢复闪退问题 https://sentry.shanqu.cc/organizations/lightgame/issues/281841/?project=22 2023-07-17 11:08:11 +08:00
164ec0c368 fix: 捕抓首页 tab 的 roundToInt 闪退异常 2023-07-17 11:07:11 +08:00
756bc66f26 Merge branch 'fix/GHZS-2945' into 'dev'
fix:【光环助手】内容导航栏图标闪烁 https://jira.shanqu.cc/browse/GHZS-2945

See merge request halo/android/assistant-android!1200
2023-07-17 09:45:10 +08:00
e589bce5c6 fix:【光环助手】内容导航栏图标闪烁 https://jira.shanqu.cc/browse/GHZS-2945 2023-07-17 09:36:28 +08:00
991bd22511 Merge branch 'fix/sensors_log' into 'release'
fix: 修复畅玩助手下载弹窗错误上报安装点击事件的问题

See merge request halo/android/assistant-android!1199
2023-07-14 17:05:55 +08:00
df1ab5221d fix: 修复畅玩助手下载弹窗错误上报安装点击事件的问题 2023-07-14 16:41:51 +08:00
70916fd0f7 Merge remote-tracking branch 'origin/release' into dev
# Conflicts:
#	app/src/main/java/com/gh/gamecenter/home/gamecollection/carousel/HomeGameCollectionCarouselAdapter.kt
#	dependencies.gradle
2023-07-14 09:58:36 +08:00
226d6c4f2c chore: 版本更新至 5.28.1 2023-07-13 17:25:06 +08:00
896adc9d36 Merge branch 'feature-data-watcher-patch' into 'release'
fix: Sentry312134...

See merge request halo/android/assistant-android!1198
2023-07-13 15:35:48 +08:00
0e33abebdd fix: Sentry312134... 2023-07-13 15:35:48 +08:00
c8ed126605 Merge branch 'fix/GHZS-2926' into 'release'
fix:【光环助手】游戏单封面图显示问题 https://jira.shanqu.cc/browse/GHZS-2926

See merge request halo/android/assistant-android!1196
2023-07-12 14:48:17 +08:00
b510a329b6 fix:【光环助手】游戏单封面图显示问题 https://jira.shanqu.cc/browse/GHZS-2926 2023-07-12 14:36:38 +08:00
2de1ba4e1d Merge branch 'fix/GHZS-2907' into 'release'
fix: 神策埋点—07/10测试 (3) https://jira.shanqu.cc/browse/GHZS-2907

See merge request halo/android/assistant-android!1195
2023-07-11 15:37:47 +08:00
e4a0f0e68b fix: 神策埋点—07/10测试 (3) https://jira.shanqu.cc/browse/GHZS-2907 2023-07-11 15:31:44 +08:00
c064f9d3a6 Merge branch 'feat/core_event_with_toast' into 'release'
fix: 特殊包上报比例为 1 时关键行为进行 toast 提示(方便测试)

See merge request halo/android/assistant-android!1190
2023-07-11 13:52:00 +08:00
759401d9ae Merge branch 'fix/CWZS-91' into 'release'
fix: 推送更新测试问题—测试问题07/06 https://jira.shanqu.cc/browse/CWZS-91

See merge request halo/android/assistant-android!1191
2023-07-11 13:51:53 +08:00
e56209d15e fix: 处理弹窗 dismiss 问题 2023-07-11 13:38:59 +08:00
c466ff1f21 fix: 处理弹窗 dismiss 问题 2023-07-11 11:51:41 +08:00
e09cf299f0 Merge branch 'feature-GHZS-2771-patch-3' into 'release'
fix: 支持xapk格式的apks文件解压-0706测试

See merge request halo/android/assistant-android!1193
2023-07-11 10:40:24 +08:00
25352ba609 fix: 支持xapk格式的apks文件解压-0706测试 2023-07-11 10:40:24 +08:00
3cd065cb6e fix: 处理弹窗 dismiss 问题 2023-07-10 16:21:01 +08:00
5a483bb5db Merge branch 'fix/GHZS-2887' into 'dev'
fix: 游戏单功能优化-游戏单合集-前端部分—0709测试-客户端 https://jira.shanqu.cc/browse/GHZS-2887

See merge request halo/android/assistant-android!1192
2023-07-10 15:55:07 +08:00
3b380c6fe3 fix: 游戏单功能优化-游戏单合集-前端部分—0709测试-客户端 https://jira.shanqu.cc/browse/GHZS-2887 2023-07-10 14:25:14 +08:00
919a98ffe6 fix: 处理弹窗 dismiss 问题 2023-07-10 11:26:22 +08:00
eff84218a8 fix: 特殊包上报比例为 1 时关键行为进行 toast 提示(方便测试) 2023-07-07 11:32:44 +08:00
7c9c363422 fix: 推送更新测试问题—测试问题07/06 https://jira.shanqu.cc/browse/CWZS-91 2023-07-07 10:04:41 +08:00
add6448f44 Merge branch 'fix/GHZS-2848' into 'dev'
fix: 游戏单功能优化-游戏单合集-前端部分—0704测试-客户端(0706测试1、3) https://jira.shanqu.cc/browse/GHZS-2848

See merge request halo/android/assistant-android!1188
2023-07-06 15:49:58 +08:00
efccfaaa7f fix: 游戏单功能优化-游戏单合集-前端部分—0704测试-客户端(0706测试1、3) https://jira.shanqu.cc/browse/GHZS-2848 2023-07-06 15:33:01 +08:00
a61057ae10 Merge branch 'fix/download_issue' into 'dev'
fix: 移除部分在 DownloadObserver/DownloadDataHelper 进行的数据库操作

See merge request halo/android/assistant-android!1187
2023-07-06 15:17:27 +08:00
9472cafe48 fix: 移除部分在 DownloadObserver 进行的数据库操作 2023-07-06 14:37:00 +08:00
be83e1a2b4 Merge branch 'fix/GHZS-2870' into 'dev'
fix: 相关曝光数据埋点补充—0705测试 https://jira.shanqu.cc/browse/GHZS-2870

See merge request halo/android/assistant-android!1186
2023-07-06 11:08:09 +08:00
e48d7745b4 fix: 相关曝光数据埋点补充—0705测试 https://jira.shanqu.cc/browse/GHZS-2870 2023-07-06 10:59:50 +08:00
8b1a38214c Merge branch 'feature-GHZS-2771-patch-2' into 'release'
feat: 支持xapk格式的apks文件解压—0705测试

See merge request halo/android/assistant-android!1185
2023-07-06 09:47:32 +08:00
2acde0af00 feat: 支持xapk格式的apks文件解压—0705测试 2023-07-06 09:47:32 +08:00
daab20424e Merge branch 'fix/GHZS-2848' into 'dev'
fix: 游戏单功能优化-游戏单合集-前端部分—0704测试-客户端 https://jira.shanqu.cc/browse/GHZS-2848

See merge request halo/android/assistant-android!1184
2023-07-05 16:55:40 +08:00
63f2adade2 fix: 游戏单功能优化-游戏单合集-前端部分—0704测试-客户端 https://jira.shanqu.cc/browse/GHZS-2848 2023-07-05 15:39:04 +08:00
201c1207f9 Merge branch 'feature-GHZS-2771-patch-1' into 'release'
feat: 支持xapk格式的apks文件解压—0704测试

See merge request halo/android/assistant-android!1183
2023-07-05 14:24:55 +08:00
75d86b5a91 feat: 支持xapk格式的apks文件解压—0704测试 2023-07-05 14:24:55 +08:00
f30d647936 Merge branch 'feat/enable_log_in_internal_build' into 'dev'
feat: 邮件包保留日志输出,方便无编译条件时简单调试

See merge request halo/android/assistant-android!1182
2023-07-05 10:50:06 +08:00
c7dd449899 feat: 邮件包保留日志输出,方便无编译条件时简单调试 2023-07-05 10:13:09 +08:00
76 changed files with 1149 additions and 521 deletions

View File

@ -11,6 +11,9 @@ android {
String CONFIG_ID = ""
String FIRST_LAUNCH = ""
String SDK_VERSION = ""
String SDK_APP_ID = ""
String SDK_APP_NAME = ""
int ACTIVATE_REPORTING_RATIO = 100
buildFeatures {
@ -79,6 +82,11 @@ android {
// 推广用的配置 id
buildConfigField "String", "CONFIG_ID", "\"${CONFIG_ID}\""
// 推广用的 SDK 版本 (仅记录使用)
buildConfigField "String", "SDK_VERSION", "\"${SDK_VERSION}\""
buildConfigField "String", "SDK_APP_ID", "\"${SDK_APP_ID}\""
buildConfigField "String", "SDK_APP_NAME", "\"${SDK_APP_NAME}\""
// 首次启动的跳转配置
buildConfigField "String", "FIRST_LAUNCH", "\"${FIRST_LAUNCH}\""
@ -206,17 +214,11 @@ android {
kuaishou {
dimension "env"
String KUAI_SHOU_APP_ID = ""
String KUAI_SHOU_APP_NAME = ""
buildConfigField "String", "DEV_API_HOST", "\"${API_HOST}\""
buildConfigField "String", "NEW_DEV_API_HOST", "\"${NEW_API_HOST}\""
buildConfigField "String", "DEV_VAPI_HOST", "\"${VAPI_HOST}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "KUAI_SHOU_APP_ID", "\"${KUAI_SHOU_APP_ID}\""
buildConfigField "String", "KUAI_SHOU_APP_NAME", "\"${KUAI_SHOU_APP_NAME}\""
}
gdt {

View File

@ -20,6 +20,7 @@
-keep class com.gh.gamecenter.db.info.* {*;}
-keep class com.gh.gamecenter.entity.** {<fields>;}
-keep class com.gh.gamecenter.qa.entity.** {<fields>;}
-keep class com.gh.download.DownloadDataSimpleEntity {<fields>;}
-keep class com.gh.gamecenter.floatingwindow.FloatingWindowEntity {<fields>;}
-keep class com.gh.gamecenter.BR
-keep class com.gh.gamecenter.retrofit.* {*;}

View File

@ -5,8 +5,8 @@ import com.kwai.monitor.log.TurboAgent
import com.kwai.monitor.log.TurboConfig
object KuaishouHelper {
private val mAppId by lazy { BuildConfig.KUAI_SHOU_APP_ID.ifEmpty { "81537" } }
private val mAppName by lazy { BuildConfig.KUAI_SHOU_APP_NAME.ifEmpty { "guanghuanzhushou_1" } }
private val mAppId by lazy { BuildConfig.SDK_APP_ID.ifEmpty { "81537" } }
private val mAppName by lazy { BuildConfig.SDK_APP_NAME.ifEmpty { "guanghuanzhushou_1" } }
@JvmStatic
fun init(context: Context, channel: String) {

View File

@ -3,10 +3,13 @@ package com.gh.gamecenter.provider
import android.app.Activity
import android.app.Application
import android.text.TextUtils
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.KuaishouHelper
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.provider.IFlavorProvider
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.TimeUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.halo.assistant.HaloApp
import com.kwai.monitor.payload.TurboHelper
@ -44,6 +47,11 @@ class FlavorProviderImp : IFlavorProvider {
override fun logCoreEvent() {
logEvent("EVENT_KEY_PATH_OPTIMIZATION")
if (BuildConfig.ACTIVATE_REPORTING_RATIO == 1) {
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast("关键行为 EVENT_KEY_PATH_OPTIMIZATION")
}, 500)
}
}
companion object {

View File

@ -830,8 +830,9 @@
</intent-filter>
</receiver>
<receiver
<activity
android:name="com.gh.common.xapk.XapkInstallReceiver"
android:theme="@style/Theme.Transparent"
android:exported="false" />
<receiver

View File

@ -1,23 +0,0 @@
package com.gh.common.chain
import android.content.Context
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.R
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.feature.entity.GameEntity
class AutoSwitchAssistantInstallHandler : ChainHandler() {
override fun handleRequest(context: Context, gameEntity: GameEntity) {
if (BrowserInstallHelper.isUseBrowserToInstallEnabled()
&& BrowserInstallHelper.shouldUseBrowserToInstall()
&& gameEntity.isSplitXApk()) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint))
}
if (hasNext()) {
getNext()?.handleRequest(context, gameEntity)
} else {
processEndCallback?.invoke(null)
}
}
}

View File

@ -1,5 +1,6 @@
package com.gh.common.databind;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Typeface;
@ -19,7 +20,6 @@ import androidx.core.content.ContextCompat;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.facebook.drawee.view.SimpleDraweeView;
import com.gh.common.chain.AutoSwitchAssistantInstallHandler;
import com.gh.common.chain.BrowserInstallHandler;
import com.gh.common.chain.CertificationHandler;
import com.gh.common.chain.ChainBuilder;
@ -52,6 +52,7 @@ import com.gh.common.util.PackageUtils;
import com.gh.common.util.ReservationHelper;
import com.gh.download.DownloadManager;
import com.gh.download.dialog.DownloadDialog;
import com.gh.download.server.BrowserInstallHelper;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WebActivity;
@ -66,6 +67,7 @@ import com.gh.gamecenter.common.view.DrawableView;
import com.gh.gamecenter.core.utils.DisplayUtils;
import com.gh.gamecenter.core.utils.MtaHelper;
import com.gh.gamecenter.core.utils.NumberUtils;
import com.gh.gamecenter.core.utils.ToastUtils;
import com.gh.gamecenter.databinding.KaifuDetailItemRowBinding;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.CommunityVideoEntity;
@ -414,7 +416,7 @@ public class BindingAdapters {
builder.addHandler(new CheckDownloadHandler());
builder.setProcessEndCallback(o -> {
download(progressBar, gameEntity, traceEvent, (boolean) o, entrance, location);
download(v.getContext(), progressBar, gameEntity, traceEvent, (boolean) o, entrance, location);
return null;
});
final ChainHandler chainHandler = builder.buildHandlerChain();
@ -452,7 +454,7 @@ public class BindingAdapters {
if (downloadEntity != null) {
File file = new File(downloadEntity.getPath());
if (!file.exists()) {
download(progressBar, gameEntity, traceEvent, false, entrance, location);
download(v.getContext(), progressBar, gameEntity, traceEvent, false, entrance, location);
return;
}
@ -678,12 +680,16 @@ public class BindingAdapters {
// 开始下载
private static void download(DownloadButton progressBar,
private static void download(Context context,
DownloadButton progressBar,
GameEntity gameEntity,
ExposureEvent traceEvent,
boolean isSubscribe,
String entrance,
String location) {
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint));
}
String str = progressBar.getText().toString();
String method;
if (str.contains("更新")) {

View File

@ -47,7 +47,7 @@ object ExposureManager {
fun log(eventList: List<ExposureEvent>) {
AppExecutor.logExecutor.execute {
for (event in eventList) {
if (!exposureCache.contains(event.id)) {
if (event != null && !exposureCache.contains(event.id)) {
exposureSet.add(event)
exposureCache.add(event.id)
} else {

View File

@ -2,6 +2,7 @@ package com.gh.common.provider
import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IAppProvider
@ -70,6 +71,10 @@ class AppProviderImpl : IAppProvider {
return HaloApp.getInstance().flavorProvider
}
override fun getFlavor(): String {
return BuildConfig.FLAVOR
}
override fun getIsBrandNewInstall(): Boolean {
return HaloApp.getInstance().isBrandNewInstall
}

View File

@ -341,7 +341,7 @@ object DirectUtils {
"feedback" -> directToFeedback(context, linkEntity.name, linkEntity.text, false, "", entrance)
"qa", "Q&A" -> directToQa(context, linkEntity.text ?: "", linkEntity.link ?: "")
"qa", "qa_content", "Q&A" -> directToQa(context, linkEntity.text ?: "", linkEntity.link ?: "")
"qa_collection", "Q&A合集" -> directToQaCollection(
context, linkEntity.text

View File

@ -31,6 +31,7 @@ import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.PluginLocation
@ -1014,10 +1015,13 @@ object DownloadItemUtils {
isSubscribe,
traceEvent
)
ToastUtils.toast(gameEntity.name + "已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint))
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
Utils.toast(context, gameEntity.name + "已加入下载队列")
if (downloadBtn is DownloadButton) {
downloadBtn.text = "0%"
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.DOWNLOADING_NORMAL
@ -1041,10 +1045,13 @@ object DownloadItemUtils {
val msg = FileUtils.isCanDownload(context, gameEntity.getApk()[0].size ?: "")
if (TextUtils.isEmpty(msg)) {
DownloadManager.createDownload(context, gameEntity, "插件化", entrance, location, isSubscribe, traceEvent)
ToastUtils.toast(gameEntity.name + "已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint))
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
Utils.toast(context, gameEntity.name + "已加入下载队列")
if (downloadBtn is DownloadButton) {
downloadBtn.setText(R.string.downloading)
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.DOWNLOADING_PLUGIN

View File

@ -39,8 +39,11 @@ object DownloadObserver {
// TODO 修复因为更改内存对象造成的双重下载完成事件问题,具体触发代码见 DownloadDao.updateSnapshotList
private var mDoneDebouncePair: Pair<String, Long>? = null
private const val TAG = "DownloadObserver"
private const val CORE_EVENT_DOWNLOAD_COMPLETE_LOGGED = "CORE_EVENT_DOWNLOAD_COMPLETE_LOGGED"
private val mRetryableHashMap = hashMapOf<String, Boolean>()
// 如果在WIFI状态下,下载自动暂停,则再重试一遍
@JvmStatic
fun initObserver() {
@ -70,28 +73,34 @@ object DownloadObserver {
val currentActivity = AppManager.getInstance().currentActivity() ?: return
DialogHelper.showDialog(currentActivity, "下载失败", "下载链接已失效,建议提交反馈", "立即反馈", "取消", {
HelpAndFeedbackBridge.startSuggestionActivity(
currentActivity,
SuggestType.gameQuestion, "notfound",
StringUtils.buildString(downloadEntity.name, ",问题反馈:下载链接失效"),
SimpleGameEntity(gameId, downloadEntity.name, "")
)
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
DialogHelper.showDialog(
currentActivity,
"下载失败",
"下载链接已失效,建议提交反馈",
"立即反馈",
"取消",
{
HelpAndFeedbackBridge.startSuggestionActivity(
currentActivity,
SuggestType.gameQuestion, "notfound",
StringUtils.buildString(downloadEntity.name, ",问题反馈:下载链接失效"),
SimpleGameEntity(gameId, downloadEntity.name, "")
)
},
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
)
return
} else if (DownloadStatus.neterror == downloadEntity.status
|| DownloadStatus.timeout == downloadEntity.status
|| DownloadStatus.diskioerror == downloadEntity.status
|| DownloadStatus.diskisfull == downloadEntity.status) {
if (downloadEntity.meta[Constants.MARK_RETRY_DOWNLOAD].isNullOrEmpty()
|| DownloadStatus.diskisfull == downloadEntity.status
) {
if (mRetryableHashMap[downloadEntity.url] == true
&& NetworkUtils.isWifiConnected(HaloApp.getInstance().application)
) {
downloadEntity.meta[Constants.MARK_RETRY_DOWNLOAD] = downloadEntity.progress.toString()
downloadManager.updateDownloadEntity(downloadEntity)
downloadManager.resumeDownload(downloadEntity.url)
debugOnly {
Utils.log("DownloadObserver", "下载重试->" + downloadEntity.toJson())
}
mRetryableHashMap[downloadEntity.url] = false
Utils.log(TAG, "下载重试->" + downloadEntity.toJson())
} else {
if (DownloadStatus.diskisfull == downloadEntity.status) {
ToastUtils.toast("磁盘已满,请清理空间后重试下载")
@ -102,13 +111,10 @@ object DownloadObserver {
}
DataLogUtils.uploadNeterrorLog(mApplication, downloadEntity)
debugOnly {
Utils.log("DownloadObserver", "下载自动暂停->" + downloadEntity.toJson())
}
Utils.log(TAG, "下载自动暂停->" + downloadEntity.toJson())
}
} else if (DownloadStatus.redirected == downloadEntity.status) {
debugOnly { Utils.log("重定向完毕") }
Utils.log(TAG, "重定向完毕")
DownloadDataHelper.uploadRedirectEvent(downloadEntity)
} else if (DownloadStatus.unqualified == downloadEntity.status) {
// 未成年
@ -153,40 +159,35 @@ object DownloadObserver {
if (DownloadStatus.done == downloadEntity.status) {
if (mDoneDebouncePair?.first != downloadEntity.url) {
mDoneDebouncePair = Pair(downloadEntity.url, System.currentTimeMillis())
performDownloadCompleteAction(downloadEntity, gameId, downloadManager)
performDownloadCompleteAction(downloadEntity, downloadManager)
} else {
if (mDoneDebouncePair?.second == 0L
|| System.currentTimeMillis() - (mDoneDebouncePair?.second ?: 0) > 500
) {
performDownloadCompleteAction(downloadEntity, gameId, downloadManager)
performDownloadCompleteAction(downloadEntity, downloadManager)
}
}
}
if (downloadEntity.status == DownloadStatus.done) {
mRetryableHashMap.remove(downloadEntity.url)
EventBus.getDefault().post(EBDownloadStatus("done", "", "", "", downloadEntity.packageName, ""))
}
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
// 如果已下载大小发生变化,表示成功恢复下载,则重置重试标记
if (downloadEntity.status == DownloadStatus.downloading &&
downloadEntity.progress.toString() != downloadEntity.meta[Constants.MARK_RETRY_DOWNLOAD]
) {
downloadEntity.meta[Constants.MARK_RETRY_DOWNLOAD] = ""
downloadManager.updateDownloadEntity(downloadEntity)
if (downloadEntity.status == DownloadStatus.downloading) {
mRetryableHashMap[downloadEntity.url] = true
}
}
}
// 添加观察者
DownloadManager.getInstance().addObserver(dataWatcher)
}
private fun performDownloadCompleteAction(
downloadEntity: DownloadEntity,
gameId: String,
downloadManager: DownloadManager
) {
if (downloadEntity.name.contains(mApplication.getString(R.string.app_name))) {
@ -221,10 +222,12 @@ object DownloadObserver {
downloadEntity.pluginDesc
)
)
downloadEntity.isPlugin -> Utils.toast(
mApplication,
downloadEntity.name + " - " + platform + " - 下载完成"
)
else -> {
if (!downloadEntity.isVGame()) {
Utils.toast(mApplication, downloadEntity.name + " - 下载完成")
@ -242,15 +245,10 @@ object DownloadObserver {
val gameName = downloadEntity.getMetaExtra(Constants.GAME_NAME)
if (simulatorJson.isEmpty()) return
var simulator = GsonUtils.fromJson(simulatorJson, SimulatorEntity::class.java)
val isInstalled = PackageUtils.isInstalledFromAllPackage(
HaloApp.getInstance().application,
simulator.apk?.packageName
)
val isInstalledNewSimulator =
SimulatorGameManager.isNewSimulatorInstalled(HaloApp.getInstance().application)
val isInstalledOldSimulator =
SimulatorGameManager.isOldSimulatorInstalled(HaloApp.getInstance().application)
// if (!isInstalled && !isInstalledNewSimulator) {
val currentActivity = AppManager.getInstance().currentActivity()
?: return
val newSimulator = Config.getNewSimulatorEntitySetting()
@ -261,7 +259,6 @@ object DownloadObserver {
currentActivity, simulator,
SimulatorDownloadManager.SimulatorLocation.LAUNCH, downloadEntity.gameId, gameName, null
)
// }
SimulatorGameManager.recordDownloadSimulatorGame(downloadEntity.gameId, simulator.type)
SimulatorGameManager.postPlayedGame(downloadEntity.gameId, downloadEntity.packageName)
} else {

View File

@ -27,6 +27,7 @@ import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.observableToMain
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.common.view.dsbridge.CompletionHandler
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.EmptyCallback
import com.gh.gamecenter.core.utils.MtaHelper
@ -183,10 +184,13 @@ object GameActivityDownloadHelper {
str != context.getString(R.string.install) &&
str != context.getString(R.string.launch)
) {
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint))
}
ToastUtils.toast("${gameEntity.name}已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
} else {
when {
str == context.getString(R.string.download) || str == context.getString(R.string.attempt) -> {
@ -208,10 +212,13 @@ object GameActivityDownloadHelper {
handleUpdateStatus(context, gameEntity, apk, entrance, location, traceEvent)
}
else -> {
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint))
}
ToastUtils.toast("${gameEntity.name}已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
}
}
}
@ -430,10 +437,13 @@ object GameActivityDownloadHelper {
R.string.download
), entrance, location, isSubscribe, traceEvent
)
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint))
}
ToastUtils.toast("${gameEntity.name}已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
} else {
ToastUtils.toast(msg)
}
@ -452,10 +462,13 @@ object GameActivityDownloadHelper {
val msg = FileUtils.isCanDownload(context, apk.size)
if (TextUtils.isEmpty(msg)) {
DownloadManager.createDownload(context, apk, gameEntity, "插件化", entrance, location, isSubscribe, traceEvent)
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint))
}
ToastUtils.toast("${gameEntity.name}已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
} else {
ToastUtils.toast(msg)
}
@ -495,10 +508,13 @@ object GameActivityDownloadHelper {
traceEvent: ExposureEvent?
) {
DownloadManager.createDownload(context, apk, gameEntity, "更新", entrance, location, isSubscribe, traceEvent)
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
ToastUtils.toast(context.getString(R.string.unsupported_browser_install_hint))
}
ToastUtils.toast("${gameEntity.name}已加入下载队列")
if (BrowserInstallHelper.shouldAutoSwitchAssistantInstall(gameEntity)) {
val toast = context.getString(R.string.unsupported_browser_install_hint)
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast(toast)
}, 1000)
}
}
@SuppressLint("CheckResult")

View File

@ -161,14 +161,13 @@ object PackageInstaller {
}
val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_CANCEL_CURRENT
} else {
PendingIntent.FLAG_UPDATE_CURRENT
PendingIntent.FLAG_CANCEL_CURRENT
}
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, flags)
val pendingIntent = PendingIntent.getActivity(context, sessionId, intent, flags)
// 提交数据流并执行安装
session.commit(pendingIntent.intentSender)
session.close()
}
/**

View File

@ -1,30 +1,35 @@
package com.gh.common.xapk
import android.content.BroadcastReceiver
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller
import android.content.pm.PackageInstaller.SessionInfo
import android.os.Build
import android.os.Bundle
import androidx.annotation.RequiresApi
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class XapkInstallReceiver : BroadcastReceiver() {
class XapkInstallReceiver : Activity() {
companion object {
const val KEY_PACKAGE_PATH = "package_path"
}
override fun onReceive(context: Context, intent: Intent) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
overridePendingTransition(0, 0)
handleIntent(this, intent)
}
private fun handleIntent(context: Context, intent: Intent) {
when (intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
val installIntent = intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT)
if (installIntent != null) {
val installPackagePath = intent.getStringExtra(KEY_PACKAGE_PATH)
val installSessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1)
XapkInstaller.onPendingUserAction(installPackagePath!!, installSessionId)
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(installIntent)
updatePendingSessionInfoStatus(intent, XapkPendingSessionInfo.STATUS_PENDING_USER_ACTION)
finish()
}
}
PackageInstaller.STATUS_FAILURE,
@ -34,11 +39,21 @@ class XapkInstallReceiver : BroadcastReceiver() {
PackageInstaller.STATUS_FAILURE_INCOMPATIBLE,
PackageInstaller.STATUS_FAILURE_INVALID,
PackageInstaller.STATUS_FAILURE_STORAGE -> {
val installPackagePath = intent.getStringExtra(KEY_PACKAGE_PATH)
if (!installPackagePath.isNullOrEmpty()) {
XapkInstaller.onInstallCanceled(installPackagePath)
}
updatePendingSessionInfoStatus(intent, XapkPendingSessionInfo.STATUS_INSTALL_CANCELED)
finish()
}
else -> {
updatePendingSessionInfoStatus(intent, XapkPendingSessionInfo.STATUS_INSTALL_SUCCESS)
finish()
}
}
}
private fun updatePendingSessionInfoStatus(intent: Intent, status: Int) {
val installPackagePath = intent.getStringExtra(KEY_PACKAGE_PATH)
if (!installPackagePath.isNullOrEmpty()) {
val pendingSessionInfo = XapkInstaller.getPendingSessionInfo(installPackagePath)
pendingSessionInfo?.updateStatus(status)
}
}
}

View File

@ -2,14 +2,19 @@ package com.gh.common.xapk
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Build
import android.provider.Settings
import com.gh.common.constant.Config
import com.gh.common.util.*
import com.gh.download.DownloadDataHelper
import com.gh.download.DownloadManager
import com.gh.gamecenter.common.utils.debugOnly
import com.gh.gamecenter.common.utils.getExtension
import com.gh.gamecenter.common.utils.throwExceptionInDebug
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.SentryHelper
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.xapk.XApkUnZipper
import com.gh.gamecenter.xapk.core.XApkFile
import com.gh.gamecenter.xapk.core.XApkUnZipCallback
@ -50,6 +55,9 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
const val XAPK_DATA_EXTENSION_NAME = "obb"
const val PACKAGE_EXTENSION_NAME = "apk"
private const val GUIDE_TYPE_MIUI_OPTIMIZATION = "miui_optimization"
private const val MIUI_OPTIMIZATION_WARNING_DIALOG_ENTRANCE = "MIUI优化关闭提示弹窗"
private var mContext = HaloApp.getInstance().application.applicationContext
private val mXApkUnZipper = XApkUnZipper(this)
@ -59,9 +67,7 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
private val mDownloadEntityMap = Collections.synchronizedMap(HashMap<String, DownloadEntity>())
private val mInstallingPath = Collections.synchronizedList(mutableListOf<String>())
private val mPendingSessionIdMap = Collections.synchronizedMap(HashMap<String, Int>())
private val mPendingSessionInfoMap = HashMap<String, XapkPendingSessionInfo>()
// 按并行解压
@JvmStatic
@ -70,6 +76,35 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
val filePath = downloadEntity.path
if (XAPK_EXTENSION_NAME == filePath.getExtension()) {
if (MiuiUtils.isMiui() && !MiuiUtils.isMiuiOptimizationDisabled() && downloadEntity.format == Constants.XAPK_APKS_FORMAT) {// 小米手机开启miui以后需要引导用户关闭miui优化
DialogHelper.showMiuiOptimizationWarning(
context,
onHintClick = {
val guides = Config.getNewApiSettingsEntity()?.install
val miuiOptimizationGuide = guides?.guides?.findLast {
it.type == GUIDE_TYPE_MIUI_OPTIMIZATION
}
if (miuiOptimizationGuide != null) {
DirectUtils.directToLinkPage(
context,
miuiOptimizationGuide.link,
MIUI_OPTIMIZATION_WARNING_DIALOG_ENTRANCE,
""
)
}
},
onConfirmClick = {
if (SystemUtils.isDevelopmentSettingsEnabled(context)) {
context.startActivity(Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS))
it.dismiss()
} else {
ToastUtils.showToast(context.getString(R.string.miui_open_adb_hint))
}
}
)
return
}
unzipXapkFile(downloadEntity)
if (showUnzipToast) {
Utils.toast(mContext, "解压过程请勿退出光环助手!")
@ -99,7 +134,11 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
val downloadEntity = mDownloadEntityMap[apk.file.path] ?: return
downloadEntity.meta[XAPK_UNZIP_PERCENT] = String.format("%.2f", progress * 100)
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.UNZIPPING.name
NDataChanger.notifyDataChanged(downloadEntity)
AppExecutor.ioExecutor.execute {
NDataChanger.notifyDataChanged(downloadEntity)
}
debugOnly {
Utils.log("unzip", "onProgress->$progress")
}
@ -110,43 +149,40 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "100.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.SUCCESS.name
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk解压成功")
AppExecutor.ioExecutor.execute {
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk解压成功")
}
debugOnly {
Utils.log("unzip", "onSuccess->${downloadEntity.path}")
}
if (!mInstallingPath.contains(downloadEntity.path)) {
mInstallingPath.add(downloadEntity.path)
}
NDataChanger.notifyDataChanged(downloadEntity)
XapkInstallerLooper.add(downloadEntity.path, installer)
XapkInstallerLooper.install(mContext)
installer.install(mContext)
}
override fun onError(apk: XApkFile, exception: Throwable) {
val downloadEntity = mDownloadEntityMap[apk.file.path] ?: return
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.FAILURE.name
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
// 仅官网渠道上报 XAPK 异常信息
if (HaloApp.getInstance().channel == "GH_206") {
SentryHelper.onEvent(
"XAPK_UNZIP_ERROR",
"gameName", downloadEntity.name,
"errorDigest", exception.localizedMessage
)
AppExecutor.ioExecutor.execute {
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
// 仅官网渠道上报 XAPK 异常信息
if (HaloApp.getInstance().channel == "GH_206") {
SentryHelper.onEvent(
"XAPK_UNZIP_ERROR",
"gameName", downloadEntity.name,
"errorDigest", exception.localizedMessage
)
}
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk解压失败")
}
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk解压失败")
debugOnly {
Utils.log("unzip", "onFailure->$exception")
}
@ -156,8 +192,10 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
val downloadEntity = mDownloadEntityMap.remove(apk.file.path) ?: return
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "0.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.CANCEL.name
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
AppExecutor.ioExecutor.execute {
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
}
}
override fun onNext(apk: XApkFile, fileName: String) {
@ -166,11 +204,9 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
}
}
fun isInstalling(packagePath: String): Boolean = mInstallingPath.contains(packagePath)
fun getPendingSessionInfo(packagePath: String): XapkPendingSessionInfo? = mPendingSessionInfoMap[packagePath]
fun onPendingUserAction(packagePath: String, sessionId: Int) {
mPendingSessionIdMap[packagePath] = sessionId
}
fun isInstalling(packagePath: String): Boolean = mPendingSessionInfoMap.containsKey(packagePath)
/**
* 通知XAPK安装完成
@ -178,41 +214,32 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
fun onInstalled(packagePath: String) {
val downloadEntity = mDownloadEntityMap.remove(packagePath) ?: return
mPendingSessionIdMap.remove(packagePath)
mInstallingPath.remove(packagePath)
mPendingSessionInfoMap.remove(packagePath)
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "100.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.INSTALLED.name
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk安装成功")
XapkInstallerLooper.remove(downloadEntity.path)
XapkInstallerLooper.install(mContext)
AppExecutor.ioExecutor.execute {
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk安装成功")
}
}
fun onInstallCanceled(packagePath: String) {
val downloadEntity = mDownloadEntityMap.remove(packagePath) ?: return
mPendingSessionIdMap.remove(packagePath)
mInstallingPath.remove(packagePath)
mPendingSessionInfoMap.remove(packagePath)
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "0.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.CANCEL.name
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk安装取消")
XapkInstallerLooper.remove(downloadEntity.path)
XapkInstallerLooper.install(mContext)
AppExecutor.ioExecutor.execute {
NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
DownloadDataHelper.uploadDownloadStatusEvent(downloadEntity, "xapk安装取消")
}
}
/**
@ -220,29 +247,48 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
* 1. 用户触碰安装弹窗(原生Android系统)区域外导致安装取消
*/
fun updateCurrentInstallStatus() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || mPendingSessionIdMap.isEmpty()) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || mPendingSessionInfoMap.isEmpty()) {
return
}
val installer = mContext.packageManager.packageInstaller
val updateList = mutableListOf<XapkPendingSessionInfo>()
for (pendingSessionEntry in mPendingSessionIdMap) {
val sessionInfo = installer.getSessionInfo(pendingSessionEntry.value)
for (pendingSessionInfoEntry in mPendingSessionInfoMap) {
// 1. 用户点击了取消按钮时sessionInfo为空
// 2. 用户点击了确定按钮时sessionInfo的progress大于0.8
if (sessionInfo == null || sessionInfo.progress > 0.8F) {
continue
val pendingSessionInfo = pendingSessionInfoEntry.value
if (pendingSessionInfo.getStatus() == XapkPendingSessionInfo.STATUS_PENDING_USER_ACTION) {// 用户触摸安装弹窗外部区域取消安装后,更新安装状态
val installer = mContext.packageManager.packageInstaller
val sessionId = pendingSessionInfo.sessionId
if (sessionId != -1) {
val sessionInfo = installer.getSessionInfo(sessionId)
// 表示用户点击了安装弹窗外部区域
if (sessionInfo == null) {
pendingSessionInfo.updateStatus(XapkPendingSessionInfo.STATUS_INSTALL_CANCELED)
} else if (sessionInfo.progress <= 0.8F) {
AppExecutor.ioExecutor.execute {
installer.abandonSession(sessionInfo.sessionId)
}
pendingSessionInfo.updateStatus(XapkPendingSessionInfo.STATUS_INSTALL_CANCELED)
}
}
}
installer.abandonSession(sessionInfo.sessionId)
val installStatus = pendingSessionInfo.getStatus()
if (installStatus == XapkPendingSessionInfo.STATUS_INSTALL_CANCELED
|| installStatus == XapkPendingSessionInfo.STATUS_INSTALL_SUCCESS
) {
updateList.add(pendingSessionInfo)
}
}
val downloadEntity = mDownloadEntityMap[pendingSessionEntry.key] ?: return
if (!PackageUtils.isInstalled(mContext, downloadEntity.packageName)) {
onInstallCanceled(downloadEntity.path)
} else {
for (pendingSessionInfo in updateList) {
val downloadEntity = mDownloadEntityMap[pendingSessionInfo.path] ?: continue
val installStatus = pendingSessionInfo.getStatus()
if (installStatus == XapkPendingSessionInfo.STATUS_INSTALL_SUCCESS) {
onInstalled(downloadEntity.path)
} else if (installStatus == XapkPendingSessionInfo.STATUS_INSTALL_CANCELED) {
onInstallCanceled(downloadEntity.path)
}
}
}
@ -268,9 +314,16 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
private val xApkFile: XApkFile,
private val sessionId: Int,
) : IPackageInstaller {
override fun install(context: Context) {
val applicationContext = context.applicationContext
val downloadEntity = mDownloadEntityMap[xApkFile.file.path] ?: return
PackageInstaller.installMultiple(context, downloadEntity.path, sessionId)
mPendingSessionInfoMap[downloadEntity.path] = XapkPendingSessionInfo(downloadEntity.path, sessionId)
AppExecutor.ioExecutor.execute {// 有可能卡顿造成anr
PackageInstaller.installMultiple(applicationContext, downloadEntity.path, sessionId)
NDataChanger.notifyDataChanged(downloadEntity)
}
}
}
@ -278,6 +331,7 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
private val xApkFile: XApkFile,
private val file: File
) : IPackageInstaller {
override fun install(context: Context) {
val downloadEntity = mDownloadEntityMap[xApkFile.file.path] ?: return
PackageInstaller.install(
@ -288,49 +342,12 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
)
}
}
/**
* XAPK安装每次只能执行一个安装流程因此添加一个安装队列
*/
private object XapkInstallerLooper {
private val packagePathList = mutableListOf<String>()
private val installerList = mutableListOf<IPackageInstaller>()
fun add(packagePath: String, installer: IPackageInstaller) {
if (packagePathList.contains(packagePath)) {
return
}
packagePathList.add(packagePath)
installerList.add(installer)
}
fun install(context: Context) {
if (installerList.isEmpty()) {
return
}
installerList.first().install(context)
}
fun remove(packagePath: String) {
if (!packagePathList.contains(packagePath)) {
return
}
val index = packagePathList.indexOf(packagePath)
if (index != -1) {
packagePathList.removeAt(index)
installerList.removeAt(index)
}
}
}
}
enum class XapkUnzipStatus(status: String) {
UNZIPPING("unzipping"),
SUCCESS("success"),
CANCEL("cancel"),
INSTALLING("installing"),
INSTALLED("installed"),
FAILURE("failure");
}

View File

@ -0,0 +1,21 @@
package com.gh.common.xapk
class XapkPendingSessionInfo(
val path: String,
val sessionId: Int = -1
) {
companion object {
const val STATUS_INIT = -1
const val STATUS_PENDING_USER_ACTION = 0
const val STATUS_INSTALL_SUCCESS = 1
const val STATUS_INSTALL_CANCELED = 2
}
private var status = STATUS_INIT
internal fun updateStatus(status: Int) {
this.status = status
}
fun getStatus(): Int = status
}

View File

@ -23,9 +23,6 @@ import org.json.JSONObject
object DownloadDataHelper {
private const val TAG = "DownloadDataHelper"
private const val DOWNLOAD_SPEED_TIME = "download_speed_time"
private const val DOWNLOAD_SPEED_SIZE = "download_speed_size"
const val DOWNLOAD_RESUME_WAY = "download_resume_way"
const val DOWNLOAD_RESUME_MANUAL = "manual"
const val DOWNLOAD_RESUME_AUTO = "auto"
@ -34,8 +31,6 @@ object DownloadDataHelper {
const val DOWNLOAD_CANCEL_MANUAL = "manual"
const val DOWNLOAD_CANCEL_AUTO = "auto"
const val DOWNLOAD_FIRST_START = "download_first_start"
const val DOWNLOAD_THREAD_SIZE = "download_thread_size" // 线程数量0为传统单线程模式; 1为多线程的单线程; >1为多线程的实际线程数量
private val mDownloadSpeedMap = HashMap<String, MutableList<Long>>()
@ -140,26 +135,28 @@ object DownloadDataHelper {
@JvmStatic
fun uploadDownloadEvent(downloadEntity: DownloadEntity) {
val downloadSimpleEntity = DownloadDataSimpleHelper.getDownloadDataSimpleEntity(downloadEntity.url)
if (downloadEntity.status != DownloadStatus.downloading) {
uploadDownloadStatusEvent(downloadEntity)
}
if (downloadEntity.status == DownloadStatus.downloading) {
val startupTime = downloadEntity.meta[DownloadEntity.DOWNLOAD_STARTUP_TIME_KEY]
val startupTime =
downloadSimpleEntity?.downloadStartUpTime
if (startupTime != null) {
uploadDownloadStartupTimeEvent(downloadEntity, startupTime.toInt())
downloadEntity.meta.remove(DownloadEntity.DOWNLOAD_STARTUP_TIME_KEY)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
uploadDownloadStartupTimeEvent(downloadEntity, startupTime)
DownloadDataSimpleHelper.updateDownloadDataSimpleEntity(downloadEntity.url, downloadStartUpTime = null)
}
}
if (downloadEntity.status == DownloadStatus.downloading || downloadEntity.status == DownloadStatus.done) {
val time = downloadEntity.meta[DOWNLOAD_SPEED_TIME]
val size = downloadEntity.meta[DOWNLOAD_SPEED_SIZE]
val time = downloadSimpleEntity?.downloadSpeedTime
val size = downloadSimpleEntity?.downloadSpeedSize
if (downloadEntity.speed == 0L || time == null || size == null) {
downloadEntity.meta[DOWNLOAD_SPEED_TIME] = System.currentTimeMillis().toString()
downloadEntity.meta[DOWNLOAD_SPEED_SIZE] = downloadEntity.progress.toString()
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
val currentTime = System.currentTimeMillis()
val currentProgress = downloadEntity.progress
DownloadDataSimpleHelper.updateDownloadDataSimpleEntity(downloadEntity.url, downloadSpeedTime = currentTime, downloadSpeedSize = currentProgress)
} else {
val offset = System.currentTimeMillis() - time.toLong()
if (offset > 5000) {
@ -180,15 +177,15 @@ object DownloadDataHelper {
}
}
}
downloadEntity.meta[DOWNLOAD_SPEED_TIME] = System.currentTimeMillis().toString()
downloadEntity.meta[DOWNLOAD_SPEED_SIZE] = downloadEntity.progress.toString()
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
val currentTime = System.currentTimeMillis()
val currentProgress = downloadEntity.progress
DownloadDataSimpleHelper.updateDownloadDataSimpleEntity(downloadEntity.url, downloadSpeedTime = currentTime, downloadSpeedSize = currentProgress)
}
}
}
}
private fun uploadDownloadStartupTimeEvent(downloadEntity: DownloadEntity, startupTime: Int) {
private fun uploadDownloadStartupTimeEvent(downloadEntity: DownloadEntity, startupTime: Long) {
val jsonObject = JSONObject()
try {
@ -280,7 +277,7 @@ object DownloadDataHelper {
}
payloadObject.put("completed_size", downloadEntity.progress / 1024 / 1024)
if (downloadEntity.status == DownloadStatus.resume) {
if (downloadEntity.meta[DOWNLOAD_FIRST_START] == "YES") {
if (DownloadDataSimpleHelper.getDownloadDataSimpleEntity(downloadEntity.url)?.isFirstTimeDownload == true) {
payloadObject.put("is_first_start", true)
} else {
payloadObject.put("is_first_start", false)
@ -288,8 +285,7 @@ object DownloadDataHelper {
}
if (downloadEntity.status == DownloadStatus.resume || downloadEntity.status == DownloadStatus.add) {
downloadEntity.meta[DOWNLOAD_FIRST_START] = "NO"
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
DownloadDataSimpleHelper.updateDownloadSimpleEntityFirstTimeDownload(downloadEntity.url, false)
}
jsonObject.put("payload", payloadObject)
} catch (e: Exception) {
@ -342,7 +338,7 @@ object DownloadDataHelper {
/**
* 分片检测下载进度,每隔15秒内记录一次,60秒上传一次
*
* 请见:https://gitlab.ghzs.com/stats/stats-issues/-/issues/188#note_66919
* 请见:https://git.shanqu.cc/stats/stats-issues/-/issues/188#note_66919
*/
fun uploadDownloadHeartbeat(upload: Boolean) {
val allDownloadEntity = DownloadManager.getInstance().allDownloadEntity

View File

@ -0,0 +1,60 @@
package com.gh.download
import android.content.Context
import android.content.SharedPreferences
import com.gh.gamecenter.common.HaloApp
import com.gh.gamecenter.common.utils.toJsonIgnoredNull
import com.gh.gamecenter.common.utils.toObject
import com.gh.gamecenter.core.utils.SPUtils
/**
* 用来简单保存/获取下载时一些额外信息的辅助类,避免下载时反复修改原始下载实体的糟糕操作
* 使用 SP 来实现,只适用于相对较为低频的调用
*/
object DownloadDataSimpleHelper {
private val mSp: SharedPreferences by lazy {
HaloApp.getInstance().getSharedPreferences("DownloadDataSimpleDao", Context.MODE_PRIVATE)
}
fun getDownloadDataSimpleEntity(url: String): DownloadDataSimpleEntity? {
return mSp.getString(url, "")?.toObject()
}
fun updateDownloadDataSimpleEntity(
url: String,
downloadStartUpTime: Long? = null,
downloadSpeedTime: Long? = null,
downloadSpeedSize: Long? = null,
) {
val entity = getDownloadDataSimpleEntity(url) ?: DownloadDataSimpleEntity()
entity.downloadStartUpTime = downloadStartUpTime
entity.downloadSpeedTime = downloadSpeedTime
entity.downloadSpeedSize = downloadSpeedSize
SPUtils.setString(mSp, url, entity.toJsonIgnoredNull())
}
fun updateDownloadSimpleEntityFirstTimeDownload(url: String, isFirstTimeDownload: Boolean) {
val entity = getDownloadDataSimpleEntity(url) ?: DownloadDataSimpleEntity()
entity.isFirstTimeDownload = isFirstTimeDownload
SPUtils.setString(mSp, url, entity.toJsonIgnoredNull())
}
fun removeDownloadSimpleEntity(url: String) {
SPUtils.remove(mSp, url)
}
}
class DownloadDataSimpleEntity(
var downloadStartUpTime: Long? = null,
var downloadSpeedTime: Long? = null,
var downloadSpeedSize: Long? = null,
var isFirstTimeDownload: Boolean? = true
)

View File

@ -834,6 +834,7 @@ public class DownloadManager implements DownloadStatusListener {
*/
public void cancel(String url, boolean isDeleteFile, boolean automatic, boolean cancelSilently) {
DownloadEntity entry = mDownloadDao.getSnapshot(url);
DownloadDataSimpleHelper.INSTANCE.removeDownloadSimpleEntity(url);
if (entry != null) {
AppExecutor.getIoExecutor().execute(() -> {
NDownloadBridge.INSTANCE.cancel(url);
@ -996,8 +997,11 @@ public class DownloadManager implements DownloadStatusListener {
}
if (status == DownloadStatus.add || status == DownloadStatus.subscribe) {
if (downloadEntity.getMeta().get(DownloadDataHelper.DOWNLOAD_FIRST_START) == null) {
downloadEntity.getMeta().put(DownloadDataHelper.DOWNLOAD_FIRST_START, "YES");
DownloadDataSimpleEntity simpleEntity =
DownloadDataSimpleHelper.INSTANCE.getDownloadDataSimpleEntity(downloadEntity.getUrl());
if (simpleEntity == null || simpleEntity.isFirstTimeDownload() == null) {
DownloadDataSimpleHelper.INSTANCE.updateDownloadSimpleEntityFirstTimeDownload(downloadEntity.getUrl(), true);
}
}
@ -1237,7 +1241,10 @@ public class DownloadManager implements DownloadStatusListener {
/**
* 更新数据库中的下载实体
*
* @deprecated 随意更新数据库可能会出现意想不到的情况,建议不要随意调用
*/
@Deprecated()
public void updateDownloadEntity(DownloadEntity downloadEntity) {
mDownloadDao.update(downloadEntity, false);
}

View File

@ -111,8 +111,7 @@ object PackageObserver {
runOnIoThread { FileUtils.deleteFile(mDownloadEntity.path) }
}
if (mDownloadEntity.format == Constants.XAPK_FORMAT
|| mDownloadEntity.format == Constants.XAPK_APKS_FORMAT) {
if (mDownloadEntity.format == Constants.XAPK_FORMAT) {
XapkInstaller.onInstalled(mDownloadEntity.path)
}

View File

@ -55,23 +55,21 @@ object DownloadMessageHandler : InnerDownloadListener {
* @param status 下载状态
*/
override fun onStatusChanged(id: String, status: DownloadStatus) {
val entity = findEntity(id)
val entity = findEntity(id) ?: return
if (entity != null) {
entity.status = status
entity.status = status
if (status == DownloadStatus.COMPLETED) {
SimpleDownloadManager.resumeQueuedTask()
}
if (status == DownloadStatus.COMPLETED) {
SimpleDownloadManager.resumeQueuedTask()
}
ExecutorProvider.getInstance().backgroundExecutor.execute {
updateDownloadToDatabase(entity)
updateDownloadList()
}
ExecutorProvider.getInstance().backgroundExecutor.execute {
updateDownloadToDatabase(entity)
updateDownloadList()
}
for (listener in mGlobalStatusChangedListenerList) {
listener.invoke(entity!!, status)
listener.invoke(entity, status)
}
val listenerList = mListenerMap[id] ?: return

View File

@ -198,7 +198,6 @@ public class MainActivity extends BaseActivity {
protected void onCreate(Bundle savedInstanceState) {
showAd = getIntent().getBooleanExtra(SHOW_AD, false) && savedInstanceState == null;
HaloApp.getInstance().initFresco();
HaloApp.getInstance().isAlreadyUpAndRunning = true;
super.onCreate(savedInstanceState);

View File

@ -297,19 +297,7 @@ class SplashScreenActivity : BaseActivity() {
private fun doFlavorInit() {
HaloApp.getInstance().flavorProvider.init(HaloApp.getInstance(), this, PkgHelper.getActivateRatio())
val whiteListChannel = arrayListOf(
"GH_206",
"KS-GHZS-KY1",
"KS-GHZS-MC1",
"GDT_GHZS_MC1",
"T11-GH-APPDY-ZC01",
"T7-GH-APPDY-KY03",
"T8-GH-APPUX-KY04",
"T1-GHZS-MC01",
"T4-GHZS-MC03"
)
if (whiteListChannel.contains(HaloApp.getInstance().channel) || PackageFlavorHelper.IS_TEST_FLAVOR) {
if (HaloApp.getInstance().channel == "GH_206" || PackageFlavorHelper.IS_TEST_FLAVOR) {
SensorsBridge.init(HaloApp.getInstance(), HaloApp.getInstance().channel)
}
}

View File

@ -12,10 +12,6 @@ import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import com.airbnb.lottie.LottieAnimationView;
import com.gh.common.chain.AutoSwitchAssistantInstallHandler;
import com.gh.common.chain.UnsupportedFeatureHandler;
import com.gh.common.util.PackageLauncher;
import com.gh.gamecenter.common.base.GlobalActivityManager;
import com.gh.common.chain.BrowserInstallHandler;
import com.gh.common.chain.CertificationHandler;
import com.gh.common.chain.ChainBuilder;
@ -26,15 +22,13 @@ import com.gh.common.chain.DownloadDialogHelperHandler;
import com.gh.common.chain.GamePermissionHandler;
import com.gh.common.chain.OverseaDownloadHandler;
import com.gh.common.chain.PackageCheckHandler;
import com.gh.common.chain.UnsupportedFeatureHandler;
import com.gh.common.chain.UpdateNewSimulatorHandler;
import com.gh.common.chain.ValidateVSpaceHandler;
import com.gh.common.chain.VersionNumberHandler;
import com.gh.common.constant.Config;
import com.gh.common.dialog.DeviceRemindDialog;
import com.gh.common.dialog.GameOffServiceDialogFragment;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.common.utils.SensorsBridge;
import com.gh.gamecenter.feature.exposure.ExposureEvent;
import com.gh.common.filter.RegionSetting;
import com.gh.common.filter.RegionSettingHelper;
import com.gh.common.history.HistoryHelper;
@ -42,34 +36,38 @@ import com.gh.common.simulator.NewSimulatorGameManager;
import com.gh.common.simulator.SimulatorDownloadManager;
import com.gh.common.simulator.SimulatorGameManager;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.DirectUtils;
import com.gh.common.xapk.XapkInstaller;
import com.gh.common.xapk.XapkUnzipStatus;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.utils.DataLogUtils;
import com.gh.common.util.DetailDownloadUtils;
import com.gh.gamecenter.common.utils.DialogHelper;
import com.gh.common.util.DialogUtils;
import com.gh.gamecenter.core.utils.PageSwitchDataHelper;
import com.gh.common.util.DirectUtils;
import com.gh.common.util.LogUtils;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageLauncher;
import com.gh.common.util.PackageUtils;
import com.gh.gamecenter.common.utils.PermissionHelper;
import com.gh.common.util.ReservationHelper;
import com.gh.gamecenter.feature.view.DownloadButton;
import com.gh.common.xapk.XapkInstaller;
import com.gh.common.xapk.XapkUnzipStatus;
import com.gh.download.DownloadManager;
import com.gh.download.dialog.DownloadDialog;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WebActivity;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.core.utils.StringUtils;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.entity.LinkEntity;
import com.gh.gamecenter.common.eventbus.EBReuse;
import com.gh.gamecenter.feature.entity.SimulatorEntity;
import com.gh.gamecenter.common.utils.DataLogUtils;
import com.gh.gamecenter.common.utils.DialogHelper;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.common.utils.PermissionHelper;
import com.gh.gamecenter.common.utils.SensorsBridge;
import com.gh.gamecenter.core.utils.PageSwitchDataHelper;
import com.gh.gamecenter.core.utils.StringUtils;
import com.gh.gamecenter.eventbus.EBScroll;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.feature.entity.SimulatorEntity;
import com.gh.gamecenter.feature.exposure.ExposureEvent;
import com.gh.gamecenter.feature.view.DownloadButton;
import com.gh.gamecenter.gamedetail.GameDetailFragment;
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment;
import com.gh.gamecenter.teenagermode.TeenagerModeActivity;
@ -227,7 +225,6 @@ public class DetailViewHolder {
}
case PLUGIN:
ChainBuilder builder = new ChainBuilder();
builder.addHandler(new AutoSwitchAssistantInstallHandler());
builder.addHandler(new UnsupportedFeatureHandler());
builder.addHandler(new UpdateNewSimulatorHandler());
builder.addHandler(new GamePermissionHandler());

View File

@ -138,8 +138,7 @@ public class GameDownloadFragment extends BaseFragment implements View.OnClickLi
}
}
adapter.getUrlMap().put(PackageUtils.getPackageNameByPath(HaloApp.getInstance().getApplication(),
downloadEntity.getPath()), downloadEntity.getUrl());
adapter.getUrlMap().put(downloadEntity.getPackageName(), downloadEntity.getUrl());
// 用户焦点在下载管理页面时有任务完成,直接把所有下载完成的任务标记为已读
DownloadManager.getInstance().markDownloadedTaskAsRead();

View File

@ -584,6 +584,7 @@ class UpdatableGameViewModel(
downloadEntity.platform = update.platform
downloadEntity.packageName = update.packageName
downloadEntity.versionName = update.version
downloadEntity.pluginDesc = update.pluginDesc
downloadEntity.addMetaExtra(Constants.RAW_GAME_ICON, update.rawIcon)
downloadEntity.addMetaExtra(Constants.GAME_ICON_SUBSCRIPT, update.iconSubscript)
downloadEntity.addMetaExtra(Constants.DOWNLOAD_ID, downloadId)

View File

@ -1,5 +1,6 @@
package com.gh.gamecenter.entity
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.feature.entity.SimulatorEntity
import com.google.gson.annotations.SerializedName
@ -29,7 +30,9 @@ class NewApiSettingsEntity(
// VPN 配置
class Install(
@SerializedName("vpn_required")
val vpnRequired: VpnSetting? = null
val vpnRequired: VpnSetting? = null,
@SerializedName("guides")
val guides: List<Guide>? = null
)
class VpnSetting(
@ -38,4 +41,9 @@ class NewApiSettingsEntity(
@SerializedName("packages")
val vpnMatchedPackagesName: HashSet<String>
)
class Guide(
val type: String,
val link: LinkEntity
)
}

View File

@ -773,7 +773,18 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
}
// 这里的 selectedPosition 指的是应该被高亮显示的 position
val selectedPosition = (position + positionOffset).roundToInt()
val selectedPosition = try {
(position + positionOffset).roundToInt()
} catch (e: IllegalArgumentException) {
// roundToInt() 方法有时候会报 Cannot round NaN value. 错误
// https://sentry.shanqu.cc/organizations/lightgame/issues/301377/?project=22
SentryHelper.onEvent(
"HOME_NAN_POSITION",
"value",
"$position+$positionOffset=(${position + positionOffset})"
)
position
}
val positionOffsetOnRealSelectedPosition = if (positionOffset >= 0.5) {
positionOffset - 1
} else {
@ -797,8 +808,8 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
// positionOffset 小于零,表示 indicator 当前位置处于选中的 tab 的左边
val indicatorOnLeft = positionOffset < 0F
val selectedTabBinding = mTabBindingList[selectedPosition]
val selectedTabImageStyle = mTabImageStyleList[selectedPosition]
val selectedTabBinding = mTabBindingList.safelyGetInRelease(selectedPosition) ?: return
val selectedTabImageStyle = mTabImageStyleList.safelyGetInRelease(selectedPosition) ?: return
// 前一个 tab、当前选中的 tab、后一个 tab 的显示比例
val preScaleRatio = 1 + abs(positionOffset) / 4

View File

@ -84,6 +84,7 @@ class HomeSearchToolWrapperViewModel(application: Application) : AndroidViewMode
if (pkgLinkEntity.type == tab.type
&& (pkgLinkEntity.link == tab.link || tab.link == null)) {
defaultTabPosition = index
PkgHelper.markConfigUsed()
break
}
}

View File

@ -82,7 +82,6 @@ import com.gh.gamecenter.home.test_v2.HomeGameTestV2GameListRvAdapter
import com.gh.gamecenter.home.test_v2.HomeGameTestV2ViewModel
import com.gh.gamecenter.home.test_v2.HomeItemGameTestV2ViewHolder
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
import com.gh.gamecenter.servers.GameServersActivity
import com.gh.gamecenter.servers.gametest2.GameServerTestV2Activity
import com.gh.gamecenter.subject.SubjectActivity
import com.lightgame.adapter.BaseRecyclerAdapter
@ -1270,38 +1269,51 @@ class GameFragmentAdapter(
}
}
private fun getGameCollectionExposureEventList(itemData: GameItemData): ArrayList<ExposureEvent> {
private fun getHomeGameCollectionExposureEventList(
itemData: GameItemData,
refreshCurrentPosition: Int = -1
): ArrayList<ExposureEvent> {
val exposureList = arrayListOf<ExposureEvent>()
runOnIoThread(true) {
itemData.gameCollection?.gameCollectionItemDataList?.forEachIndexed { index, gameCollectionItemData ->
val gameCollection = gameCollectionItemData.homeGameCollectionItem
val gameCollectionSource =
listOf(
ExposureSource("游戏单合集", itemData.gameCollection?.id ?: ""),
ExposureSource("游戏单", "${gameCollection?.title} + ${gameCollection?.id}")
)
val exposureEvent = ExposureEvent.createEventWithSourceConcat(
gameEntity = GameEntity().apply {
isAdData = gameCollection?.adIconActive ?: false
outerSequence = gameCollectionItemData.outerSequence
sequence = index
},
basicSource = mBasicExposureSource,
source = gameCollectionSource
)
gameCollection?.games?.forEach {
it.exposureEvent = ExposureEvent.createEventWithSourceConcat(
gameEntity = it.apply {
isAdData = gameCollection.adIconActive
outerSequence = gameCollectionItemData.outerSequence
sequence = index
},
basicSource = mBasicExposureSource,
source = gameCollectionSource
)
itemData.gameCollection?.gameCollectionItemDataList?.run {
val currentIndex = if (itemData.gameCollection?.style?.contains("refresh") == true) {
refreshCurrentPosition % size
} else -1
forEachIndexed { index, gameCollectionItemData ->
if (itemData.gameCollection?.style?.contains("refresh") == false || currentIndex == index) {
gameCollectionItemData.homeGameCollectionItem?.let {
val gameCollectionSource =
listOf(
ExposureSource("游戏单合集", itemData.gameCollection?.id ?: ""),
ExposureSource("游戏单", "${it.title} + ${it.id}")
)
val gameExposureList = arrayListOf<ExposureEvent>()
it.games?.forEach { game ->
game.isAdData = it.adIconActive
game.outerSequence = gameCollectionItemData.outerSequence
game.sequence = index
val exposureEvent = ExposureEvent.createEventWithSourceConcat(
gameEntity = game,
basicSource = mBasicExposureSource,
source = gameCollectionSource
)
game.exposureEvent = exposureEvent
gameExposureList.add(exposureEvent)
}
exposureList.addAll(gameExposureList)
gameCollectionItemData.exposureEvent = ExposureEvent.createEventWithSourceConcat(
gameEntity = GameEntity().apply {
adIconActive = it.adIconActive
outerSequence = gameCollectionItemData.outerSequence
sequence = index
},
basicSource = mBasicExposureSource,
source = gameCollectionSource
)
}
}
}
gameCollectionItemData.exposureEvent = exposureEvent
exposureList.add(exposureEvent)
}
}
return exposureList
@ -1309,7 +1321,7 @@ class GameFragmentAdapter(
private fun bindGameCollectionCarousel(holder: HomeGameCollectionCarouselViewHolder, position: Int) {
val gameItemData = mItemDataList[position]
gameItemData.exposureEventList = getGameCollectionExposureEventList(gameItemData)
gameItemData.exposureEventList = getHomeGameCollectionExposureEventList(gameItemData)
gameItemData.gameCollection?.let {
holder.bindGameCollectionList(
it,
@ -1322,7 +1334,7 @@ class GameFragmentAdapter(
private fun bindGameCollectionSlide(holder: HomeGameCollectionSlideViewHolder, position: Int) {
val gameItemData = mItemDataList[position]
gameItemData.exposureEventList = getGameCollectionExposureEventList(gameItemData)
gameItemData.exposureEventList = getHomeGameCollectionExposureEventList(gameItemData)
gameItemData.gameCollection?.let {
holder.bindGameCollectionSlide(
it,
@ -1335,7 +1347,7 @@ class GameFragmentAdapter(
private fun bindGameCollectionRefresh(holder: HomeGameCollectionRefreshViewHolder, position: Int) {
val gameItemData = mItemDataList[position]
gameItemData.exposureEventList = getGameCollectionExposureEventList(gameItemData)
gameItemData.exposureEventList = getHomeGameCollectionExposureEventList(gameItemData, holder.currentPosition)
gameItemData.gameCollection?.let {
holder.bindGameCollectionRefresh(
it,
@ -1343,7 +1355,7 @@ class GameFragmentAdapter(
mViewModel.blockData?.link ?: "",
mViewModel.blockData?.name ?: ""
) {
mViewModel.changeGameCollectionRefresh(it.id)
mViewModel.changeGameCollectionRefresh(it.id, true)
}
}
}

View File

@ -598,17 +598,17 @@ class GameViewModel(application: Application, var blockData: SubjectRecommendEnt
}
}
fun changeGameCollectionRefresh(collectionId: String): Boolean {
fun changeGameCollectionRefresh(collectionId: String, isRefreshClick: Boolean): Boolean {
val page = (mRefreshGameCollectionPageMap[collectionId] ?: 1) + 1
return if (page != 0) {
getGameCollectionRefresh(collectionId, page)
getGameCollectionRefresh(collectionId, page, isRefreshClick)
true // 表示需要从接口获取数据
} else {
false // 表示已加载完毕
}
}
private fun getGameCollectionRefresh(collectionId: String, page: Int) {
private fun getGameCollectionRefresh(collectionId: String, page: Int, isRefreshClick: Boolean) {
mSensitiveApi.getGameCollectionRefresh(collectionId, "block", page, 1)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
@ -622,6 +622,15 @@ class GameViewModel(application: Application, var blockData: SubjectRecommendEnt
addAll(response)
}
}
// 手动点击刷新获取时,若游戏单内游戏被全部屏蔽会自动获取下一个游戏单
if (isRefreshClick) {
val filterGameList = RegionSettingHelper.filterGame(response[0].games)
if (filterGameList.isEmpty()) {
changeGameCollectionRefresh(collectionId, true)
return
}
}
} else {
// -1 表示加载完毕
mRefreshGameCollectionPageMap[collectionId] = -1
@ -707,6 +716,7 @@ class GameViewModel(application: Application, var blockData: SubjectRecommendEnt
if (!(!isTopItemShown && index == 0)
&& !shouldShowDivider
&& !hideSubjectName
&& !(subjectEntity.type == "game_list_collection" && subjectEntity.style == LegacyHomeFragmentAdapterAssistant.GAME_COLLECTION_VERTICAL_REFRESH_STYLE)
) {
mItemDataListCache.add(getBlankSpacingItem())
}
@ -1006,7 +1016,7 @@ class GameViewModel(application: Application, var blockData: SubjectRecommendEnt
}
for (item in subjectEntity.gameListCollection!!) {
item.games = RegionSettingHelper.filterGame(item.games)
if (!item.games.isNullOrEmpty() || subjectEntity.style?.contains("carousel") == true) {
if (!item.games.isNullOrEmpty() || subjectEntity.style == LegacyHomeFragmentAdapterAssistant.GAME_COLLECTION_CAROUSEL_STYLE || subjectEntity.style == LegacyHomeFragmentAdapterAssistant.GAME_COLLECTION_SMALL_SLIDE_STYLE) {
add(
GameCollectionListItemData(
homeGameCollectionItem = item,
@ -1017,6 +1027,13 @@ class GameViewModel(application: Application, var blockData: SubjectRecommendEnt
}
}
}
if (itemDataList.isEmpty()) {
if (subjectEntity.style?.contains("refresh") == true) {
subjectEntity.id?.let { changeGameCollectionRefresh(it, false) }
return
}
continue
}
// 轮播图样式需要至少3个游戏单
if ((subjectEntity.style == LegacyHomeFragmentAdapterAssistant.GAME_COLLECTION_CAROUSEL_STYLE && itemDataList.size >= 3) || subjectEntity.style != LegacyHomeFragmentAdapterAssistant.GAME_COLLECTION_CAROUSEL_STYLE) {
if (subjectEntity.style?.contains("refresh") == false) {

View File

@ -15,10 +15,19 @@ import com.lightgame.adapter.BaseRecyclerAdapter
class CommonCollectionAdapter(
context: Context,
private var mSubjectEntity: SubjectEntity,
private var mClickClosure: (position: Int, contentEntity: CommonCollectionContentEntity) -> Unit,
private var mExposureClosure: (position: Int, entity: ExposureLinkEntity) -> Unit
) : BaseRecyclerAdapter<CommonCollectionItemViewHolder>(context) {
private var mExposureClosure: ((position: Int, entity: ExposureLinkEntity) -> Unit)? = null
private var mClickClosure: ((position: Int, contentEntity: CommonCollectionContentEntity) -> Unit)? = null
fun setCallback(
clickClosure: ((position: Int, contentEntity: CommonCollectionContentEntity) -> Unit),
exposureClosure: ((position: Int, entity: ExposureLinkEntity) -> Unit)
) {
mClickClosure = clickClosure
mExposureClosure = exposureClosure
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CommonCollectionItemViewHolder {
return CommonCollectionItemViewHolder(parent.toBinding())
}
@ -45,7 +54,7 @@ class CommonCollectionAdapter(
}
if (linkEntity.type == "game") {
mExposureClosure.invoke(position, linkEntity)
mExposureClosure?.invoke(position, linkEntity)
}
holder.binding.apply {
@ -81,7 +90,7 @@ class CommonCollectionAdapter(
rootParams.rightMargin = if (position == itemCount - 1) 16F.dip2px() else 0
root.layoutParams = rootParams
root.setOnClickListener { mClickClosure.invoke(position, contentEntity) }
root.setOnClickListener { mClickClosure?.invoke(position, contentEntity) }
}
}

View File

@ -55,15 +55,20 @@ class CommonCollectionViewHolder(val binding: CommonCollectionListBinding) : Bas
}
}
})
adapter = CommonCollectionAdapter(context, mCollection!!, clickClosure, exposureClosure)
adapter = CommonCollectionAdapter(context, mCollection!!).also {
it.setCallback(clickClosure, exposureClosure)
}
} else {
mLayoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
if (itemDecorationCount > 0) {
removeItemDecorationAt(0)
}
addItemDecoration(SpacingItemDecoration(notDecorateTheFirstItem = true, left = 8f.dip2px()))
addItemDecoration(SpacingItemDecoration(notDecorateTheFirstItem = true, left = 8F.dip2px()))
layoutManager = mLayoutManager
(adapter as CommonCollectionAdapter).checkResetData(mCollection!!)
(adapter as CommonCollectionAdapter).apply {
setCallback(clickClosure, exposureClosure)
checkResetData(mCollection!!)
}
}
}
}

View File

@ -35,6 +35,7 @@ class GameCollectionHotListAdapter(
private val mPath: String,
private val mBasicExposureSource: List<ExposureSource>
) : ListAdapter<GameCollectionListItemData>(context), IExposable {
private val mCoverWidth = (DisplayUtils.getScreenWidth() - 40F.dip2px()) / 2
override fun getItemViewType(position: Int): Int {
return if (position == itemCount - 1) ItemViewType.ITEM_FOOTER else ItemViewType.ITEM_BODY
}
@ -94,7 +95,7 @@ class GameCollectionHotListAdapter(
stampIv.setBackgroundResource(if (entity?.stamp == "official") R.drawable.label_game_collection_official else R.drawable.label_game_collection_special_choice)
titleTv.text = entity?.title
userTv.text = entity?.user?.name
coverImage.setTag(ImageUtils.TAG_TARGET_WIDTH, DisplayUtils.getScreenWidth() - 40F.dip2px())
coverImage.setTag(ImageUtils.TAG_TARGET_WIDTH, mCoverWidth)
ImageUtils.display(coverImage, entity?.cover)
ImageUtils.display(userIv, entity?.user?.icon)

View File

@ -55,6 +55,7 @@ class GameCollectionSquareAdapter(
private val mRefreshCallback: () -> Unit
) :
ListAdapter<GameCollectionListItemData>(context), IExposable {
private val mPosterWidth = DisplayUtils.getScreenWidth() - 32F.dip2px()
override fun setListData(updateData: MutableList<GameCollectionListItemData>?) {
if (updateData == null) {
@ -409,7 +410,7 @@ class GameCollectionSquareAdapter(
}
}
class GameCollectionSquareItemViewHolder(val binding: GameCollectionSquareItemBinding) :
inner class GameCollectionSquareItemViewHolder(val binding: GameCollectionSquareItemBinding) :
RecyclerView.ViewHolder(binding.root) {
@SuppressLint("SetTextI18n")
fun bindGameCollection(
@ -421,6 +422,7 @@ class GameCollectionSquareAdapter(
) {
binding.run {
val context = root.context
poster.setTag(ImageUtils.TAG_TARGET_WIDTH, mPosterWidth)
display(poster, gamesCollectionEntity.cover)
display(userIv, gamesCollectionEntity.user?.icon)
titleTv.text = gamesCollectionEntity.title

View File

@ -324,17 +324,18 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
}
}
fun changeGameCollectionRefresh(collectionId: String): Boolean {
fun changeGameCollectionRefresh(collectionId: String, isRefreshClick: Boolean): Boolean {
val page = (mRefreshGameCollectionPageMap[collectionId] ?: 1) + 1
return if (page != 0) {
getGameCollectionRefresh(collectionId, page)
getGameCollectionRefresh(collectionId, page, isRefreshClick)
true // 表示需要从接口获取数据
} else {
false // 表示已加载完毕
}
}
private fun getGameCollectionRefresh(collectionId: String, page: Int) {
private fun getGameCollectionRefresh(collectionId: String, page: Int, isRefreshClick: Boolean) {
// 每次获取一个游戏单
mApi.getGameCollectionRefresh(collectionId, "home_content", page, 1)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
@ -348,6 +349,15 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
addAll(response)
}
}
// 手动点击刷新获取时,若游戏单内游戏被全部屏蔽会自动获取下一个游戏单
if (isRefreshClick) {
val filterGameList = RegionSettingHelper.filterGame(response[0].games)
if (filterGameList.isEmpty()) {
changeGameCollectionRefresh(collectionId, true)
return
}
}
} else {
// -1 表示加载完毕
mRefreshGameCollectionPageMap[collectionId] = -1
@ -882,12 +892,19 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
}
for (item in homeContent.linkGameCollection!!) {
item.games = RegionSettingHelper.filterGame(item.games)
if (!item.games.isNullOrEmpty() || homeContent.style.contains("carousel")) {
if (!item.games.isNullOrEmpty() || homeContent.style == LegacyHomeFragmentAdapterAssistant.GAME_COLLECTION_CAROUSEL_STYLE || homeContent.style == LegacyHomeFragmentAdapterAssistant.GAME_COLLECTION_SMALL_SLIDE_STYLE) {
add(GameCollectionListItemData(homeGameCollectionItem = item))
}
}
}
}
if (itemDataList.isEmpty()) {
if (homeContent.style.contains("refresh")) {
changeGameCollectionRefresh(homeContent.linkId, false)
return
}
continue
}
// 轮播图样式需要至少3个游戏单
if ((homeContent.style == LegacyHomeFragmentAdapterAssistant.GAME_COLLECTION_CAROUSEL_STYLE && itemDataList.size >= 3) || homeContent.style != LegacyHomeFragmentAdapterAssistant.GAME_COLLECTION_CAROUSEL_STYLE) {
if (!homeContent.style.contains("refresh")) {

View File

@ -1045,59 +1045,72 @@ class LegacyHomeFragmentAdapterAssistant(
}
}
private fun getGameCollectionExposureEventList(itemData: LegacyHomeItemData): ArrayList<ExposureEvent> {
private fun getHomeGameCollectionExposureEventList(
itemData: LegacyHomeItemData,
refreshCurrentPosition: Int = -1
): ArrayList<ExposureEvent> {
val exposureList = arrayListOf<ExposureEvent>()
runOnIoThread(true) {
itemData.gameCollection?.gameCollectionItemDataList?.forEachIndexed { index, gameCollectionItemData ->
val gameCollection = gameCollectionItemData.homeGameCollectionItem
val gameCollectionSource =
listOf(
ExposureSource("游戏单合集", itemData.gameCollection?.id ?: ""),
ExposureSource("游戏单", "${gameCollection?.title} + ${gameCollection?.id}")
)
val exposureEvent = ExposureEvent.createEventWithSourceConcat(
gameEntity = GameEntity().apply {
isAdData = gameCollection?.adIconActive ?: false
outerSequence = itemData.blockPosition
sequence = index
},
basicSource = mBasicExposureSources,
source = gameCollectionSource
)
gameCollection?.games?.forEach {
it.exposureEvent = ExposureEvent.createEventWithSourceConcat(
gameEntity = it.apply {
isAdData = gameCollection.adIconActive
outerSequence = itemData.blockPosition
sequence = index
},
basicSource = mBasicExposureSources,
source = gameCollectionSource
)
itemData.gameCollection?.gameCollectionItemDataList?.run {
val currentIndex = if (itemData.gameCollection?.style?.contains("refresh") == true) {
refreshCurrentPosition % size
} else -1
forEachIndexed { index, gameCollectionItemData ->
if (itemData.gameCollection?.style?.contains("refresh") == false || currentIndex == index) {
gameCollectionItemData.homeGameCollectionItem?.let {
val gameCollectionSource =
listOf(
ExposureSource("游戏单合集", itemData.gameCollection?.id ?: ""),
ExposureSource("游戏单", "${it.title} + ${it.id}")
)
val gameExposureList = arrayListOf<ExposureEvent>()
it.games?.forEach { game ->
game.isAdData = it.adIconActive
game.outerSequence = itemData.blockPosition
game.sequence = index
val exposureEvent = ExposureEvent.createEventWithSourceConcat(
gameEntity = game,
basicSource = mBasicExposureSources,
source = gameCollectionSource
)
game.exposureEvent = exposureEvent
gameExposureList.add(exposureEvent)
}
exposureList.addAll(gameExposureList)
gameCollectionItemData.exposureEvent = ExposureEvent.createEventWithSourceConcat(
gameEntity = GameEntity().apply {
adIconActive = it.adIconActive
outerSequence = itemData.blockPosition
sequence = index
},
basicSource = mBasicExposureSources,
source = gameCollectionSource
)
}
}
}
gameCollectionItemData.exposureEvent = exposureEvent
exposureList.add(exposureEvent)
}
}
return exposureList
}
private fun bindGameCollectionCarousel(holder: HomeGameCollectionCarouselViewHolder, item: LegacyHomeItemData) {
item.exposureEventList = getGameCollectionExposureEventList(item)
item.exposureEventList = getHomeGameCollectionExposureEventList(item)
item.gameCollection?.let { holder.bindGameCollectionList(it, "首页内容列表") }
}
private fun bindGameCollectionSlide(holder: HomeGameCollectionSlideViewHolder, item: LegacyHomeItemData) {
item.exposureEventList = getGameCollectionExposureEventList(item)
item.exposureEventList = getHomeGameCollectionExposureEventList(item)
item.gameCollection?.let { holder.bindGameCollectionSlide(it, "首页内容列表") }
}
private fun bindGameCollectionRefresh(holder: HomeGameCollectionRefreshViewHolder, item: LegacyHomeItemData) {
item.exposureEventList = getGameCollectionExposureEventList(item)
item.exposureEventList = getHomeGameCollectionExposureEventList(item, holder.currentPosition)
item.gameCollection?.let {
holder.bindGameCollectionRefresh(it, "首页内容列表") {
if (mAdapter is HomeFragmentAdapter) {
(mAdapter as HomeFragmentAdapter).viewModel.changeGameCollectionRefresh(it.id)
(mAdapter as HomeFragmentAdapter).viewModel.changeGameCollectionRefresh(it.id, true)
} else {
false
}

View File

@ -29,6 +29,7 @@ class HomeGameCollectionCarouselAdapter(
private val mBlockName: String = ""
) :
BaseRecyclerAdapter<HomeGameCollectionCarouselAdapter.HomeGameCollectionCardViewHolder>(context) {
private val mPosterWidth = DisplayUtils.getScreenWidth() - 50F.dip2px()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
HomeGameCollectionCardViewHolder(HomeGameCollectionCarouselItemCell(mContext).apply { inflate() })
@ -69,7 +70,7 @@ class HomeGameCollectionCarouselAdapter(
}
}
class HomeGameCollectionCardViewHolder(cell: HomeGameCollectionCarouselItemCell) :
inner class HomeGameCollectionCardViewHolder(val cell: HomeGameCollectionCarouselItemCell) :
BaseRecyclerViewHolder<Any>(cell) {
fun bindGameCollectionCard(
binding: HomeGameCollectionCardItemBinding,
@ -83,9 +84,9 @@ class HomeGameCollectionCarouselAdapter(
binding.run {
val context = root.context
val gamesCollectionEntity = itemData.homeGameCollectionItem
root.layoutParams.width = DisplayUtils.getScreenWidth() - 50F.dip2px()
root.layoutParams.width = mPosterWidth
if (gamesCollectionEntity != null) {
poster.setTag(ImageUtils.TAG_TARGET_WIDTH, DisplayUtils.getScreenWidth() - 50F.dip2px())
poster.setTag(ImageUtils.TAG_TARGET_WIDTH, mPosterWidth)
ImageUtils.display(poster, gamesCollectionEntity.cover)
ImageUtils.display(userIv, gamesCollectionEntity.user?.icon)
titleTv.text = gamesCollectionEntity.title

View File

@ -26,7 +26,7 @@ class HomeGameCollectionRefreshViewHolder(val binding: HomeGameCollectionRefresh
BaseRecyclerViewHolder<ViewHolder>(binding.root) {
private var mIsHorizontal = false
private var mSpanCount = 0
private var mCurrentPosition = 0
var currentPosition = 0
private var mSnapHelper: SpanCountPagerSnapHelper? = null
private var mGameCollectionList: List<GameCollectionListItemData>? = null
private var mGameCollectionItemData: GameCollectionListItemData? = null
@ -145,7 +145,7 @@ class HomeGameCollectionRefreshViewHolder(val binding: HomeGameCollectionRefresh
binding.refreshLottie.setOnClickListener {
if (!binding.refreshLottie.isAnimating) {
binding.refreshLottie.playAnimation()
mCurrentPosition++
currentPosition++
if (!refreshAction()) {
refreshGameCollection()
if (!mIsHorizontal) changeSpanCountIfNeeded()
@ -170,7 +170,7 @@ class HomeGameCollectionRefreshViewHolder(val binding: HomeGameCollectionRefresh
private fun refreshGameCollection() {
mGameCollectionList?.let {
mGameCollectionItemData = it.safelyGetInRelease(mCurrentPosition % it.size)
mGameCollectionItemData = it.safelyGetInRelease(currentPosition % it.size)
mGameCollection = mGameCollectionItemData?.homeGameCollectionItem
mGameList = mGameCollection?.games ?: listOf()
mSpanCount = if (mGameList.size < 3) mGameList.size else 3

View File

@ -85,7 +85,7 @@ class HomeGameCollectionSlideAdapter(
listOf(gameItem1, gameItem2, gameItem3).forEachIndexed { index, binding ->
binding.root.goneIf(games.size < index + 1) {
val gameEntity = games[index]
holder.updateGameItem(binding, gameEntity, gameCollectionItemData)
holder.updateGameItem(binding, gameEntity)
}
}
@ -158,7 +158,7 @@ class HomeGameCollectionSlideAdapter(
mContext,
gameEntity.id,
BaseActivity.mergeEntranceAndPath(mEntrance, "游戏单合集"),
gameCollectionItemData?.exposureEvent
gameEntity.exposureEvent
)
}
}
@ -289,9 +289,9 @@ class HomeGameCollectionSlideAdapter(
(itemView as HomeGameCollectionBigSlideCardCell).binding?.run {
when (position) {
0 -> updateGameItem(gameItem1, dataList[position], mGameCollectionListItemData)
1 -> updateGameItem(gameItem2, dataList[position], mGameCollectionListItemData)
2 -> updateGameItem(gameItem3, dataList[position], mGameCollectionListItemData)
0 -> updateGameItem(gameItem1, dataList[position])
1 -> updateGameItem(gameItem2, dataList[position])
2 -> updateGameItem(gameItem3, dataList[position])
}
}
}
@ -312,7 +312,7 @@ class HomeGameCollectionSlideAdapter(
listOf(gameItem1, gameItem2, gameItem3).forEachIndexed { index, binding ->
binding.root.goneIf(games.size < index + 1) {
val gameEntity = games[index]
updateGameItem(binding, gameEntity, mGameCollectionListItemData)
updateGameItem(binding, gameEntity)
}
}
}
@ -323,8 +323,7 @@ class HomeGameCollectionSlideAdapter(
fun updateGameItem(
binding: ItemHomeGameCollectionBigSlideCardGameBinding,
gameEntity: GameEntity,
itemData: GameCollectionListItemData? = null
gameEntity: GameEntity
) {
binding.root.visibility = View.VISIBLE
@ -340,7 +339,7 @@ class HomeGameCollectionSlideAdapter(
null,
mEntrance,
"游戏单合集",
itemData?.exposureEvent,
gameEntity.exposureEvent,
clickCallback = null,
refreshCallback = {
DownloadItemUtils.updateItem(
@ -381,7 +380,7 @@ class HomeGameCollectionSlideAdapter(
mContext,
gameEntity.id,
BaseActivity.mergeEntranceAndPath(mEntrance, "游戏单合集"),
itemData?.exposureEvent
gameEntity.exposureEvent
)
}
}

View File

@ -0,0 +1,48 @@
package com.gh.gamecenter.pkg
import android.content.Context
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.utils.toJsonIgnoredNull
import com.gh.gamecenter.core.provider.IPkgConfigProvider
import com.halo.assistant.HaloApp
@Route(path = RouteConsts.provider.pkgConfig, name = "PkgConfig暴露服务")
class PkgConfigProviderImpl: IPkgConfigProvider {
override fun getPkgConfig(): ArrayList<String> {
val configList = arrayListOf<String>()
val sdk = when (BuildConfig.FLAVOR) {
"tea" -> "头条"
"kuaishou" -> "快手"
"gdt" -> "广点通"
else -> "普通包"
} + " " + BuildConfig.SDK_VERSION + " (仅头条有效)"
val coreEvent = if (PkgHelper.getCoreEventGameCategory() == "online") {
"网游"
} else {
"普通"
}
configList.add(sdk)
if (BuildConfig.FLAVOR == "kuaishou") {
configList.add("appid: ${BuildConfig.SDK_APP_ID.ifEmpty { "81537" }}")
configList.add("appname: ${BuildConfig.SDK_APP_NAME.ifEmpty { "guanghuanzhushou_1"}}")
}
configList.add(HaloApp.getInstance().channel)
configList.add("${PkgHelper.getActivateRatio()}%")
configList.add(coreEvent)
configList.add(PkgHelper.getPkgConfigLink()?.toJsonIgnoredNull() ?: "")
return configList
}
override fun init(context: Context?) {
// do nothing
}
}

View File

@ -11,6 +11,7 @@ import com.gh.gamecenter.core.utils.SPUtils
import java.nio.charset.Charset
object PkgHelper {
private var mTempPkgConfigEntity : PkgConfigEntity.PkgLinkEntity? = null
private var mPkgConfigLink: PkgConfigEntity.PkgLinkEntity? = null
private const val SP_PKG_CONFIG_IS_USED = "pkg_config_is_used"
@ -25,7 +26,7 @@ object PkgHelper {
/**
* 获取激活比例
*/
fun getActivateRatio() : Int {
fun getActivateRatio(): Int {
return if (mActivateRatioFromInternet > 0) {
mActivateRatioFromInternet
} else {
@ -41,17 +42,18 @@ object PkgHelper {
}
fun getPkgConfig(isFromHomeTopTab: Boolean): PkgConfigEntity.PkgLinkEntity? {
if (mPkgConfigLink == null
&& !SPUtils.getBoolean(SP_PKG_CONFIG_IS_USED, false)
if (!SPUtils.getBoolean(SP_PKG_CONFIG_IS_USED, false)
&& BuildConfig.FIRST_LAUNCH.isNotEmpty()
) {
if (mPkgConfigLink == null) {
mPkgConfigLink =
String(Base64.decode(BuildConfig.FIRST_LAUNCH, Base64.DEFAULT), Charset.defaultCharset()).toObject()
}
mPkgConfigLink =
String(Base64.decode(BuildConfig.FIRST_LAUNCH, Base64.DEFAULT), Charset.defaultCharset()).toObject()
mTempPkgConfigEntity = mPkgConfigLink
return if (isFromHomeTopTab) {
if (mPkgConfigLink?.shouldStayAtHomePage != true && mPkgConfigLink?.homeBottomTab == "home") {
markConfigUsed()
if (mPkgConfigLink?.shouldStayAtHomePage == true && mPkgConfigLink?.homeBottomTab == "home") {
mPkgConfigLink
} else {
null
@ -61,6 +63,10 @@ object PkgHelper {
}
}
if (mPkgConfigLink != null) {
mTempPkgConfigEntity = mPkgConfigLink
}
return mPkgConfigLink
}
@ -70,7 +76,7 @@ object PkgHelper {
}
/**
* 获取特殊包配置
* 从接口获取特殊包配置
*/
fun requestPkgConfig(configId: String) {
if (SPUtils.getBoolean(SP_PKG_CONFIG_IS_USED, false)) return
@ -80,7 +86,10 @@ object PkgHelper {
mActivateRatioFromInternet = it.data?.activateRatio ?: 0
mCoreEventGameCategory = it.data?.coreEventGameCategory
}
}
fun getPkgConfigLink(): PkgConfigEntity.PkgLinkEntity? {
return mTempPkgConfigEntity
}
}

View File

@ -534,8 +534,7 @@ class SearchGameIndexAdapter(
if (key.contains(download.packageName) && key.contains(download.gameId)) {
val position = positionAndPackageMap[key]
if (position != null && mEntityList != null && position < mEntityList.size && mEntityList[position].game != null) {
mEntityList[position].game!!.getEntryMap()[download.platform] = download
notifyItemChanged(position)
DownloadItemUtils.processDate(mEntityList[position].game!!, download, this, position)
}
}
}

View File

@ -23,6 +23,8 @@ import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
class GameBigImageViewHolder(val binding: ItemGameServerTestBigImageBinding) :
BaseRecyclerViewHolder<Any>(binding.root) {
private val mGameImageWidth = DisplayUtils.getScreenWidth() - 32F.dip2px()
fun bindAttachGame(
holder: GameBigImageViewHolder,
gameEntity: GameEntity,
@ -32,7 +34,7 @@ class GameBigImageViewHolder(val binding: ItemGameServerTestBigImageBinding) :
) {
holder.bindGameInfo(gameEntity, adapter, exposureEvent, entrance)
holder.binding.gameImage.goneIf(gameEntity.topVideo != null || gameEntity.homeSetting.image.isEmpty()) {
binding.gameImage.setTag(ImageUtils.TAG_TARGET_WIDTH, DisplayUtils.getScreenWidth() - 32F.dip2px())
binding.gameImage.setTag(ImageUtils.TAG_TARGET_WIDTH, mGameImageWidth)
ImageUtils.display(binding.gameImage, gameEntity.homeSetting.image)
val hierarchy = binding.gameImage.hierarchy
try {

View File

@ -102,6 +102,7 @@ class GameServerTestV2ListFragment :
}
override fun initSkeletonScreen() {
if (mBinding?.skeleton == null) return
mSkeletonScreen = Skeleton.bind(mBinding?.skeleton)
.shimmer(true)
.angle(Constants.SHIMMER_ANGLE)

View File

@ -3,6 +3,7 @@ package com.gh.ndownload
import android.text.TextUtils
import androidx.annotation.WorkerThread
import com.gh.download.DownloadDataHelper
import com.gh.download.DownloadDataSimpleHelper
import com.gh.download.DownloadManager
import com.gh.gamecenter.common.utils.NetworkUtils
import com.gh.gamecenter.common.utils.addMetaExtra
@ -142,9 +143,7 @@ object NDownloadBridge : InnerDownloadListener, IErrorRetryHandler {
override fun onProgressWithoutThrottle(id: String?, progress: Float) {
if (id != null && (mStartUpTimeMap[id] ?: 0) > 0) {
val startupTime: Long = System.currentTimeMillis() - (mStartUpTimeMap[id] ?: 0)
getDownloadEntityFromSnapshot(id)?.let { downloadEntity ->
downloadEntity.meta.put(DownloadEntity.DOWNLOAD_STARTUP_TIME_KEY, startupTime.toString())
}
DownloadDataSimpleHelper.updateDownloadDataSimpleEntity(id, downloadStartUpTime = startupTime)
mStartUpTimeMap[id] = 0
}
}

View File

@ -150,7 +150,7 @@ object VArchiveHelper {
if (isSuccess) {
val vGameEntity = VHelper.getVGameSnapshot(packageName = packageName)
runOnIoThread {
val fileMd5 = MD5Utils.calculateMD5(mLatestArchiveFile)
val fileMd5 = MD5Utils.calculateMD5(mLatestArchiveFile) ?: return@runOnIoThread
val vArchiveEntity = VArchiveEntity(
id = fileMd5,
gameId = vGameEntity?.downloadEntity?.gameId ?: "",

View File

@ -157,6 +157,9 @@ object VHelper {
if (it.type == EBPackage.TYPE_INSTALLED) {
SensorsBridge.trackEvent("HaloFunInstallDone", "space_schema_type", if (isVSpace32) "32位" else "64位")
if (isVSpace32) {
SensorsBridge.trackEvent("HaloFunExpandInstallDone")
}
if (skip64VSpaceInstalled) return@PackageChangeListener
@ -956,11 +959,21 @@ object VHelper {
location: String? = null) {
Utils.log(LOG_TAG, "检测是需要安装还是启动 ${downloadEntity.gameId}")
if (downloadEntity.name.isNullOrEmpty()) {
SentryHelper.onEvent(
"V_GAME_DOWNLOAD_ENTITY_NAME_EMPTY",
"game_id",
downloadEntity.gameId,
"location",
location
)
}
installOrLaunch(
context,
downloadEntity.packageName,
downloadEntity.gameId,
downloadEntity.name,
downloadEntity.name ?: "",
downloadEntity.getGameCategory(),
downloadEntity.getMetaExtra(KEY_BIT),
location
@ -1340,7 +1353,6 @@ object VHelper {
VSpace32DialogFragment.showDownloadDialog(
context,
getVSpaceDownloadEntity(false),
autoDownload = true,
gameId = gameId,
gameName = gameName
)

View File

@ -46,6 +46,7 @@ class VSpace32DialogFragment : BaseDraggableDialogFragment() {
private val mBinding by lazy { DialogVspace32Binding.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) {
@ -146,6 +147,8 @@ class VSpace32DialogFragment : BaseDraggableDialogFragment() {
downloadType
).toJson()
mIsClickDownloadThisTime = true
AppExecutor.uiExecutor.executeWithDelay({
DownloadManager.getInstance().cancel(mDownloadUrl)
DownloadManager.getInstance().add(downloadEntity)
@ -165,7 +168,7 @@ class VSpace32DialogFragment : BaseDraggableDialogFragment() {
// 上面监听安装包名变化的 LiveData 监听有可能被冲掉了
// 手动再检查一下安装状态,避免出现已安装但是没有 dismiss 弹窗的问题
if (PackageUtils.isInstalled(requireContext(), VHelper.VSPACE_32BIT_PACKAGENAME)) {
if (PackageUtils.isInstalledFromAllPackage(requireContext(), VHelper.VSPACE_32BIT_PACKAGENAME)) {
dismissAllowingStateLoss()
}
}
@ -221,7 +224,7 @@ class VSpace32DialogFragment : BaseDraggableDialogFragment() {
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) {
if (!isVSpace32DownloadOnly && isAutoInstall && !mIsLogAutoInstallClick && mIsClickDownloadThisTime) {
NewFlatLogUtils.logHaloFunEvent("halo_fun_32_install_tip_dialog_click")
SensorsBridge.trackEvent("HaloFunExpandInstallButtonClick")
mIsLogAutoInstallClick = true
@ -260,15 +263,11 @@ class VSpace32DialogFragment : BaseDraggableDialogFragment() {
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 = ""
) {
@ -291,8 +290,6 @@ class VSpace32DialogFragment : BaseDraggableDialogFragment() {
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(
@ -301,24 +298,6 @@ class VSpace32DialogFragment : BaseDraggableDialogFragment() {
)
}
@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 ->

View File

@ -39,6 +39,13 @@ import com.lightgame.download.DownloadStatus.*
import com.lightgame.utils.AppManager
import java.io.File
/**
* 1. 单独的 64 位组件的下载和更新使用本 VSpaceDialogFragment
* 2. 已经安装了 64 位组件,后续操作所调起的 32 位组件的首次下载使用亦 VSpace32DialogFragment
* 3. 64 位组件已安装且 64 位组件无需更新时32 位组件需要更新时,使用本 VSpaceDialogFragment
* 4. 64 位组件已安装且 6432 位都需要更新时64 位更新使用本 VSpaceDialogFragment
* 同时下载64位组件和32位组件但是32位在64位安装完成之前不触发安装 32 位安装使用跳转 VSpaceUpdate32DialogFragment 进行
*/
class VSpaceDialogFragment : BaseDraggableDialogFragment() {
private var mAppEntity64: AppEntity? = null
@ -52,6 +59,7 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
private val mBinding by lazy { DialogVspaceBinding.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 (((mAppEntity64 != null && downloadEntity.url == mDownloadUrl64) || (mAppEntity64 == null && downloadEntity.url == mDownloadUrl32)) && isAdded) {
@ -92,13 +100,8 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
val mViewModel = viewModelProvider<VSpaceDialogViewModel>()
mViewModel.packageLiveData.observe(this) {
if (it.packageName == VHelper.DEFAULT_VSPACE_PACKAGENAME) {
if (mIsUpdate) showVSpace32UpdateDialogIfNeeded() else showVSpace32DownloadDialogIfNeeded()
dismissAllowingStateLoss()
}
if (it.packageName == VHelper.VSPACE_32BIT_PACKAGENAME) {
dismissAllowingStateLoss()
}
show32BitRelatedDialogIfNeeded()
dismissDialogIfInstalled()
}
mBinding.downloadBtn.text = "下载畅玩助手服务组件"
@ -157,6 +160,7 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
DataCollectionUtils.uploadDownload(HaloApp.getInstance(), downloadEntity32, "开始")
}
mIsClickDownloadThisTime = true
AppExecutor.uiExecutor.executeWithDelay({
if (downloadEntity64 != null) {
DownloadManager.getInstance().cancel(mDownloadUrl64)
@ -204,13 +208,42 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
super.onStart()
DownloadManager.getInstance().addObserver(mDataWatcher)
// 上面监听安装包名变化的 LiveData 监听有可能被冲掉了
// 手动再检查一下安装状态,避免出现已安装但是没有 dismiss 弹窗的问题
if (PackageUtils.isInstalled(requireContext(), VHelper.DEFAULT_VSPACE_PACKAGENAME)) {
if (mIsUpdate) showVSpace32UpdateDialogIfNeeded() else showVSpace32DownloadDialogIfNeeded()
dismissAllowingStateLoss()
show32BitRelatedDialogIfNeeded()
// 检查安装状态,避免出现已安装但是没有 dismiss 弹窗的问题
dismissDialogIfInstalled()
}
// 弹下载/更新 32 位组件,前提是 64 位组件已经安装并安装了指定的版本
private fun show32BitRelatedDialogIfNeeded() {
if (PackageUtils.isInstalledFromAllPackage(requireContext(), VHelper.DEFAULT_VSPACE_PACKAGENAME)
&& mAppEntity64?.version == PackageUtils.getVersionNameByPackageName(VHelper.DEFAULT_VSPACE_PACKAGENAME)) {
// 该游戏需要 32 位组件,且后台配置的 32 位组件不为空
if (mBit == "32" && mAppEntity32 != null && !mAppEntity32?.url.isNullOrEmpty()) {
if (mIsUpdate) {
showVSpace32UpdateDialog()
} else {
showVSpace32DownloadDialogIfNeeded()
}
}
}
if (PackageUtils.isInstalled(requireContext(), VHelper.VSPACE_32BIT_PACKAGENAME)) {
}
/**
* dismiss 当前 VSpaceDialogFragment (如果满足入参条件的话)
*/
private fun dismissDialogIfInstalled() {
// 需要下载的 64 位组件是否与已安装的 64 位组件版本一致
val is64BitVersionMatched =
mAppEntity64 == null
|| mAppEntity64?.version == PackageUtils.getVersionNameByPackageName(VHelper.DEFAULT_VSPACE_PACKAGENAME)
// 需要下载的 32 位组件是否与已安装的 32 位组件版本一致
val is32BitVersionMatched =
(mAppEntity32 == null || mBit != "32")
|| mAppEntity32?.version == PackageUtils.getVersionNameByPackageName(VHelper.VSPACE_32BIT_PACKAGENAME)
if (is64BitVersionMatched && is32BitVersionMatched) {
dismissAllowingStateLoss()
}
}
@ -218,7 +251,7 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
private fun showVSpace32DownloadDialogIfNeeded() {
val is32VSpaceInstalled =
PackageUtils.isInstalledFromAllPackage(requireContext(), VHelper.VSPACE_32BIT_PACKAGENAME)
if (!is32VSpaceInstalled && mBit == "32" && mAppEntity32 != null && !mAppEntity32?.url.isNullOrEmpty()) {
if (!is32VSpaceInstalled) {
VSpace32DialogFragment.showDownloadDialog(
requireContext(),
mAppEntity32!!,
@ -228,15 +261,13 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
}
}
private fun showVSpace32UpdateDialogIfNeeded() {
if (mBit == "32" && mAppEntity32 != null && !mAppEntity32?.url.isNullOrEmpty()) {
VSpaceUpdate32DialogFragment.showDownloadDialog(
requireContext(),
mAppEntity32!!,
gameId = mGameId,
gameName = mGameName
)
}
private fun showVSpace32UpdateDialog() {
VSpaceUpdate32DialogFragment.showDownloadDialog(
requireContext(),
mAppEntity32!!,
gameId = mGameId,
gameName = mGameName
)
}
override fun onStop() {
@ -277,6 +308,7 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
DownloadManager.getInstance().resume(downloadEntity, false)
}
}
done -> {
downloadBtn.setText(R.string.install)
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.INSTALL_NORMAL
@ -288,8 +320,14 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
mIsLogInstallShow = true
}
if (SPUtils.getBoolean(Constants.SP_AUTO_INSTALL, true) && !mIsLogAutoInstallClick) {
SensorsBridge.trackEvent("HaloFunInstallButtonClick", "space_schema_type", vSpaceType)
if (SPUtils.getBoolean(
Constants.SP_AUTO_INSTALL,
true
) && !mIsLogAutoInstallClick && mIsClickDownloadThisTime
) {
downloadBtn.postDelayed({
SensorsBridge.trackEvent("HaloFunInstallButtonClick", "space_schema_type", vSpaceType)
}, SENSORS_LOG_DELAY)
mIsLogAutoInstallClick = true
}
@ -316,6 +354,7 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
DownloadManager.getInstance().resume(downloadEntity, true)
}
}
else -> {
// do nothing
}
@ -328,6 +367,8 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
const val KEY_AUTO_DOWNLOAD = "auto_download"
const val KEY_IS_UPDATE = "is_update"
const val SENSORS_LOG_DELAY = 1000L
@JvmStatic
fun showDownloadDialog(
context: Context?,
@ -370,7 +411,6 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
)
}
val downloadDialog = VSpaceDialogFragment().apply {
arguments = Bundle().apply {
if (appEntity64 != null) putParcelable(KEY_APP_ENTITY_64, appEntity64)
@ -388,6 +428,14 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
)
}
/**
* 显示下载弹窗
* @param appEntity64 需要下载的 64 位组件实体,不为空即代表需要下载
* @param appEntity32 需要下载的 32 位组件实体,不为空即代表需要下载
* @param gameEntity 游戏相关的实体
* @param autoDownload 是否需要显示弹窗即进行下载
* @param isUpdate 是否为更新
*/
@JvmStatic
fun showDownloadDialog(
context: Context?,

View File

@ -141,7 +141,8 @@ class VSpaceUpdate32DialogFragment : BaseDialogFragment() {
// 上面监听安装包名变化的 LiveData 监听有可能被冲掉了
// 手动再检查一下安装状态,避免出现已安装但是没有 dismiss 弹窗的问题
if (PackageUtils.isInstalled(requireContext(), VHelper.VSPACE_32BIT_PACKAGENAME)) {
if (PackageUtils.isInstalledFromAllPackage(requireContext(), VHelper.VSPACE_32BIT_PACKAGENAME)
&& mAppEntity?.version == PackageUtils.getVersionNameByPackageName(VHelper.VSPACE_32BIT_PACKAGENAME)) {
dismissAllowingStateLoss()
}
}

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Matrix
import android.view.WindowManager
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
@ -15,6 +16,7 @@ import com.gh.gamecenter.common.exposure.meta.MetaUtil
import com.gh.gamecenter.common.utils.ImageUtils
import com.gh.gamecenter.common.utils.PermissionHelper
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
@ -38,7 +40,11 @@ class ShortcutManager private constructor() {
object : ShortcutAction() {
override fun showPermissionDialog(context: Context, check: Int, executor: Executor) {
runOnUiThread {
mResult?.showPermissionDialog(executor)
try {
mResult?.showPermissionDialog(executor)
} catch (e: WindowManager.BadTokenException) {
ToastUtils.toast("创建快捷方式失败,请稍后再试")
}
}
}
@ -52,7 +58,11 @@ class ShortcutManager private constructor() {
} else {
//创建失败估计还是权限问题,直接弹出跳转权限设置
runOnUiThread {
mResult?.showPermissionDialog(executor)
try {
mResult?.showPermissionDialog(executor)
} catch (e: WindowManager.BadTokenException) {
ToastUtils.toast("创建快捷方式失败,请稍后再试")
}
}
}
}

View File

@ -227,12 +227,12 @@ public class HaloApp extends MultiDexApplication {
PlayerFactory.setPlayManager(Exo2PlayerManager.class);
CacheFactory.setCacheManager(ExoPlayerCacheManager.class);
initFresco();
AppExecutor.getIoExecutor().execute(() -> {
initDataHelper();
ExtensionsKt.doOnMainProcessOnly(this, () -> Tracker.init(this));
initFresco();
deviceRamSize = DeviceUtils.getTotalRamSizeOfDevice(this);
mChannel = mFlavorProvider.getChannelStr(this);

View File

@ -474,4 +474,8 @@
<string name="article_detail_top_category_dialog_title">请选择置顶类型</string>
<string name="article_detail_top_success_toast">置顶成功</string>
<string name="unsupported_browser_install_hint">此游戏不支持浏览器安装,已切换为助手安装</string>
<string name="update_all_has_land_page_address_dialog_title">提示</string>
<string name="update_all_has_land_page_address_dialog_content">部分游戏下载资源由第三方提供,此类游戏无法自动更新,请手动点击游戏【更新】按钮前往第三方网址更新游戏</string>
<string name="update_all_has_land_page_address_dialog_confirm">我知道了</string>
<string name="miui_open_adb_hint">请查看关闭教程,先开启开发者模式</string>
</resources>

View File

@ -7,9 +7,11 @@ import android.text.TextUtils
import com.gh.gamecenter.BuildConfig
import com.bytedance.hume.readapk.HumeSDK
import com.gh.gamecenter.TeaHelper
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.provider.IFlavorProvider
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.TimeUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import java.io.File
@ -58,6 +60,11 @@ class FlavorProviderImp : IFlavorProvider {
override fun logCoreEvent() {
logEvent("game_addiction")
if (BuildConfig.ACTIVATE_REPORTING_RATIO == 1) {
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast("关键行为 game_addiction")
}, 500)
}
}
private fun amILucky(percentage: Int = 100): Boolean {

View File

@ -84,6 +84,10 @@ class AppProviderImpl : IAppProvider {
}
}
override fun getFlavor(): String {
return "internal"
}
override fun getIsBrandNewInstall(): Boolean {
return true
}

View File

@ -80,6 +80,10 @@ class AppProviderImpl : IAppProvider {
}
}
override fun getFlavor(): String {
return "internal"
}
override fun isUserAcceptPrivacyPolicy(context: Context): Boolean {
return true
}

View File

@ -80,6 +80,10 @@ class AppProviderImpl : IAppProvider {
}
}
override fun getFlavor(): String {
return "internal"
}
override fun isUserAcceptPrivacyPolicy(context: Context): Boolean {
return true
}

View File

@ -2,6 +2,7 @@ package com.gh.gamecenter.xapk.io
import android.content.Context
import android.content.pm.PackageInstaller
import android.content.pm.PackageInstaller.Session
import android.content.pm.PackageInstaller.SessionParams
import android.content.pm.PackageManager
import android.os.Build
@ -35,9 +36,6 @@ class SplitApksOutput(
.packageInstaller
// 创建安装会话并获取返回会话ID
val sessionId = installer.createSession(it)
.also { sessionId ->
SessionPool.put(installer, sessionId)
}
// 开启安装会话
val session = installer.openSession(sessionId)
try {
@ -59,24 +57,4 @@ class SplitApksOutput(
} else {
throw ApkOutputUnsupportedSplitApksException()
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private object SessionPool {
private val sessionIdList = mutableListOf<Int>()
fun put(installer: PackageInstaller, sessionId: Int) {
sessionIdList.removeAll {
installer.getSessionInfo(it) == null
}
sessionIdList.add(sessionId)
installer.mySessions.forEach {
if (!sessionIdList.contains(it.sessionId)) {
installer.abandonSession(it.sessionId)
}
}
}
}
}

65
init.internal.gradle Normal file
View File

@ -0,0 +1,65 @@
allprojects { project ->
buildscript {
ext.booster_version = '4.9.0'
ext.plugin_version = "0.3.0"
repositories {
mavenLocal()
google()
mavenCentral()
jcenter()
maven { url 'https://oss.sonatype.org/content/repositories/public' }
maven { url "https://artifact.bytedance.com/repository/byteX/" }
maven { url 'https://maven.aliyun.com/repository/public' }
}
dependencies {
// byteX
classpath "com.bytedance.android.byteX:base-plugin:${plugin_version}"
classpath "com.bytedance.android.byteX:const-inline-plugin:${plugin_version}"
classpath "com.bytedance.android.byteX:method-call-opt-plugin:${plugin_version}"
classpath "com.bytedance.android.byteX:field-assign-opt-plugin:${plugin_version}"
// booster
classpath "com.didiglobal.booster:booster-gradle-plugin:$booster_version"
classpath "com.didiglobal.booster:booster-transform-shared-preferences:$booster_version"
classpath "com.didiglobal.booster:booster-transform-r-inline:$booster_version"
classpath "com.didiglobal.booster:booster-transform-finalizer-watchdog-daemon:$booster_version"
classpath "com.didiglobal.booster:booster-transform-res-check:$booster_version"
classpath "com.didiglobal.booster:booster-transform-activity-thread:$booster_version"
}
}
repositories {
mavenLocal()
google()
mavenCentral()
jcenter()
maven { url 'https://oss.sonatype.org/content/repositories/public' }
maven { url "https://artifact.bytedance.com/repository/byteX/" }
maven { url 'https://maven.aliyun.com/repository/public' }
}
project.afterEvaluate {
// apply plugin only with this init script
if (project.name == "app") {
project.apply plugin: 'com.didiglobal.booster'
project.apply plugin: "com.gh.gamecenter.plugin"
project.apply plugin: 'bytex'
project.apply plugin: 'bytex.field_assign_opt' //去除重复的赋值 https://github.com/bytedance/ByteX/blob/master/field-assign-opt-plugin/README-zh.md
project.field_assign_opt {
enable false
enableInDebug false
logLevel "INFO"
removeLineNumber true // 同时移除赋值对应的行号信息(如果有的话),默认true。
whiteList = [
//白名单ClassName.FieldName 。不支持模式匹配
//"android.support.constraint.solver.ArrayRow.isSimpleDefinition"
]
}
}
}
}

View File

@ -75,6 +75,7 @@ object RouteConsts {
const val vpn = "/vpn/vpn"
const val pkg = "/pkg/pkg"
const val pkgConfig = "/pkgConfig/pkgConfig"
const val floatingwindow = "/floatingwindow/floatingwindow"
const val exposureManager = "/exposure/exposureManager"

View File

@ -4,15 +4,24 @@ import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Typeface
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.text.Html
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.style.StyleSpan
import android.view.*
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.gamecenter.common.R
import com.gh.gamecenter.common.base.TrackableDialog
import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.constant.Config
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.databinding.DialogAlertDefaultBinding
import com.gh.gamecenter.common.databinding.DialogGuideBinding
@ -45,7 +54,7 @@ object DialogHelper {
confirmClickCallback: (() -> Unit)? = null,
cancelClickCallback: (() -> Unit)? = null,
extraConfig: Config? = null,
uiModificationCallback: ((binding: DialogAlertDefaultBinding) -> Unit)? = null,
uiModificationCallback: ((binding: DefaultDialogAlertDefaultBindingWrapper) -> Unit)? = null,
trackMtaEvent: Boolean = false,
mtaEvent: String = "",
mtaKey: String = ""
@ -112,7 +121,7 @@ object DialogHelper {
dialog.dismiss()
}
uiModificationCallback?.invoke(binding)
uiModificationCallback?.invoke(DefaultDialogAlertDefaultBindingWrapper(dialog, binding))
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setContentView(contentView)
@ -622,18 +631,6 @@ object DialogHelper {
)
}
/**
* @param context may be is application context
* @return activity context
*/
fun checkDialogContext(context: Context?): Context? {
if (context == null) {
throw NullPointerException("dialog context is null")
}
return context as? Activity ?: AppManager.getInstance().currentActivity()
// currentActivity 是否存在 isDestroyed 的情况?
}
@JvmStatic
fun showUnsupportedFeatureDialog(context: Context) {
@ -655,6 +652,51 @@ object DialogHelper {
)
}
fun showMiuiOptimizationWarning(
context: Context,
onHintClick: () -> Unit,
onConfirmClick: (DefaultDialogAlertDefaultBindingWrapper) -> Unit,
) {
showDialog(
context = context,
title = context.getString(R.string.miui_optimization_warning_dialog_title),
content = SpannableStringBuilder(
context.getString(R.string.miui_optimization_warning_dialog_content)
).apply {
setSpan(StyleSpan(Typeface.BOLD), 10, 15, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
},
confirmText = context.getString(R.string.miui_optimizaition_warning_dialog_confirm),
cancelText = context.getString(R.string.miui_optimizaition_warning_dialog_cancel),
extraConfig = Config(),
uiModificationCallback = { binding ->
binding.hintTv.text = context.getString(R.string.miui_optimizaition_warning_dialog_hint)
binding.hintTv.visibility = View.VISIBLE
binding.hintTv.paint.flags = Paint.UNDERLINE_TEXT_FLAG
binding.hintTv.paint.isAntiAlias = true
binding.hintTv.setTextColor(ContextCompat.getColor(context, R.color.theme_font))
binding.hintTv.setOnClickListener {
onHintClick.invoke()
}
binding.confirmTv.setOnClickListener {
onConfirmClick.invoke(binding)
}
}
)
}
/**
* @param context may be is application context
* @return activity context
*/
fun checkDialogContext(context: Context?): Context? {
if (context == null) {
throw NullPointerException("dialog context is null")
}
return context as? Activity ?: AppManager.getInstance().currentActivity()
// currentActivity 是否存在 isDestroyed 的情况?
}
class Config(
val hint: String = "",
val showCloseIcon: Boolean = false,
@ -665,4 +707,23 @@ object DialogHelper {
val titleIcon: Int = -1
)
/**
* 通用Alert弹窗包装类可通过该类代理一些Dialog相关的方法
*/
class DefaultDialogAlertDefaultBindingWrapper(
private val dialog: Dialog,
private val binding: DialogAlertDefaultBinding
) {
val root: View = binding.root
val titleTv: TextView get() = binding.titleTv
val contentTv: TextView get() = binding.contentTv
val hintTv: TextView get() = binding.hintTv
val centerDivider: View get() = binding.centerDivider
val closeContainer: RelativeLayout get() = binding.closeContainer
val cancelTv: TextView get() = binding.cancelTv
val confirmTv: TextView get() = binding.confirmTv
val lineView: View get() = binding.lineView
fun dismiss() = dialog.dismiss()
}
}

View File

@ -402,6 +402,10 @@ inline fun <reified T : Any> T.toJson(): String {
return GsonUtils.toJson(this)
}
inline fun <reified T : Any> T.toJsonIgnoredNull(): String {
return GsonUtils.toJsonIgnoreNull(this)
}
fun String.insert(index: Int, string: String): String {
return this.substring(0, index) + string + this.substring(index, this.length)
}

View File

@ -0,0 +1,92 @@
package com.gh.gamecenter.common.utils;
import android.annotation.SuppressLint;
import android.os.Build;
import android.text.TextUtils;
import java.util.Objects;
public class MiuiUtils {
public static boolean isMiui() {
return !TextUtils.isEmpty(SystemUtils.getSystemProperty("ro.miui.ui.version.name"));
}
public static String getMiuiVersionName() {
String versionName = SystemUtils.getSystemProperty("ro.miui.ui.version.name");
return !TextUtils.isEmpty(versionName) ? versionName : "???";
}
public static int getMiuiVersionCode() {
try {
return Integer.parseInt(Objects.requireNonNull(SystemUtils.getSystemProperty("ro.miui.ui.version.code")));
} catch (Exception e) {
return -1;
}
}
public static String getActualMiuiVersion() {
return Build.VERSION.INCREMENTAL;
}
private static int[] parseVersionIntoParts(String version) {
try {
String[] versionParts = version.split("\\.");
int[] intVersionParts = new int[versionParts.length];
for (int i = 0; i < versionParts.length; i++)
intVersionParts[i] = Integer.parseInt(versionParts[i]);
return intVersionParts;
} catch (Exception e) {
return new int[]{-1};
}
}
/**
* @return 0 if versions are equal, values less than 0 if ver1 is lower than ver2, value more than 0 if ver1 is higher than ver2
*/
private static int compareVersions(String version1, String version2) {
if (version1.equals(version2))
return 0;
int[] version1Parts = parseVersionIntoParts(version1);
int[] version2Parts = parseVersionIntoParts(version2);
for (int i = 0; i < version2Parts.length; i++) {
if (i >= version1Parts.length)
return -1;
if (version1Parts[i] < version2Parts[i])
return -1;
if (version1Parts[i] > version2Parts[i])
return 1;
}
return 1;
}
public static boolean isActualMiuiVersionAtLeast(String targetVer) {
return compareVersions(getActualMiuiVersion(), targetVer) >= 0;
}
@SuppressLint("PrivateApi")
public static boolean isMiuiOptimizationDisabled() {
final String miuiOptimization = SystemUtils.getSystemProperty("persist.sys.miui_optimization");
if ("0".equals(miuiOptimization) || "false".equals(miuiOptimization))
return true;
try {
return (boolean) Class.forName("android.miui.AppOpsUtils")
.getDeclaredMethod("isXOptMode")
.invoke(null);
} catch (Exception e) {
return false;
}
}
public static boolean isFixedMiui() {
return isActualMiuiVersionAtLeast("20.2.20") || isMiuiOptimizationDisabled();
}
}

View File

@ -0,0 +1,33 @@
package com.gh.gamecenter.common.utils
import android.annotation.SuppressLint
import android.content.Context
import android.os.Build
import android.provider.Settings
object SystemUtils {
@SuppressLint("PrivateApi")
@JvmStatic
fun getSystemProperty(key: String?): String? {
return try {
Class.forName("android.os.SystemProperties")
.getDeclaredMethod("get", String::class.java)
.invoke(null, key) as String
} catch (e: Exception) {
null
}
}
/**
* 是否开启开发者选项
* @param context 上下文
*/
@JvmStatic
fun isDevelopmentSettingsEnabled(context: Context): Boolean = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Settings.Global.getInt(context.contentResolver, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED) > 0
} else {
Settings.Secure.getInt(context.contentResolver, Settings.Secure.DEVELOPMENT_SETTINGS_ENABLED) > 0
}
}

View File

@ -74,4 +74,9 @@
<string name="unsupported_feature_dialog_hint">当前版本不支持该功能,\n建议您升级到最新版本体验哦</string>
<string name="unsupported_feature_dialog_confirm_text">体验升级</string>
<string name="unspported_feature_dialog_cancel_text">取消</string>
<string name="miui_optimization_warning_dialog_title">温馨提示</string>
<string name="miui_optimization_warning_dialog_content">安装该游戏需要关闭MIUI优化否则将无法解压安装\n注意MIUI优化关闭后可能会导致手机系统不稳定以及无法使用MIUI提供的服务。你可以在游戏安装完成后重新开启</string>
<string name="miui_optimizaition_warning_dialog_confirm">立即关闭</string>
<string name="miui_optimizaition_warning_dialog_cancel">以后再说</string>
<string name="miui_optimizaition_warning_dialog_hint"><![CDATA[查看MIUI优化关闭教程>]]></string>
</resources>

View File

@ -32,5 +32,7 @@ interface IAppProvider : IProvider {
fun getFlavorProvider(): IFlavorProvider
fun getFlavor(): String
fun getIsBrandNewInstall(): Boolean
}

View File

@ -0,0 +1,9 @@
package com.gh.gamecenter.core.provider
import com.alibaba.android.arouter.facade.template.IProvider
interface IPkgConfigProvider : IProvider {
fun getPkgConfig(): ArrayList<String>
}

View File

@ -127,4 +127,14 @@ object SPUtils {
editor.remove(key)
editor.apply()
}
/**
* 使用传入的 SP 来移除 KV
*/
@JvmStatic
fun remove(sharedPreferences: SharedPreferences, key: String) {
val editor = sharedPreferences.edit()
editor.remove(key)
editor.apply()
}
}

View File

@ -84,6 +84,10 @@ class AppProviderImpl : IAppProvider {
}
}
override fun getFlavor(): String {
return "internal"
}
override fun getIsBrandNewInstall(): Boolean {
return false
}

View File

@ -15,7 +15,6 @@ import androidx.core.content.ContextCompat
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.gamecenter.common.base.fragment.ToolbarFragment
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.provider.*
@ -84,8 +83,26 @@ class AboutFragment : ToolbarFragment() {
}
false
}
}
val appProvider = ARouter.getInstance().build(RouteConsts.provider.app).navigation() as? IAppProvider
if (appProvider?.getFlavor() != "publish") {
val pkgConfigProvider = ARouter.getInstance().build(RouteConsts.provider.pkgConfig).navigation() as? IPkgConfigProvider
var clickCount = 0
mBinding.appNameTv.setOnClickListener {
clickCount = clickCount + 1
if (clickCount % 5 == 0) {
val configList = pkgConfigProvider?.getPkgConfig()
var configString = ""
configList?.forEach {
if (it.isNotEmpty()) {
configString = "$configString$it\n"
}
}
toastLong(configString)
}
}
}
}
@SuppressLint("SetTextI18n")
private fun initView() {

View File

@ -72,6 +72,9 @@ class AppProviderImpl : IAppProvider {
}
}
override fun getFlavor(): String {
return "internal"
}
override fun isUserAcceptPrivacyPolicy(context: Context): Boolean {
return true

View File

@ -7,7 +7,7 @@ versionCode=$(awk -v FS="versionCode = " 'NF>1{print $2}' dependencies.gradle |
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
post_init_script=init.gradle
post_init_script=init.internal.gradle
git checkout module_common/build.gradle
git checkout gradle.properties
@ -26,7 +26,6 @@ git log --pretty=format:'%s' --max-count=20 --no-merges > app/src/main/assets/gi
while getopts "c" arg
do
sed -i '260 a implementation(project(\x27:module_setting_compose\x27)) { exclude group: \x27androidx.swiperefreshlayout\x27 }' app/build.gradle
post_init_script=init.gradle
done
./gradlew rIR -I ${post_init_script}

View File

@ -78,12 +78,12 @@ fi
# 保存快手 app_id
if [ "${app_id}" != "" ]; then
sed -i "s/String KUAI_SHOU_APP_ID = \"\"/String KUAI_SHOU_APP_ID = \"${app_id}\"/g" app/build.gradle
sed -i "s/String SDK_APP_ID = \"\"/String SDK_APP_ID = \"${app_id}\"/g" app/build.gradle
fi
# 保存快手 app_name
if [ "${app_name}" != "" ]; then
sed -i "s/String KUAI_SHOU_APP_NAME = \"\"/String KUAI_SHOU_APP_NAME = \"${app_name}\"/g" app/build.gradle
sed -i "s/String SDK_APP_NAME = \"\"/String SDK_APP_NAME = \"${app_name}\"/g" app/build.gradle
fi
# 保存推广时上报关键行为事件的游戏类型
@ -93,14 +93,16 @@ fi
# 是否选择了 sdk 类型
if [ "${sdk_platform}" != "" ]; then
if [ "${activate_reporting_ratio}" == "" ]; then
activate_reporting_ratio="100"
fi
# 调整上报比例
sed -i "s/int ACTIVATE_REPORTING_RATIO = 100/int ACTIVATE_REPORTING_RATIO = ${activate_reporting_ratio}/g" app/build.gradle
sed -i "s/String SDK_VERSION = \"\"/String SDK_VERSION = \"${sdk_version}\"/g" app/build.gradle
# 头条包
if [ "${sdk_platform}" == "toutiao" ]; then
if [ "${activate_reporting_ratio}" == "" ]; then
activate_reporting_ratio="100"
fi
# 调整上报比例
sed -i "s/int ACTIVATE_REPORTING_RATIO = 100/int ACTIVATE_REPORTING_RATIO = ${activate_reporting_ratio}/g" app/build.gradle
if [ "${sdk_version}" == "5.3.0" ]; then
sed -i "s/bytedanceApplog = \"6.14.3\"/bytedanceApplog = \"${sdk_version}\"/g" dependencies.gradle
rm app/src/tea/java/com/gh/gamecenter/TeaHelper.kt