diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index a0740cf999..063581b94f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,12 +1,57 @@
stages:
- - analysis
- - sendmail
+ - android-build && analysis
+ - docker-build && sendmail
+ - deploy-trigger
-## 代码检查
+android_build:
+ tags:
+ - offline-test
+ stage: android-build && analysis
+ image: hub.shanqu.cc/devops/ci-android:jdk11
+ variables:
+ KUBERNETES_CPU_LIMIT: "16"
+ GIT_SUBMODULE_STRATEGY: recursive
+ Apk_Path: "app/build/outputs/apk/**/release/*.apk"
+ script:
+ - export GRADLE_USER_HOME=./.gradle
+ - chmod +x ./gradlew
+ - ./scripts/meta_build.sh --config_id 6400549c21c2c94ead074500 --sdk_platform toutiao --sdk_version 5.3.0 --channel BD-GHZS-ZP-KY --activate_reporting_ratio 60 --first_lanuch_jump e1wibGlua190eXBlXCI6XCJcIixcImxpbmtfaWRcIjpcIlwiLFwibGlua190ZXh0XCI6XCJcIixcImhvbWVfaW5kZXhcIjpcIlwiLFwiYm90dG9tX2luZGV4XCI6XCJcIn0= --unix_timestamp 1677657618 --output ./release/com.gh.gamecenter_5.17.4_694_BD-GHZS-ZP-KY_toutiao_5.3.0_1677657618.apk
+ - rm -rf ./.gradle/caches/build-cache-1
+ cache:
+ paths:
+ - .gradle
+ artifacts:
+ paths:
+ - Dockerfile
+ expire_in: 15 mins
+ only:
+ - feature-meta_build
+
+# 构建推送docker镜像
+docker-build:
+ tags:
+ - offline-test
+ stage: docker-build && sendmail
+ image: hub.shanqu.cc/library/docker:latest
+ variables:
+ GIT_STRATEGY: none
+ script:
+ - projectPath=`echo $CI_PROJECT_PATH | sed 's#/#-#g'`
+ - docker build -t registry.cn-shenzhen.aliyuncs.com/ghzs/$projectPath:latest .
+ - docker push registry.cn-shenzhen.aliyuncs.com/ghzs/$projectPath:latest
+ - docker run -e PROJECTKEY=$projectPath -e EMAIL=$GITLAB_USER_EMAIL -e BRANCH=$CI_COMMIT_REF_NAME --name send-email --rm hub.shanqu.cc/platform/send-sonar-report:latest
+ cache:
+ paths:
+ - .gradle
+ policy: pull
+ only:
+ - feature-meta_build
+
+# 代码检查
sonarqube_analysis:
tags:
- offline-test
- stage: analysis
+ stage: android-build && analysis
image: sonarsource/sonar-scanner-cli:latest
dependencies: [] #禁止传递来的artifact
script:
@@ -27,17 +72,12 @@ sonarqube_analysis:
-Dsonar.gitlab.merge_request_discussion=true
-Dsonar.java.binaries=. # 如果不使用Maven或Gradle进行分析,则必须手动提供测试二进制文件
only:
- - dev
-
-## 发送简易检测结果报告
-send_sonar_report:
- tags:
- - offline-test
- stage: sendmail
- image: hub.shanqu.cc/library/docker:latest
- dependencies: [] #禁止传递来的artifact
- script:
- - group=`echo $CI_PROJECT_PATH | sed 's#/#-#g'`
- - docker run -e PROJECTKEY=$group -e EMAIL=$GITLAB_USER_EMAIL --name send-email --rm hub.shanqu.cc/platform/send-sonar-report:latest
- only:
- - dev
+ - feature-meta_build
+
+## 触发多项目构建
+trigger_job:
+ stage: deploy-trigger
+ trigger:
+ project: devops/automation/build-eci
+ branch: dev
+
diff --git a/.gitmodules b/.gitmodules
index b5e90c44ba..7cbef87053 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,13 +1,13 @@
[submodule "libraries/LGLibrary"]
path = libraries/LGLibrary
- url = git@git.shanqu.cc:android/common-library.git
+ url = ../../../android/common-library.git
branch = master
[submodule "vspace-bridge"]
path = vspace-bridge
- url = git@git.shanqu.cc:cwzs/android/vspace-bridge.git
+ url = ../../../cwzs/android/vspace-bridge.git
[submodule "module_common/src/debug/assets/assistant-android-mock"]
path = module_common/src/debug/assets/assistant-android-mock
- url = git@git.shanqu.cc:halo/android/assistant-android-mock.git
+ url = ../../../halo/android/assistant-android-mock.git
[submodule "ndownload"]
path = ndownload
- url = git@git.shanqu.cc:android/ndownload.git
+ url = ../../../android/ndownload.git
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000..ab194bd3e4
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,15 @@
+FROM openjdk:11-jdk
+WORKDIR /project
+SHELL ["/bin/bash", "-c"]
+#配置SDK环境变量
+ENV ANDROID_SDK_ROOT /usr/lib/sdk
+ENV ANDROID_HOME /usr/lib/sdk
+ENV PATH $ANDROID_SDK_ROOT:$PATH
+ENV PATH=$PATH:${ANDROID_HOME}/cmdline-tools/cmdline-tools/bin/
+ENV GRADLE_USER_HOME /project/.gradle
+RUN source ~/.bashrc
+RUN sed -i "s@http://\(deb\|security\).debian.org@https://mirrors.aliyun.com@g" /etc/apt/sources.list \
+ && apt-get --quiet update --yes \
+ && apt-get --quiet install --yes lib32stdc++6 lib32z1 libncurses5 util-linux bash tzdata librdkafka-dev pkgconf \
+ && rm -rf /var/lib/apt/lists/*
+COPY .gradle /project/.gradle
diff --git a/app/build.gradle b/app/build.gradle
index 04d87bc677..fa225b1a1a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -9,6 +9,9 @@ import groovy.xml.XmlUtil
android {
+ String CONFIG_ID = ""
+ String FIRST_LAUNCH = ""
+
buildFeatures {
viewBinding true
dataBinding true
@@ -67,9 +70,13 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt'
- /**
- * All third-party appid/appkey
- */
+ // 推广用的配置 id
+ buildConfigField "String", "CONFIG_ID", "\"${CONFIG_ID}\""
+
+ // 首次启动的跳转配置
+ buildConfigField "String", "FIRST_LAUNCH", "\"${FIRST_LAUNCH}\""
+
+ // All third-party appid/appkey
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
buildConfigField "String", "NEW_API_HOST", "\"${NEW_API_HOST}\""
buildConfigField "String", "VAPI_HOST", "\"${VAPI_HOST}\""
@@ -270,6 +277,7 @@ dependencies {
implementation "com.llew.huawei:verifier:${verifier}"
teaImplementation "com.bytedance.applog:RangersAppLog-Lite-cn:${bytedanceApplog}"
+ teaImplementation "com.bytedance.applog:RangersAppLog-All-convert:${bytedanceApplog}"
implementation "net.lingala.zip4j:zip4j:${zip4j}"
@@ -314,6 +322,7 @@ dependencies {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(':module_vpn'))
+ implementation(project(':module_pkg'))
// 默认不接入光能模块,提高编译速度
// debugImplementation(project(':module_energy')) {
// exclude group: 'androidx.swiperefreshlayout'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2dba2904cb..30a5d90bdf 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -119,6 +119,8 @@
android:name="io.sentry.breadcrumbs.system-events"
android:value="false" />
+
+
() {
- @Override
- public void onSuccess(VSetting data) {
- mVSetting = data;
- SPUtils.setString(Constants.SP_V_SETTINGS, GsonUtils.toJson(data));
- }
- });
- }
+ RetrofitManager.getInstance()
+ .getVApi().getSettings(BuildConfig.VERSION_NAME)
+ .subscribeOn(Schedulers.io())
+ .subscribe(new BiResponse() {
+ @Override
+ public void onSuccess(VSetting data) {
+ mVSetting = data;
+ SPUtils.setString(Constants.SP_V_SETTINGS, GsonUtils.toJson(data));
+ }
+ });
RetrofitManager.getInstance()
.getApi().getGameGuidePopup(Build.MANUFACTURER, Build.VERSION.RELEASE, Build.MODEL, channel, BuildConfig.VERSION_NAME)
diff --git a/app/src/main/java/com/gh/common/databind/BindingAdapters.java b/app/src/main/java/com/gh/common/databind/BindingAdapters.java
index d4963820d2..ccd71d880e 100644
--- a/app/src/main/java/com/gh/common/databind/BindingAdapters.java
+++ b/app/src/main/java/com/gh/common/databind/BindingAdapters.java
@@ -593,6 +593,7 @@ public class BindingAdapters {
case pause:
case timeout:
case neterror:
+ case diskisfull:
case waiting:
progressBar.setText(R.string.downloading);
if (downloadEntity.isPluggable() && PackagesManager.isInstalled(downloadEntity.getPackageName())) {
diff --git a/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt b/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt
index c3405a577d..8ee6a87fa1 100644
--- a/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt
+++ b/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt
@@ -22,8 +22,12 @@ import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.feature.entity.ApkEntity
import com.gh.gamecenter.feature.entity.SimulatorEntity
import com.gh.gamecenter.entity.TrackableEntity
+import com.gh.ndownload.NDataChanger
import com.halo.assistant.HaloApp
-import com.lightgame.download.*
+import com.lightgame.download.DataWatcher
+import com.lightgame.download.DownloadEntity
+import com.lightgame.download.DownloadStatus
+import com.lightgame.download.FileUtils
import com.lightgame.utils.Utils
import java.lang.ref.WeakReference
import java.text.DecimalFormat
@@ -95,6 +99,9 @@ class SimulatorDownloadManager private constructor() {
downloadDialog?.dismiss()
}
}
+ DownloadStatus.diskisfull == downloadEntity.status -> {
+ ToastUtils.showToast("存储空间已满,下载任务已暂停")
+ }
DownloadStatus.neterror == downloadEntity.status -> {
ToastUtils.showToast("网络不稳定,下载任务已暂停")
}
@@ -290,13 +297,16 @@ class SimulatorDownloadManager private constructor() {
HaloApp.put(simulator.name, simulator)
if (entity != null) {
when (entity.status) {
- DownloadStatus.pause, DownloadStatus.subscribe,
- DownloadStatus.neterror, DownloadStatus.timeout -> {
+ DownloadStatus.pause,
+ DownloadStatus.subscribe,
+ DownloadStatus.neterror,
+ DownloadStatus.timeout,
+ DownloadStatus.diskisfull -> {
DownloadManager.getInstance().addObserver(dataWatcher)
uiExecutor.executeWithDelay(Runnable { DownloadManager.getInstance().resume(entity, true) }, 200)
downloadDialog?.show()
}
- DownloadStatus.done -> DataChanger.notifyDataChanged(entity)
+ DownloadStatus.done -> NDataChanger.notifyDataChanged(entity)
else -> createDownload(apkEntity, simulator)
}
diff --git a/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java b/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java
index c90244ad23..b43505f4e0 100644
--- a/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java
+++ b/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java
@@ -262,6 +262,7 @@ public class DetailDownloadUtils {
case downloading:
case redirected:
case pause:
+ case diskisfull:
case overflow:
String downloadingText = "游戏加载中 " + downloadEntity.getPercent() + "%";
String resumeText = "继续加载 " + downloadEntity.getPercent() + "%";
@@ -348,6 +349,7 @@ public class DetailDownloadUtils {
case timeout:
case neterror:
case subscribe:
+ case diskisfull:
case pause:
viewHolder.mDownloadPb.setText("继续加载 " + viewHolder.downloadEntity.getPercent() + "%");
viewHolder.mDownloadPb.setButtonStyle(DownloadButton.ButtonStyle.DOWNLOADING_NORMAL);
diff --git a/app/src/main/java/com/gh/common/util/DownloadItemUtils.kt b/app/src/main/java/com/gh/common/util/DownloadItemUtils.kt
index fb705a4000..906a7f3b01 100644
--- a/app/src/main/java/com/gh/common/util/DownloadItemUtils.kt
+++ b/app/src/main/java/com/gh/common/util/DownloadItemUtils.kt
@@ -310,6 +310,7 @@ object DownloadItemUtils {
DownloadStatus.timeout,
DownloadStatus.neterror,
DownloadStatus.subscribe,
+ DownloadStatus.diskisfull,
DownloadStatus.overflow -> {
buttonStyle = DownloadButton.ButtonStyle.NORMAL
setText(R.string.resume)
@@ -429,6 +430,7 @@ object DownloadItemUtils {
DownloadStatus.pause,
DownloadStatus.timeout,
DownloadStatus.neterror,
+ DownloadStatus.diskisfull,
DownloadStatus.subscribe,
DownloadStatus.overflow -> {
if (isMultiVersion) {
diff --git a/app/src/main/java/com/gh/common/util/DownloadNotificationHelper.kt b/app/src/main/java/com/gh/common/util/DownloadNotificationHelper.kt
index 21231cac0b..33a2f7b659 100644
--- a/app/src/main/java/com/gh/common/util/DownloadNotificationHelper.kt
+++ b/app/src/main/java/com/gh/common/util/DownloadNotificationHelper.kt
@@ -98,18 +98,19 @@ object DownloadNotificationHelper {
DownloadStatus.waiting -> builder.setContentText("等待中")
DownloadStatus.subscribe,
DownloadStatus.timeout,
+ DownloadStatus.diskisfull,
DownloadStatus.neterror -> builder.setContentText("已暂停,连接WiFi自动下载")
else -> builder.setContentText("暂停中")
}
builder.setProgress(PROGRESS_MAX, entity.percent.toInt(), false)
}
- when {
- entity.status == DownloadStatus.done -> {
+ when (entity.status) {
+ DownloadStatus.done -> {
builder.setSortKey("A")
builder.setOngoing(true) // 垃圾华为 sortKey 不起效 priority 也不起效,要将下载完成任务的通知置顶只能设置为 ongoing,喷了
}
- entity.status == DownloadStatus.downloading -> builder.setSortKey("B")
+ DownloadStatus.downloading -> builder.setSortKey("B")
else -> builder.setSortKey("C")
}
diff --git a/app/src/main/java/com/gh/common/util/DownloadObserver.kt b/app/src/main/java/com/gh/common/util/DownloadObserver.kt
index 6da5470452..cd6d7efa4f 100644
--- a/app/src/main/java/com/gh/common/util/DownloadObserver.kt
+++ b/app/src/main/java/com/gh/common/util/DownloadObserver.kt
@@ -87,7 +87,9 @@ object DownloadObserver {
)
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
return
- } else if (DownloadStatus.neterror == downloadEntity.status || DownloadStatus.timeout == downloadEntity.status) {
+ } else if (DownloadStatus.neterror == downloadEntity.status
+ || DownloadStatus.timeout == downloadEntity.status
+ || DownloadStatus.diskisfull == downloadEntity.status) {
if (downloadEntity.meta[Constants.MARK_RETRY_DOWNLOAD].isNullOrEmpty()
&& NetworkUtils.isWifiConnected(HaloApp.getInstance().application)
) {
@@ -98,7 +100,12 @@ object DownloadObserver {
Utils.log("DownloadObserver", "下载重试->" + downloadEntity.toJson())
}
} else {
- Utils.toast(mApplication, "网络不稳定,下载任务已暂停")
+ if (DownloadStatus.diskisfull == downloadEntity.status) {
+ ToastUtils.toast("磁盘已满,请清理空间后重试下载")
+ } else {
+ ToastUtils.toast("网络不稳定,下载任务已暂停")
+ }
+
DataLogUtils.uploadNeterrorLog(mApplication, downloadEntity)
debugOnly {
diff --git a/app/src/main/java/com/gh/common/xapk/XapkInstaller.kt b/app/src/main/java/com/gh/common/xapk/XapkInstaller.kt
index cf4a7a4c70..a918f23511 100644
--- a/app/src/main/java/com/gh/common/xapk/XapkInstaller.kt
+++ b/app/src/main/java/com/gh/common/xapk/XapkInstaller.kt
@@ -2,16 +2,17 @@ package com.gh.common.xapk
import android.annotation.SuppressLint
import android.content.Context
-import com.gh.gamecenter.core.AppExecutor
-import com.gh.common.util.*
+import com.gh.common.util.DownloadNotificationHelper
+import com.gh.common.util.PackageInstaller
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.common.utils.tryCatchInRelease
+import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.SentryHelper
+import com.gh.ndownload.NDataChanger
import com.halo.assistant.HaloApp
-import com.lightgame.download.DataChanger
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.Utils
import java.text.DecimalFormat
@@ -82,7 +83,7 @@ object XapkInstaller : IXapkUnzipListener {
}
downloadEntity.meta[XAPK_UNZIP_PERCENT] = percent.toString()
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.UNZIPPING.name
- DataChanger.notifyDataChanged(downloadEntity)
+ NDataChanger.notifyDataChanged(downloadEntity)
}
debugOnly {
@@ -112,7 +113,7 @@ object XapkInstaller : IXapkUnzipListener {
AppExecutor.uiExecutor.execute {
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "0.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.CANCEL.name
- DataChanger.notifyDataChanged(downloadEntity)
+ NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
}
}
@@ -123,7 +124,7 @@ object XapkInstaller : IXapkUnzipListener {
AppExecutor.uiExecutor.execute {
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.FAILURE.name
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
- DataChanger.notifyDataChanged(downloadEntity)
+ NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
}
@@ -157,7 +158,7 @@ object XapkInstaller : IXapkUnzipListener {
downloadEntity.meta[XAPK_UNZIP_PERCENT] = "100.0"
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.SUCCESS.name
- DataChanger.notifyDataChanged(downloadEntity)
+ NDataChanger.notifyDataChanged(downloadEntity)
DownloadManager.getInstance().updateDownloadEntity(downloadEntity)
}
diff --git a/app/src/main/java/com/gh/download/DownloadDataHelper.kt b/app/src/main/java/com/gh/download/DownloadDataHelper.kt
index f59615c795..e3d27fbc8a 100644
--- a/app/src/main/java/com/gh/download/DownloadDataHelper.kt
+++ b/app/src/main/java/com/gh/download/DownloadDataHelper.kt
@@ -13,8 +13,8 @@ import com.gh.gamecenter.common.utils.getExtension
import com.gh.gamecenter.common.utils.getMetaExtra
import com.gh.gamecenter.common.utils.isSimulatorGame
import com.gh.gamecenter.core.utils.SentryHelper
+import com.gh.ndownload.NDataChanger
import com.halo.assistant.HaloApp
-import com.lightgame.download.DataChanger
import com.lightgame.download.DownloadConfig
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
@@ -128,6 +128,7 @@ object DownloadDataHelper {
payloadObject.put("platform", downloadEntity.platform)
payloadObject.put("package", downloadEntity.packageName)
payloadObject.put("filename", getFileName(downloadEntity))
+ payloadObject.put("task_num", NDataChanger.downloadingTasks.size)
jsonObject.put("payload", payloadObject)
} catch (e: Exception) {
e.printStackTrace()
@@ -202,6 +203,8 @@ object DownloadDataHelper {
// payload
val payloadObject = JSONObject()
+ val parallel = downloadEntity.meta[DOWNLOAD_THREAD_SIZE]?.toInt()
+
payloadObject.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
payloadObject.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
payloadObject.put("game_id", downloadEntity.gameId)
@@ -210,7 +213,10 @@ object DownloadDataHelper {
payloadObject.put("package", downloadEntity.packageName)
payloadObject.put("filename", getFileName(downloadEntity))
payloadObject.put("launch_ms", startupTime)
- payloadObject.put("parallel", downloadEntity.meta[DOWNLOAD_THREAD_SIZE]?.toInt() ?: 0)
+ payloadObject.put("task_num", NDataChanger.downloadingTasks.size)
+ if (parallel != null) {
+ payloadObject.put("parallel", parallel)
+ }
jsonObject.put("payload", payloadObject)
} catch (e: Exception) {
e.printStackTrace()
@@ -234,7 +240,9 @@ object DownloadDataHelper {
// payload
val payloadObject = JSONObject()
+ val parallel = downloadEntity.meta[DOWNLOAD_THREAD_SIZE]?.toInt()
val sizeInMB = downloadEntity.size / 1024 / 1024
+
payloadObject.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
payloadObject.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
payloadObject.put("game_id", downloadEntity.gameId)
@@ -243,7 +251,9 @@ object DownloadDataHelper {
payloadObject.put("package", downloadEntity.packageName)
payloadObject.put("filename", getFileName(downloadEntity))
payloadObject.put("total_size", sizeInMB)
- payloadObject.put("parallel", downloadEntity.meta[DOWNLOAD_THREAD_SIZE]?.toInt() ?: 0)
+ if (parallel != null) {
+ payloadObject.put("parallel", parallel)
+ }
if (statusAlias == "下载完成") {
val elapsedTimeString = downloadEntity.meta[DownloadConfig.KEY_DOWNLOAD_ELAPSED_TIME]
@@ -264,7 +274,7 @@ object DownloadDataHelper {
payloadObject.put("speed", speed)
}
} else {
- payloadObject.put("task_num", DataChanger.downloadingTasks.size)
+ payloadObject.put("task_num", NDataChanger.downloadingTasks.size)
}
payloadObject.put("completed_size", downloadEntity.progress / 1024 / 1024)
if (downloadEntity.status == DownloadStatus.resume) {
@@ -301,6 +311,8 @@ object DownloadDataHelper {
// payload
val payloadObject = JSONObject()
+ val parallel = downloadEntity.meta[DOWNLOAD_THREAD_SIZE]?.toInt()
+
payloadObject.put("host", downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] ?: "unknown")
payloadObject.put("path", downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] ?: "unknown")
payloadObject.put("game_id", downloadEntity.gameId)
@@ -311,8 +323,10 @@ object DownloadDataHelper {
payloadObject.put("speed_progress", JSONArray(averageSpeedList))
payloadObject.put("is_finished", downloadEntity.status == DownloadStatus.done)
payloadObject.put("completed_size", downloadEntity.progress / 1024 / 1024)
- payloadObject.put("parallel", downloadEntity.meta[DOWNLOAD_THREAD_SIZE]?.toInt() ?: 0)
- payloadObject.put("task_num", DataChanger.downloadingTasks.size)
+ if (parallel != null) {
+ payloadObject.put("parallel", parallel)
+ }
+ payloadObject.put("task_num", NDataChanger.downloadingTasks.size)
jsonObject.put("payload", payloadObject)
} catch (e: Exception) {
e.printStackTrace()
@@ -335,7 +349,7 @@ object DownloadDataHelper {
* 在后台唤醒的情况下 下载状态可能无法修正
* see [DownloadManager.initDownloadService]
*/
- if (downloadEntity.status == DownloadStatus.downloading && DataChanger.downloadingTasks[downloadEntity.url] != null) {
+ if (downloadEntity.status == DownloadStatus.downloading && NDataChanger.downloadingTasks[downloadEntity.url] != null) {
var sheet = mDownloadHeartbeatSheet[downloadEntity.url]
if (sheet == null) {
sheet = JSONObject()
diff --git a/app/src/main/java/com/gh/download/DownloadManager.java b/app/src/main/java/com/gh/download/DownloadManager.java
index 2f2be8d42f..0404c8c7ff 100644
--- a/app/src/main/java/com/gh/download/DownloadManager.java
+++ b/app/src/main/java/com/gh/download/DownloadManager.java
@@ -50,17 +50,17 @@ import com.gh.gamecenter.manager.PackagesManager;
import com.gh.gamecenter.login.user.UserManager;
import com.gh.gamecenter.packagehelper.PackageRepository;
import com.gh.vspace.VHelper;
+import com.gh.ndownload.NDataChanger;
+import com.gh.ndownload.NDownloadBridge;
+import com.gh.ndownload.NDownloadService;
import com.halo.assistant.HaloApp;
import com.lightgame.download.ConnectionUtils;
-import com.lightgame.download.DataChanger;
import com.lightgame.download.DataWatcher;
import com.lightgame.download.DownloadConfig;
import com.lightgame.download.DownloadDao;
import com.lightgame.download.DownloadEntity;
-import com.lightgame.download.DownloadService;
import com.lightgame.download.DownloadStatus;
import com.lightgame.download.DownloadStatusListener;
-import com.lightgame.download.DownloadStatusManager;
import com.lightgame.download.DownloadTask;
import com.lightgame.download.FileUtils;
import com.lightgame.download.HttpDnsManager;
@@ -92,9 +92,9 @@ public class DownloadManager implements DownloadStatusListener {
private final Map> gameMap;
private final ArrayMap statusMap;
- private final ArrayMap downloadingMap;
+ private final ConcurrentHashMap downloadingMap;
- private ArrayList mInvisiblePendingTaskList; // 用户不可见的 pending 任务
+ private final ArrayList mInvisiblePendingTaskList; // 用户不可见的 pending 任务
private final DownloadDao mDownloadDao;
private final DownloadedGameIdAndPackageNameDao mDownloadedGameIdAndPackageNameDao;
@@ -170,8 +170,6 @@ public class DownloadManager implements DownloadStatusListener {
mUpdateMarks = SPUtils.getStringSet(UPDATE_IS_READ_MARK);
- DownloadStatusManager.getInstance().registerTaskStatusListener(this);
-
// 只有下载模块需要这坨东西,因此移动到这里初始化
ConnectionUtils.initHttpsUrlConnection(mContext);
@@ -181,7 +179,7 @@ public class DownloadManager implements DownloadStatusListener {
platformMap = new ArrayMap<>();
gameMap = new ConcurrentHashMap<>();
statusMap = new ArrayMap<>();
- downloadingMap = new ArrayMap<>();
+ downloadingMap = new ConcurrentHashMap<>();
// mDownloadSnapshotList = new ArrayList<>();
mInvisiblePendingTaskList = new ArrayList<>();
@@ -227,10 +225,6 @@ public class DownloadManager implements DownloadStatusListener {
}
}
- public ArrayMap getDownloadingMap() {
- return downloadingMap;
- }
-
public static DownloadManager getInstance() {
return SingletonHolder.INSTANCE;
}
@@ -446,7 +440,7 @@ public class DownloadManager implements DownloadStatusListener {
if (isDownloadCompleted(url)) {
downloadEntity.setStatus(DownloadStatus.done);
- DataChanger.INSTANCE.notifyDataChanged(downloadEntity);
+ NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
} else if (!isTaskDownloading(url)) {
startDownloadService(downloadEntity, DownloadStatus.add);
}
@@ -467,7 +461,7 @@ public class DownloadManager implements DownloadStatusListener {
checkDownloadEntryRecordValidate(url);
if (isDownloadCompleted(url)) {
downloadEntity.setStatus(DownloadStatus.done);
- DataChanger.INSTANCE.notifyDataChanged(downloadEntity);
+ NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
} else if (!isTaskDownloading(url)) {
DownloadEntity daoEntity = mDownloadDao.get(downloadEntity.getUrl());
if (automatic) {
@@ -502,7 +496,7 @@ public class DownloadManager implements DownloadStatusListener {
checkDownloadEntryRecordValidate(url);
if (isDownloadCompleted(url)) {
downloadEntity.setStatus(DownloadStatus.done);
- DataChanger.INSTANCE.notifyDataChanged(downloadEntity);
+ NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
} else if (!isTaskDownloading(url)) {
startDownloadService(downloadEntity, DownloadStatus.subscribe);
}
@@ -548,7 +542,7 @@ public class DownloadManager implements DownloadStatusListener {
* 任务是否已经下载中
*/
public boolean isTaskDownloading(String url) {
- if (DataChanger.INSTANCE.getDownloadingTasks().get(url) != null) {
+ if (NDataChanger.INSTANCE.getDownloadingTasks().get(url) != null) {
Utils.log(DownloadManager.class.getSimpleName(), url + "正在下载!");
return true;
}
@@ -556,7 +550,7 @@ public class DownloadManager implements DownloadStatusListener {
}
private Intent getIntent(DownloadEntity entry, DownloadStatus status) {
- Intent service = new Intent(mContext, DownloadService.class);
+ Intent service = new Intent(mContext, NDownloadService.class);
service.putExtra(DownloadConfig.KEY_DOWNLOAD_ENTRY, entry);
service.putExtra(DownloadConfig.KEY_DOWNLOAD_ACTION, status.name());
return service;
@@ -585,6 +579,16 @@ public class DownloadManager implements DownloadStatusListener {
return mDownloadDao.getAllSnapshots();
}
+ /**
+ * 获取快照
+ *
+ * @param url 下载地址
+ */
+ @Nullable
+ public DownloadEntity getDownloadEntitySnapshot(String url) {
+ return mDownloadDao.getSnapshot(url);
+ }
+
/**
* 获取快照
*
@@ -825,6 +829,8 @@ public class DownloadManager implements DownloadStatusListener {
DownloadEntity entry = mDownloadDao.getSnapshot(url);
if (entry != null) {
AppExecutor.getIoExecutor().execute(() -> {
+ NDownloadBridge.INSTANCE.cancel(url);
+
mDownloadDao.delete(url);
if (isDeleteFile) {
@@ -858,19 +864,16 @@ public class DownloadManager implements DownloadStatusListener {
private void cancelAndNotify(DownloadEntity entry, boolean cancelSilently) {
mDownloadDao.removeErrorMessage(entry.getUrl());
- DownloadTask task = DataChanger.INSTANCE.getDownloadingTasks().get(entry.getUrl());
+ DownloadTask task = NDataChanger.INSTANCE.getDownloadingTasks().get(entry.getUrl());
if (task != null) {
task.cancel();
// 改任务队列的状态
- DataChanger.INSTANCE.getDownloadingTasks().remove(entry.getUrl());
- if (!cancelSilently) {
- DataChanger.INSTANCE.notifyDataChanged(entry);
- }
+ NDataChanger.INSTANCE.getDownloadingTasks().remove(entry.getUrl());
}
- DataChanger.INSTANCE.getDownloadEntries().remove(entry.getUrl());
+ NDataChanger.INSTANCE.getDownloadEntries().remove(entry.getUrl());
if (!cancelSilently) {
- DataChanger.INSTANCE.notifyDataChanged(entry);
- DownloadStatusManager.getInstance().onTaskCancelled(entry);
+ NDataChanger.INSTANCE.notifyDataChanged(entry);
+ onTaskCancelled(entry);
}
Utils.log(DownloadManager.class.getSimpleName(), "cancel");
@@ -880,7 +883,7 @@ public class DownloadManager implements DownloadStatusListener {
* 暂停所有正在下载的任务
*/
public void pauseAll() {
- for (DownloadEntity entity : DataChanger.INSTANCE.getDownloadEntries().values()) {
+ for (DownloadEntity entity : NDataChanger.INSTANCE.getDownloadEntries().values()) {
pause(entity.getUrl());
}
Utils.log(DownloadManager.class.getSimpleName(), "pause all");
@@ -891,7 +894,7 @@ public class DownloadManager implements DownloadStatusListener {
*/
public void pause(String url) {
checkDownloadEntryRecordValidate(url);
- DownloadEntity entry = DataChanger.INSTANCE.getDownloadEntries().get(url);
+ DownloadEntity entry = NDataChanger.INSTANCE.getDownloadEntries().get(url);
if (entry != null) {
startDownloadService(entry, DownloadStatus.pause);
put(url, System.currentTimeMillis());
@@ -907,14 +910,14 @@ public class DownloadManager implements DownloadStatusListener {
* 3.检查是否显示下载通知栏
*/
public void initDownloadService() {
- final List urlList = new ArrayList<>(DataChanger.INSTANCE.getDownloadingTasks().keySet());
+ final List urlList = new ArrayList<>(NDataChanger.INSTANCE.getDownloadingTasks().keySet());
for (DownloadEntity downloadEntity : getAllDownloadEntity()) {
if (!urlList.contains(downloadEntity.getUrl()) &&
(downloadEntity.getStatus().equals(DownloadStatus.downloading)
|| downloadEntity.getStatus().equals(DownloadStatus.waiting))) {
downloadEntity.setStatus(DownloadStatus.subscribe);
mDownloadDao.newOrUpdate(downloadEntity);
- DataChanger.INSTANCE.notifyDataChanged(downloadEntity);
+ NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
}
}
@@ -927,7 +930,7 @@ public class DownloadManager implements DownloadStatusListener {
*/
public void addObserver(DataWatcher dataWatcher) {
Utils.log(DownloadManager.class.getSimpleName(), "addObserver");
- DataChanger.INSTANCE.addObserver(dataWatcher);
+ NDataChanger.INSTANCE.addObserver(dataWatcher);
notifyDownloadStatusASAP(dataWatcher);
}
@@ -937,7 +940,7 @@ public class DownloadManager implements DownloadStatusListener {
*/
public void removeObserver(DataWatcher dataWatcher) {
Utils.log(DownloadManager.class.getSimpleName(), "removeObserver");
- DataChanger.INSTANCE.deleteObserver(dataWatcher);
+ NDataChanger.INSTANCE.deleteObserver(dataWatcher);
}
/**
@@ -953,11 +956,11 @@ public class DownloadManager implements DownloadStatusListener {
* 初始化下载服务
*/
public void startDownloadService() {
- Intent serviceIntent = new Intent(mContext, DownloadService.class);
+ Intent serviceIntent = new Intent(mContext, NDownloadService.class);
// 当满足系统版本大于 8.0 并且应用在后台运行时以前台服务开启
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
&& !PackageUtils.isAppOnForeground(mContext)) {
- serviceIntent.putExtra(DownloadService.KEY_SERVICE_ACTION, DownloadService.START_FOREGROUND);
+ serviceIntent.putExtra(NDownloadService.KEY_SERVICE_ACTION, NDownloadService.START_FOREGROUND);
mContext.startForegroundService(serviceIntent);
} else {
/*
@@ -997,7 +1000,7 @@ public class DownloadManager implements DownloadStatusListener {
// 当满足系统版本大于 8.0 并且应用在后台运行时以前台服务开启
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
&& !PackageUtils.isAppOnForeground(mContext)) {
- serviceIntent.putExtra(DownloadService.KEY_SERVICE_ACTION, DownloadService.START_FOREGROUND);
+ serviceIntent.putExtra(NDownloadService.KEY_SERVICE_ACTION, NDownloadService.START_FOREGROUND);
mContext.startForegroundService(serviceIntent);
} else {
mContext.startService(serviceIntent);
@@ -1128,7 +1131,7 @@ public class DownloadManager implements DownloadStatusListener {
String mark = downloadEntity.getMeta().get(DOWNLOADED_IS_READ_MARK);
if (TextUtils.isEmpty(mark)) {
downloadEntity.getMeta().put(DOWNLOADED_IS_READ_MARK, DOWNLOADED_IS_READ_MARK);
- mDownloadDao.newOrUpdate(downloadEntity);
+ mDownloadDao.update(downloadEntity, false);
if (!markHasChanged) markHasChanged = true;
}
}
@@ -1168,12 +1171,12 @@ public class DownloadManager implements DownloadStatusListener {
String mark = downloadEntity.getMeta().get(DOWNLOADING_IS_READ_MARK);
if (TextUtils.isEmpty(mark)) {
downloadEntity.getMeta().put(DOWNLOADING_IS_READ_MARK, DOWNLOADING_IS_READ_MARK);
- mDownloadDao.newOrUpdate(downloadEntity);
+ mDownloadDao.update(downloadEntity, false);
if (!markHasChanged) markHasChanged = true;
}
} else {
downloadEntity.getMeta().put(DOWNLOADING_IS_READ_MARK, "");
- mDownloadDao.newOrUpdate(downloadEntity);
+ mDownloadDao.update(downloadEntity, false);
if (!markHasChanged) markHasChanged = true;
}
}
@@ -1231,7 +1234,7 @@ public class DownloadManager implements DownloadStatusListener {
* 更新数据库中的下载实体
*/
public void updateDownloadEntity(DownloadEntity downloadEntity) {
- mDownloadDao.newOrUpdate(downloadEntity);
+ mDownloadDao.update(downloadEntity, false);
}
/**
diff --git a/app/src/main/java/com/gh/download/simple/DownloadMessageHandler.kt b/app/src/main/java/com/gh/download/simple/DownloadMessageHandler.kt
index c4ba87f885..5e37bfb2e9 100644
--- a/app/src/main/java/com/gh/download/simple/DownloadMessageHandler.kt
+++ b/app/src/main/java/com/gh/download/simple/DownloadMessageHandler.kt
@@ -83,10 +83,6 @@ object DownloadMessageHandler : InnerDownloadListener {
}
}
- override fun onDownloadComplete(id: String?, elapsedTime: Long) {
- // do nothing
- }
-
/**
* 重定向中的回调
* @param id 下载 id
@@ -218,6 +214,10 @@ object DownloadMessageHandler : InnerDownloadListener {
// do nothing
}
+ override fun onDownloadComplete(id: String?, elapsedTime: Long) {
+ // do nothing
+ }
+
fun registerListener(id: String, listener: DownloadListener) {
var listenerList = mListenerMap[id]
if (listenerList == null) {
diff --git a/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.kt b/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.kt
index 834d35f6ed..2e048734d5 100644
--- a/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.kt
+++ b/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.kt
@@ -37,6 +37,7 @@ import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.entity.PrivacyPolicyEntity
import com.gh.gamecenter.feature.utils.PlatformUtils
+import com.gh.gamecenter.pkg.PkgHelper
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lightgame.download.FileUtils
@@ -386,6 +387,10 @@ class SplashScreenActivity : BaseActivity() {
checkAndPostUsageStats()
updateGameSubstituteRepository()
+ if (BuildConfig.CONFIG_ID.isNotEmpty()) {
+ PkgHelper.requestPkgConfig(BuildConfig.CONFIG_ID)
+ }
+
// 获取自动刷新的cd,获取版本对应表
val time = mSharedPreferences!!.getString("refresh_time", null)
val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
diff --git a/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragment.java b/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragment.java
index ea9b774f00..be0f28e376 100644
--- a/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragment.java
+++ b/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragment.java
@@ -162,7 +162,8 @@ public class GameDownloadFragment extends BaseFragment implements View.OnClickLi
adapter.notifyItemChanged(adapter.getBase() + location + 1);
}
}
- if (downloadEntity.getStatus() == DownloadStatus.neterror) {
+ if (downloadEntity.getStatus() == DownloadStatus.neterror
+ || downloadEntity.getStatus() == DownloadStatus.diskisfull) {
adapter.notifyItemChanged(adapter.getBase());
}
} else {
diff --git a/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragmentAdapter.java b/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragmentAdapter.java
index 3d7cfdbaf7..6296cf8297 100644
--- a/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragmentAdapter.java
+++ b/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragmentAdapter.java
@@ -238,6 +238,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
} else if (status.equals(DownloadStatus.pause)
|| status.equals(DownloadStatus.timeout)
|| status.equals(DownloadStatus.neterror)
+ || status.equals(DownloadStatus.diskisfull)
|| status.equals(DownloadStatus.subscribe)) {
viewHolder.binding.dmItemTvStartorpause.setText(R.string.resume);
viewHolder.binding.dmItemTvStartorpause.setButtonStyle(DownloadButton.ButtonStyle.NORMAL);
@@ -247,6 +248,8 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
|| status.equals(DownloadStatus.neterror)
|| status.equals(DownloadStatus.subscribe)) {
viewHolder.binding.dmItemTvSpeed.setText("等待WIFI");
+ } else if (status.equals(DownloadStatus.diskisfull)) {
+ viewHolder.binding.dmItemTvSpeed.setText("已暂停,磁盘空间不足");
} else {
viewHolder.binding.dmItemTvSpeed.setText("已暂停");
}
diff --git a/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperViewModel.kt b/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperViewModel.kt
index d1204aba72..dc31f26f03 100644
--- a/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperViewModel.kt
@@ -11,6 +11,7 @@ import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.entity.HomeDataEntity
import com.gh.gamecenter.entity.SubjectRecommendEntity
+import com.gh.gamecenter.pkg.PkgHelper
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
@@ -64,6 +65,20 @@ class HomeSearchToolWrapperViewModel(application: Application) : AndroidViewMode
if (homeTab.size == 0) {
homeTab.add(SubjectRecommendEntity(type = "home"))
}
+
+ // 从推广包配置信息里找是否需要默认选中一个 tab
+ PkgHelper.getPkgConfig()?.let { pkgLinkEntity ->
+ if (pkgLinkEntity.isHomeTopTabLink) {
+ PkgHelper.markConfigUsed()
+ for ((index, tab) in homeTab.withIndex()) {
+ if (pkgLinkEntity.type == tab.type && pkgLinkEntity.link == tab.link) {
+ defaultTabPosition = index
+ break
+ }
+ }
+ }
+ }
+
if (!isRefresh) {
tabs.postValue(homeTab)
}
diff --git a/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java b/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java
index c1d2122b2d..720e23ddd9 100644
--- a/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java
+++ b/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java
@@ -29,6 +29,7 @@ import com.facebook.imagepipeline.image.ImageInfo;
import com.gh.common.constant.Config;
import com.gh.common.dialog.PrivacyPolicyDialogFragment;
import com.gh.common.dialog.ReserveDialog;
+import com.gh.common.util.DirectUtils;
import com.gh.common.util.HomeBottomBarHelper;
import com.gh.common.util.IntegralLogHelper;
import com.gh.common.util.LogUtils;
@@ -41,6 +42,7 @@ import com.gh.gamecenter.common.callback.BiCallback;
import com.gh.gamecenter.common.callback.OnDoubleTapListener;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.EntranceConsts;
+import com.gh.gamecenter.common.entity.PkgConfigEntity;
import com.gh.gamecenter.common.eventbus.EBReuse;
import com.gh.gamecenter.common.syncpage.SyncPageRepository;
import com.gh.gamecenter.common.tracker.TrackerLogger;
@@ -67,6 +69,7 @@ import com.gh.gamecenter.login.entity.UserInfoEntity;
import com.gh.gamecenter.message.MessageUnreadRepository;
import com.gh.gamecenter.message.MessageUnreadViewModel;
import com.gh.gamecenter.personal.HaloPersonalFragment;
+import com.gh.gamecenter.pkg.PkgHelper;
import com.gh.gamecenter.servers.GameServersPublishFragment;
import com.gh.gamecenter.servers.GameServersTestFragment;
import com.gh.gamecenter.subject.SubjectFragment;
@@ -266,11 +269,47 @@ public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implem
}
});
+ applyPkgConfig();
+
ViewModelProviders.of(this)
.get(MessageUnreadViewModel.class)
.getUnreadMessageTotalLiveData().observe(this, isShow -> ExtensionsKt.goneIf(mBinding.mainIvMessageHint, !isShow));
}
+ private void applyPkgConfig() {
+ PkgConfigEntity.PkgLinkEntity pkgLinkEntity = PkgHelper.INSTANCE.getPkgConfig();
+ if (pkgLinkEntity != null && !pkgLinkEntity.isHomeTopTabLink()) {
+ String bottomTab = pkgLinkEntity.getHomeBottomTab();
+
+ PkgHelper.INSTANCE.markConfigUsed();
+ if (!TextUtils.isEmpty(bottomTab)) {
+ // TODO 根据具体 tab 来作为跳转的具体位置,避免硬编码
+ int targetIndex = INDEX_HOME;
+
+ switch (bottomTab) {
+ case "game_lib":
+ targetIndex = INDEX_GAME;
+ break;
+ case "community":
+ targetIndex = INDEX_BBS;
+ break;
+ case "video":
+ targetIndex = INDEX_VIDEO;
+ break;
+ case "gh":
+ targetIndex = INDEX_PERSONAL;
+ break;
+ }
+
+ mViewPager.setCurrentItem(targetIndex);
+ onPageChanged(targetIndex);
+ changeColor(targetIndex);
+ } else {
+ DirectUtils.directToLinkPage(requireContext(), pkgLinkEntity, "推广包配置", "首页");
+ }
+ }
+ }
+
public void getDialog() {
mViewModel.requestOpeningData();
mViewModel.getPrivacyPolicyDialog().observe(this, it -> {
diff --git a/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java b/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java
index 97c3d812ab..f2d2b5c6f6 100644
--- a/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java
+++ b/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java
@@ -47,8 +47,8 @@ import com.gh.gamecenter.entity.AppEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.common.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
+import com.gh.ndownload.NDataChanger;
import com.halo.assistant.HaloApp;
-import com.lightgame.download.DataChanger;
import com.lightgame.download.DataWatcher;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.DownloadStatus;
@@ -158,6 +158,8 @@ public class UpdateManager {
}
} else if (DownloadStatus.neterror.equals(downloadEntity.getStatus())) {
Utils.toast(mApplicationContext, "网络错误,请稍后重试");
+ } else if (DownloadStatus.diskisfull.equals(downloadEntity.getStatus())) {
+ Utils.toast(mApplicationContext, "磁盘已满,请清理后重试");
} else if (DownloadStatus.timeout.equals(downloadEntity.getStatus())) {
Utils.toast(mApplicationContext, "请求超时,请稍后重试");
} else if (DownloadStatus.notfound.equals(downloadEntity.getStatus())) {
@@ -479,7 +481,7 @@ public class UpdateManager {
if (!isSilentUpdate
&& DownloadManager.getInstance().isTaskDownloading(appEntity.getUrl())) {
try {
- DownloadEntity entity = DataChanger.INSTANCE.getDownloadEntries().get(appEntity.getUrl());
+ DownloadEntity entity = NDataChanger.INSTANCE.getDownloadEntries().get(appEntity.getUrl());
if (entity != null) {
ExtensionsKt.addMetaExtra(entity, Constants.EXTRA_DOWNLOAD_TYPE, "不再是静默更新");
diff --git a/app/src/main/java/com/gh/gamecenter/pkg/PkgHelper.kt b/app/src/main/java/com/gh/gamecenter/pkg/PkgHelper.kt
new file mode 100644
index 0000000000..2d0da1e62a
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/pkg/PkgHelper.kt
@@ -0,0 +1,47 @@
+package com.gh.gamecenter.pkg
+
+import android.util.Base64
+import com.alibaba.android.arouter.launcher.ARouter
+import com.gh.gamecenter.BuildConfig
+import com.gh.gamecenter.common.constant.RouteConsts
+import com.gh.gamecenter.common.entity.PkgConfigEntity
+import com.gh.gamecenter.common.utils.toObject
+import com.gh.gamecenter.core.provider.IPkgProvider
+import com.gh.gamecenter.core.utils.SPUtils
+
+object PkgHelper {
+
+ private var mPkgConfigLink: PkgConfigEntity.PkgLinkEntity? = null
+ private const val SP_PKG_CONFIG_IS_USED = "pkg_config_is_used"
+
+ private val mPkgProvider by lazy {
+ ARouter.getInstance().build(RouteConsts.provider.pkg).navigation() as? IPkgProvider
+ }
+
+ fun getPkgConfig(): PkgConfigEntity.PkgLinkEntity? {
+ if (mPkgConfigLink == null
+ && !SPUtils.getBoolean(SP_PKG_CONFIG_IS_USED, false)
+ && BuildConfig.FIRST_LAUNCH.isNotEmpty()) {
+ mPkgConfigLink = Base64.decode(BuildConfig.FIRST_LAUNCH, Base64.DEFAULT).toString().toObject()
+ }
+
+ return mPkgConfigLink
+ }
+
+ fun markConfigUsed() {
+ mPkgConfigLink = null
+ SPUtils.setBoolean(SP_PKG_CONFIG_IS_USED, true)
+ }
+
+ /**
+ * 获取特殊包配置
+ */
+ fun requestPkgConfig(configId: String) {
+ if (SPUtils.getBoolean(SP_PKG_CONFIG_IS_USED, false)) return
+
+ mPkgProvider?.requestPkgConfig(configId) {
+ mPkgConfigLink = it.data?.link
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/ndownload/NDataChanger.kt b/app/src/main/java/com/gh/ndownload/NDataChanger.kt
new file mode 100644
index 0000000000..434e8c4847
--- /dev/null
+++ b/app/src/main/java/com/gh/ndownload/NDataChanger.kt
@@ -0,0 +1,37 @@
+package com.gh.ndownload
+
+import com.gh.gamecenter.core.runOnUiThread
+import com.lightgame.download.DownloadEntity
+import com.lightgame.download.DownloadTask
+import java.util.*
+
+/**
+ * 下载进度变化通知
+ */
+object NDataChanger : Observable() {
+
+ val downloadingTasks: MutableMap = Collections.synchronizedMap(HashMap())//当前正在下载的任务队列
+ val downloadEntries: MutableMap = Collections.synchronizedMap(HashMap())//包含所有下载任务的任务队列
+
+ @Synchronized
+ fun notifyDataChanged(entry: DownloadEntity?) {
+ runOnUiThread {
+ if (entry != null) {
+ if (downloadEntries[entry.url] != null) {
+ downloadEntries[entry.url] = entry
+ }
+ setChanged()
+ notifyObservers(entry)
+ }
+ }
+ }
+
+ @Synchronized
+ fun pauseDownloadingTask(url: String) {
+ runOnUiThread {
+ val downloadTask = downloadingTasks.remove(url)
+ downloadTask?.pause()
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/gh/ndownload/NDownloadBridge.kt b/app/src/main/java/com/gh/ndownload/NDownloadBridge.kt
new file mode 100644
index 0000000000..0b37db83ba
--- /dev/null
+++ b/app/src/main/java/com/gh/ndownload/NDownloadBridge.kt
@@ -0,0 +1,409 @@
+package com.gh.ndownload
+
+import android.text.TextUtils
+import com.gh.download.DownloadDataHelper
+import com.gh.download.DownloadManager
+import com.gh.gamecenter.common.utils.NetworkUtils
+import com.gh.gamecenter.common.utils.addMetaExtra
+import com.gh.gamecenter.common.utils.deepClone
+import com.gh.gamecenter.core.AppExecutor
+import com.gh.gamecenter.core.utils.ToastUtils
+import com.halo.assistant.HaloApp
+import com.lg.download.DownloadError
+import com.lg.download.listener.InnerDownloadListener
+import com.lg.ndownload.*
+import com.lightgame.download.DownloadDao
+import com.lightgame.download.DownloadEntity
+import com.lightgame.download.FileUtils
+import com.lightgame.utils.Utils
+import org.json.JSONException
+import org.json.JSONObject
+import java.io.IOException
+import java.math.RoundingMode
+import java.net.URL
+import java.net.URLConnection
+import java.text.DecimalFormat
+import java.text.DecimalFormatSymbols
+import java.util.*
+import java.util.concurrent.ConcurrentHashMap
+
+/**
+ * 是串联丑陋的下载模块与新下载模块之间的桥梁
+ */
+object NDownloadBridge : InnerDownloadListener, IErrorRetryHandler {
+
+ private const val TAG = "NDownloadBridge"
+ private const val DEFAULT_DOWNLOAD_THREAD_SIZE = 2
+ private const val NO_NETWORK_MAX_RETRY_COUNT = 5
+
+ private var mRetryTimer: Timer? = null // 用于错误重试的 timer
+ private val mRetryCountMap: ConcurrentHashMap by lazy { ConcurrentHashMap() }
+
+ private val mStartUpTimeMap: ConcurrentHashMap by lazy { ConcurrentHashMap() }
+
+ init {
+ DownloadQueue.getInstance().setMaxDownloadingTask(3)
+ }
+
+ override fun onError(id: String, error: DownloadError?, exception: Exception?) {
+ Utils.log(TAG, "id $id encounter $error -> ${exception?.message}")
+
+ resetRetryCount(id)
+ getDownloadEntity(id)?.let { downloadEntity ->
+ when (error) {
+ DownloadError.EMPTY_URL,
+ DownloadError.HTTP_NOT_FOUND,
+ DownloadError.CONTENT_LENGTH_IS_ZERO -> {
+ doCancel(downloadEntity)
+ downloadEntity.status = com.lightgame.download.DownloadStatus.notfound
+ }
+ DownloadError.HIJACKED -> {
+ doCancel(downloadEntity)
+ downloadEntity.status = com.lightgame.download.DownloadStatus.hijack
+ }
+ DownloadError.DOWNLOAD_SIZE_NOT_MATCH_CONTENT_LENGTH -> {
+ doCancel(downloadEntity)
+ downloadEntity.status = com.lightgame.download.DownloadStatus.overflow
+ DownloadManager.getInstance().onTaskError(downloadEntity)
+ }
+ DownloadError.PREVIOUS_DOWNLOAD_IS_DELETED,
+ DownloadError.FILE_CORRUPTED -> {
+ doCancel(downloadEntity)
+ ToastUtils.toast("文件已损坏,请重新下载")
+ downloadEntity.status = com.lightgame.download.DownloadStatus.cancel
+ }
+ DownloadError.PRE_DOWNLOAD_INTERNAL_ERROR,
+ DownloadError.DOWNLOAD_CONNECTION_ERROR,
+ DownloadError.PRE_DOWNLOAD_CONNECTION_ERROR -> {
+ downloadEntity.status = com.lightgame.download.DownloadStatus.neterror
+ DownloadManager.getInstance().onTaskError(downloadEntity)
+ NDownloadService.getService()?.removeFromDataChangerAndResumeWaitingTask(downloadEntity, true)
+
+ DownloadDao.getInstance(HaloApp.getInstance()).update(downloadEntity, false)
+ }
+ DownloadError.DISK_IS_FULL -> {
+ downloadEntity.status = com.lightgame.download.DownloadStatus.diskisfull
+ NDownloadService.getService()?.removeFromDataChangerAndResumeWaitingTask(downloadEntity, true)
+
+ DownloadDao.getInstance(HaloApp.getInstance()).update(downloadEntity, false)
+ }
+ DownloadError.RESOURCE_IS_FORBIDDEN -> {
+ val errorString = exception?.message
+ if (!errorString.isNullOrEmpty()) {
+ handleForbiddenException(downloadEntity, errorString)
+ }
+
+ doCancel(downloadEntity)
+ }
+ DownloadError.PERSONAL_NO_CERTIFICATION -> {
+ doCancel(downloadEntity)
+ downloadEntity.status = com.lightgame.download.DownloadStatus.uncertificated
+ }
+ DownloadError.PERSONAL_TEENAGER -> {
+ doCancel(downloadEntity)
+ downloadEntity.status = com.lightgame.download.DownloadStatus.unqualified
+ }
+ else -> {
+ // do nothing
+ }
+ }
+ NDataChanger.notifyDataChanged(downloadEntity)
+ }
+ }
+
+ override fun onProgress(id: String?, progress: Float) {
+ getDownloadEntity(id)?.let { downloadEntity ->
+ var percent = (progress * 100.0)
+ val df = DecimalFormat("#.#", DecimalFormatSymbols(Locale.CHINA))
+ df.roundingMode = RoundingMode.FLOOR
+ percent = df.format(percent).toDouble()
+
+ downloadEntity.progress = (downloadEntity.size * progress).toLong()
+ downloadEntity.percent = percent
+
+ // 有可能还处于 redirected 状态,这里检查并置换状态
+ if (com.lightgame.download.DownloadStatus.downloading != downloadEntity.status) {
+ downloadEntity.status = com.lightgame.download.DownloadStatus.downloading
+ }
+
+ DownloadDao.getInstance(HaloApp.getInstance()).update(downloadEntity, false)
+
+ NDataChanger.notifyDataChanged(downloadEntity)
+ }
+ }
+
+ override fun onProgressWithoutThrottle(id: String?, progress: Float) {
+ if (id != null && (mStartUpTimeMap[id] ?: 0) > 0) {
+ val startupTime: Long = System.currentTimeMillis() - (mStartUpTimeMap[id] ?: 0)
+ getDownloadEntity(id)?.let { downloadEntity ->
+ downloadEntity.meta.put(DownloadEntity.DOWNLOAD_STARTUP_TIME_KEY, startupTime.toString())
+ }
+ mStartUpTimeMap[id] = 0
+ }
+ }
+
+ override fun onSizeReceived(id: String?, fileSize: Long) {
+ Utils.log(TAG, "id $id onSizeReceived $fileSize")
+
+ getDownloadEntity(id)?.let { downloadEntity ->
+ downloadEntity.size = fileSize
+
+ DownloadDao.getInstance(HaloApp.getInstance()).update(downloadEntity, false)
+ }
+ }
+
+ override fun onReadyToDownload(id: String?, actualThreadSize: Int) {
+ Utils.log(TAG, "id $id onReadyToDownload, actualThreadSize is -> $actualThreadSize")
+
+ getDownloadEntity(id)?.let { downloadEntity ->
+ downloadEntity.meta[DownloadDataHelper.DOWNLOAD_THREAD_SIZE] = actualThreadSize.toString()
+
+ DownloadDao.getInstance(HaloApp.getInstance()).update(downloadEntity, false)
+ }
+ }
+
+ override fun onStatusChanged(id: String, status: com.lg.download.DownloadStatus?) {
+ Utils.log(TAG, "id $id onStatusChanged $status")
+
+ resetRetryCount(id)
+ getDownloadEntity(id)?.let { originDownloadEntity ->
+ // 状态更新使用全新的拷贝对象,避免因为不同线程对数据的变更造成通知错乱
+ val downloadEntity = originDownloadEntity.deepClone() ?: return@let
+ when (status) {
+ com.lg.download.DownloadStatus.CANCELLED -> {
+ doCancel(downloadEntity)
+
+ DownloadManager.getInstance().onTaskPaused(downloadEntity)
+ NDownloadService.getService()?.removeFromDataChangerAndResumeWaitingTask(downloadEntity, true)
+ }
+ com.lg.download.DownloadStatus.PAUSED -> {
+ downloadEntity.speed = 0
+ downloadEntity.status = com.lightgame.download.DownloadStatus.pause
+
+ NDownloadService.getService()?.removeFromDataChangerAndResumeWaitingTask(downloadEntity, false)
+ }
+ com.lg.download.DownloadStatus.WAITINGWIFI -> {
+ downloadEntity.status = com.lightgame.download.DownloadStatus.waiting
+ }
+ com.lg.download.DownloadStatus.DOWNLOADING -> {
+ downloadEntity.status = com.lightgame.download.DownloadStatus.downloading
+ DownloadManager.getInstance().onTaskAdded(downloadEntity)
+ }
+ com.lg.download.DownloadStatus.QUEUED -> {
+ downloadEntity.status = com.lightgame.download.DownloadStatus.add
+ }
+ else -> {
+ Utils.log(TAG, "status not supported yet -> $status")
+ }
+ }
+
+ DownloadDao.getInstance(HaloApp.getInstance()).update(downloadEntity, false)
+
+ NDataChanger.notifyDataChanged(downloadEntity)
+ }
+ }
+
+ override fun onDownloadComplete(id: String?, elapsedTime: Long) {
+ getDownloadEntity(id)?.let { originDownloadEntity ->
+ val downloadEntity = originDownloadEntity.deepClone() ?: return@let
+
+ downloadEntity.speed = 0
+ downloadEntity.progress = downloadEntity.size
+ downloadEntity.percent = 100.0
+ downloadEntity.end = System.currentTimeMillis()
+ downloadEntity.status = com.lightgame.download.DownloadStatus.done
+ downloadEntity.addMetaExtra(com.lightgame.download.DownloadConfig.KEY_DOWNLOAD_ELAPSED_TIME, elapsedTime.toString())
+
+ DownloadManager.getInstance().onTaskDone(downloadEntity)
+ NDownloadService.getService()?.removeFromDataChangerAndResumeWaitingTask(downloadEntity, true)
+
+ DownloadDao.getInstance(HaloApp.getInstance()).update(downloadEntity, false)
+
+ NDataChanger.notifyDataChanged(downloadEntity)
+ }
+ }
+
+ override fun onSpeedChanged(id: String, speed: Float) {
+ getDownloadEntity(id)?.let { downloadEntity ->
+ downloadEntity.speed = speed.toLong()
+
+ NDataChanger.notifyDataChanged(downloadEntity)
+ }
+ }
+
+ override fun onRedirectingUrl(id: String, connection: URLConnection?, config: DownloadConfig?) {
+ getDownloadEntity(id)?.let { downloadEntity ->
+ if (!TextUtils.isEmpty(downloadEntity.eTag)) {
+ val eTag: String = getRealETag(connection?.getHeaderField("Halo-ETag") ?: "")
+ downloadEntity.haloEtag = eTag
+ DownloadDao.getInstance(HaloApp.getInstance()).update(downloadEntity, false)
+ }
+
+ NDataChanger.notifyDataChanged(downloadEntity)
+ }
+ }
+
+ override fun onRedirectedUrl(id: String, connection: URLConnection?, redirectedUrl: String?) {
+ getDownloadEntity(id)?.let { downloadEntity ->
+ downloadEntity.finalRedirectedUrl = redirectedUrl
+ val url = URL(redirectedUrl)
+ if (url.host != null && url.path != null) {
+ downloadEntity.meta[DownloadEntity.DOWNLOAD_HOST_KEY] = url.host
+ downloadEntity.meta[DownloadEntity.DOWNLOAD_PATH_KEY] = url.path
+ DownloadDao.getInstance(HaloApp.getInstance()).update(downloadEntity, false)
+ }
+
+ downloadEntity.status = com.lightgame.download.DownloadStatus.redirected
+
+ // downloadEntity 的 etag 的值用来判断是否需要进行劫持校验,值不参与到最后判断是否被劫持的校验中去
+ val shouldCompareETag = !TextUtils.isEmpty(downloadEntity.eTag)
+ val currentETag = connection?.getHeaderField("ETag")
+ if (shouldCompareETag
+ && !TextUtils.isEmpty(currentETag)
+ && currentETag != downloadEntity.haloEtag
+ ) {
+ // 链接被劫持,抛出异常
+ downloadEntity.status = com.lightgame.download.DownloadStatus.hijack
+ }
+
+ NDataChanger.notifyDataChanged(downloadEntity)
+ }
+ }
+
+ override fun getRetryOption(id: String, e: Exception?): Int {
+ val downloadEntity =
+ DownloadDao.getInstance(HaloApp.getInstance()).getSnapshot(id) ?: return IErrorRetryHandler.RETRY_DIRECTLY
+
+ return if (e is IOException && FileUtils.getFreeSpaceByPath(downloadEntity.path) < 10F) {
+ IErrorRetryHandler.REFUSE_TO_RETRY
+ } else if (NetworkUtils.isWifiConnected(HaloApp.getInstance()) || isDownloadViaTrafficAllowed(downloadEntity)) {
+ IErrorRetryHandler.RETRY_DIRECTLY
+ } else {
+ IErrorRetryHandler.RETRY_MANUALLY
+ }
+ }
+
+ override fun retryManually(id: String, retryRunnable: Runnable, pauseRunnable: Runnable) {
+ if (mRetryTimer == null) {
+ mRetryTimer = Timer()
+ }
+
+ Utils.log(TAG, "about to retry download manually")
+
+ mRetryTimer?.schedule(object : TimerTask() {
+ override fun run() {
+ if (NetworkUtils.isWifiConnected(HaloApp.getInstance())) {
+ resetRetryCount(id)
+ retryRunnable.run()
+ } else {
+ mRetryCountMap[id] = (mRetryCountMap[id] ?: 0) + 1
+ if (mRetryCountMap[id]!! <= NO_NETWORK_MAX_RETRY_COUNT) {
+ retryManually(id, retryRunnable, pauseRunnable)
+ } else {
+ resetRetryCount(id)
+ pauseRunnable.run()
+ }
+ }
+ }
+ }, GlobalDownloadConfig.ERROR_RETRY_INTERVAL)
+ }
+
+ private fun isDownloadViaTrafficAllowed(downloadEntity: DownloadEntity?): Boolean {
+ val mNetworkMobileStatus = "2G3G4G5G"
+ val networkStatus: String? = downloadEntity?.meta?.get(DownloadEntity.NETWORK_STATUS_KEY)
+ Utils.log("download network status$networkStatus")
+ return if (networkStatus == null) false else mNetworkMobileStatus.contains(networkStatus)
+ }
+
+ fun download(downloadEntity: DownloadEntity) {
+ val config = DownloadConfigBuilder()
+ .setUniqueId(downloadEntity.url)
+ .setFileName("")
+ .setUrl(downloadEntity.url)
+ .setPathToStore(downloadEntity.path)
+ .setHttpClient(NHttpClient())
+ .setDownloadThreadSize(DEFAULT_DOWNLOAD_THREAD_SIZE)
+ .setDownloadListener(NDownloadBridge)
+ .setErrorRetryHandler(this)
+ .setDownloadExecutor(AppExecutor.downloadExecutor)
+ .setMeta(downloadEntity.meta as HashMap?)
+ .setErrorRetryHandler(this)
+ .build()
+
+ mStartUpTimeMap[downloadEntity.url] = System.currentTimeMillis()
+
+ DownloadQueue.getInstance().submitNewTask(config)
+ }
+
+ fun resume(id: String?) {
+ id?.let {
+ DownloadQueue.getInstance().resume(id)
+
+ getDownloadEntity(id)?.let { downloadEntity ->
+ mStartUpTimeMap[downloadEntity.url] = System.currentTimeMillis()
+ }
+ }
+ }
+
+ fun pause(id: String?) {
+ id?.let {
+ DownloadQueue.getInstance().pause(id)
+ }
+ }
+
+ fun cancel(id: String?) {
+ id?.let {
+ NDataChanger.downloadEntries.remove(id)
+ DownloadQueue.getInstance().cancel(id)
+ }
+ }
+
+ private fun doCancel(downloadEntity: DownloadEntity) {
+ DownloadManager.getInstance().cancel(downloadEntity.url)
+ }
+
+ private fun getRealETag(originETag: String): String {
+ var realETag = originETag
+ if (!TextUtils.isEmpty(realETag) && realETag.startsWith("\"") && realETag.endsWith("\"")) {
+ realETag = realETag.substring(1, realETag.length - 1)
+ }
+ return realETag
+ }
+
+ private fun handleForbiddenException(downloadEntity: DownloadEntity, errorString: String) {
+ try {
+ val resultObject = JSONObject(errorString)
+
+ if ("403001" == resultObject.getString("code")) {
+ // 未实名
+ if (resultObject.has("force") && !resultObject.getBoolean("force")) {
+ downloadEntity.meta["force_real_name"] = "false"
+ }
+ downloadEntity.status = com.lightgame.download.DownloadStatus.uncertificated
+ } else if ("403002" == resultObject.getString("code")) {
+ // 未成年
+ if (resultObject.has("force") && !resultObject.getBoolean("force")) {
+ downloadEntity.meta["force_real_name"] = "false"
+ }
+ downloadEntity.status = com.lightgame.download.DownloadStatus.unqualified
+ } else if ("403003" == resultObject.getString("code")) {
+ // 该游戏未接入防沉迷系统禁止下载
+ downloadEntity.status = com.lightgame.download.DownloadStatus.unavailable
+ } else if ("403004" == resultObject.getString("code")) {
+ // 后台禁止该设备下载
+ downloadEntity.status = com.lightgame.download.DownloadStatus.banned
+ }
+ } catch (e: JSONException) {
+ e.printStackTrace()
+ }
+ }
+
+ private fun resetRetryCount(id: String) {
+ mRetryCountMap[id] = 0
+ }
+
+ private fun getDownloadEntity(id: String?): DownloadEntity? {
+ return DownloadManager.getInstance().getDownloadEntitySnapshot(id)
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/ndownload/NDownloadService.java b/app/src/main/java/com/gh/ndownload/NDownloadService.java
new file mode 100644
index 0000000000..c894bafdcf
--- /dev/null
+++ b/app/src/main/java/com/gh/ndownload/NDownloadService.java
@@ -0,0 +1,276 @@
+package com.gh.ndownload;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.IBinder;
+import android.text.TextUtils;
+
+import androidx.annotation.Nullable;
+import androidx.core.app.NotificationCompat;
+
+import com.gh.download.DownloadManager;
+import com.lightgame.BuildConfig;
+import com.lightgame.download.DownloadConfig;
+import com.lightgame.download.DownloadDao;
+import com.lightgame.download.DownloadEntity;
+import com.lightgame.download.DownloadStatus;
+import com.lightgame.download.DownloadTask;
+import com.lightgame.download.ForegroundNotificationManager;
+import com.lightgame.utils.Utils;
+
+import java.util.Random;
+
+public class NDownloadService extends Service {
+
+ public static final String KEY_SERVICE_ACTION = "service_action";
+ public static final String START_FOREGROUND = "start_foreground";
+ private static final String SERVICE_CHANNEL_ID = "Halo_Download";
+
+ private static NDownloadService sService = null;
+
+ private ForegroundNotificationManager mForegroundNotificationManager;
+
+ @Nullable
+ public static NDownloadService getService() {
+ return sService;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ sService = this;
+
+ mForegroundNotificationManager = new ForegroundNotificationManager(this, this.getApplication());
+ Utils.log(NDownloadService.class.getSimpleName(), "onCreate");
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Utils.log(NDownloadService.class.getSimpleName(), "onStartCommand");
+
+ int randomNotificationId = getNextIntExcludeZero();
+
+ if (intent != null && intent.getExtras() != null) {
+ String serviceAction = intent.getStringExtra(KEY_SERVICE_ACTION);
+
+ if (START_FOREGROUND.equals(serviceAction)) {
+ startForegroundIfNeeded(randomNotificationId);
+ }
+
+ String statusString = intent.getStringExtra(DownloadConfig.KEY_DOWNLOAD_ACTION);
+ if (!TextUtils.isEmpty(statusString)) {
+ // 看不懂的操作
+ DownloadStatus status = DownloadStatus.valueOf(statusString);
+ DownloadEntity entry = (DownloadEntity) intent.getSerializableExtra(DownloadConfig.KEY_DOWNLOAD_ENTRY);
+
+ DownloadEntity downloadEntity = DownloadDao.getInstance(this).get(entry.getUrl());
+ if (downloadEntity == null) {
+ // 设置开始下载时间(排序用到)
+ entry.setStart(System.currentTimeMillis());
+ }
+
+ // 置换最新状态
+ entry.setStatus(status);
+
+ // 删除下载错误信息
+ entry.setError("");
+ DownloadDao.getInstance(this).removeErrorMessage(entry.getUrl());
+
+ if (BuildConfig.DEBUG) {
+ Utils.log(NDownloadService.class.getSimpleName(), entry.getPackageName() + "==>" + entry.getStatus().getStatus());
+ }
+ switch (status) {
+ case subscribe:
+ subscribeDownload(entry);
+ break;
+ case add:
+ addDownload(entry);
+ break;
+ case pause:
+ case timeout:
+ case neterror:
+ case diskisfull:
+ pauseDownload(entry);
+ break;
+ case resume:
+ resumeDownload(entry);
+ break;
+ case cancel:
+ cancelDownload(entry);
+ break;
+ default:
+ if (BuildConfig.DEBUG) {
+ Utils.log(NDownloadService.class.getSimpleName(), "无法处理的下载状态:" + entry.getStatus().getStatus());
+ }
+ break;
+ }
+ } else {
+ if (BuildConfig.DEBUG) {
+ Utils.log(NDownloadService.class.getSimpleName(), "启动了一个空的下载服务");
+ }
+ }
+ } else {
+ // 无参时也默认以前台启动
+ startForegroundIfNeeded(randomNotificationId);
+ }
+
+ stopForegroundIfNeeded(randomNotificationId);
+
+ // 不需要 intent 为空的重建
+ return START_NOT_STICKY;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ synchronized void subscribeDownload(DownloadEntity entry) {
+ NDataChanger.INSTANCE.getDownloadEntries().put(entry.getUrl(), entry);
+ DownloadDao.getInstance(this).newOrUpdate(entry);
+ NDataChanger.INSTANCE.notifyDataChanged(entry);
+ DownloadManager.getInstance().onTaskAdded(entry);
+ }
+
+ synchronized void addDownload(DownloadEntity entry) {
+ if (NDataChanger.INSTANCE.getDownloadingTasks().size() >= DownloadConfig.MAX_DOWNLOADING_SIZE) {
+ // 1.改任务队列的状态
+ entry.setStatus(DownloadStatus.waiting);
+ NDataChanger.INSTANCE.getDownloadEntries().put(entry.getUrl(), entry);
+ // 2.改数据库状态
+ DownloadDao.getInstance(this).newOrUpdate(entry);
+ // 3.通知更新
+ NDataChanger.INSTANCE.notifyDataChanged(entry);
+ } else {
+ startDownload(entry);
+ }
+ DownloadManager.getInstance().onTaskAdded(entry);
+ }
+
+ synchronized void pauseDownload(DownloadEntity entry) {
+ if (entry != null) {
+ entry.setStatus(DownloadStatus.pause);
+
+ // 1.改任务队列的状态
+ NDownloadBridge.INSTANCE.pause(entry.getUrl());
+ NDataChanger.INSTANCE.pauseDownloadingTask(entry.getUrl());
+
+ // 2.改数据库状态
+ DownloadDao.getInstance(this).update(entry, false);
+ }
+ }
+
+ synchronized void resumeDownload(DownloadEntity entry) {
+ addDownload(entry);
+ }
+
+ synchronized void cancelDownload(DownloadEntity downloadEntity) {
+ DownloadTask task = NDataChanger.INSTANCE.getDownloadingTasks()
+ .get(downloadEntity.getUrl());
+ if (task != null) {
+ NDownloadBridge.INSTANCE.cancel(downloadEntity.getUrl());
+ // 改任务队列的状态
+ NDataChanger.INSTANCE.getDownloadingTasks().remove(downloadEntity.getUrl());
+ NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
+ }
+ NDataChanger.INSTANCE.getDownloadEntries().remove(downloadEntity.getUrl());
+ NDataChanger.INSTANCE.notifyDataChanged(downloadEntity);
+ DownloadManager.getInstance().onTaskCancelled(downloadEntity);
+ }
+
+ synchronized void startDownload(DownloadEntity entry) {
+ DownloadTask task = NDataChanger.INSTANCE.getDownloadingTasks().get(entry.getUrl());
+ if (task == null) {
+ // 刷新初始状态
+ NDataChanger.INSTANCE.notifyDataChanged(entry);
+
+ entry.getMeta().put(DownloadEntity.DOWNLOAD_STARTUP_STATUS_KEY, entry.getStatus().getStatus());
+ // 1.改任务队列的状态
+ entry.setStatus(DownloadStatus.downloading);
+ NDataChanger.INSTANCE.getDownloadEntries().put(entry.getUrl(), entry);
+ NDataChanger.INSTANCE.getDownloadingTasks().put(entry.getUrl(), new DownloadTask(null, entry, this));
+
+ // 2.改数据库状态
+ DownloadDao.getInstance(this).newOrUpdate(entry);
+
+ // 3.执行下载
+ NDownloadBridge.INSTANCE.download(entry);
+
+ // 4.通知更新
+ NDataChanger.INSTANCE.notifyDataChanged(entry);
+ } else {
+ Utils.log("Fuck this, we received multiple download request for the same url");
+ }
+ }
+
+ /**
+ * 从 DataChanger 里移除掉数据,并找到下一个处于 waiting 状态的任务继续
+ * @param downloadEntity 需要移除的数据
+ * @param removeCompletely 是否完全移除,false 时只从下载中 hashMap 移除
+ */
+ public synchronized void removeFromDataChangerAndResumeWaitingTask(DownloadEntity downloadEntity, boolean removeCompletely) {
+ NDataChanger.INSTANCE.getDownloadingTasks().remove(downloadEntity.getUrl());
+ if (removeCompletely) {
+ NDataChanger.INSTANCE.getDownloadEntries().remove(downloadEntity.getUrl());
+ }
+ for (DownloadEntity entry : NDataChanger.INSTANCE.getDownloadEntries().values()) {
+ if (DownloadStatus.waiting.equals(entry.getStatus())) {
+ // 刷新状态(从等待中到开始下载,状态应该变为继续下载)
+ entry.setStatus(DownloadStatus.resume);
+ startDownload(entry);
+
+ if (BuildConfig.DEBUG) {
+ Utils.log(NDownloadService.class.getSimpleName(), entry.getPackageName() + "==>" + entry.getStatus().getStatus());
+ }
+ return;
+ }
+ }
+ }
+
+ private void startForegroundIfNeeded(int notificationId) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ NotificationChannel channel = new NotificationChannel(SERVICE_CHANNEL_ID, "Halo Download", NotificationManager.IMPORTANCE_LOW);
+ NotificationManager manager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
+ manager.createNotificationChannel(channel);
+ Notification notification = new NotificationCompat.Builder(this, SERVICE_CHANNEL_ID)
+ .setSmallIcon(com.lightgame.R.drawable.ic_download_notification)
+ .build();
+
+ if (mForegroundNotificationManager != null) {
+ mForegroundNotificationManager.notify(notificationId, notification);
+ }
+ }
+ }
+
+ private void stopForegroundIfNeeded(int notificationId) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ if (mForegroundNotificationManager != null) {
+ mForegroundNotificationManager.cancel(notificationId);
+ }
+ }
+ }
+
+ /**
+ * 获取 0 以外的随机 int 数值
+ */
+ private int getNextIntExcludeZero() {
+ int randomNumber = new Random().nextInt();
+ if (randomNumber != 0) {
+ return randomNumber;
+ } else {
+ return getNextIntExcludeZero();
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/gh/ndownload/NHttpClient.kt b/app/src/main/java/com/gh/ndownload/NHttpClient.kt
new file mode 100644
index 0000000000..b78593684d
--- /dev/null
+++ b/app/src/main/java/com/gh/ndownload/NHttpClient.kt
@@ -0,0 +1,31 @@
+package com.gh.ndownload
+
+import android.text.TextUtils
+import com.lg.download.httpclient.DefaultHttpClient
+import com.lightgame.download.HttpDnsManager
+
+class NHttpClient : DefaultHttpClient() {
+
+ override fun addHeader(url: String?, meta: HashMap?) {
+ super.addHeader(url, meta)
+
+ mConnection.setRequestProperty(HttpDnsManager.APP_VERSION, HttpDnsManager.metaMap[HttpDnsManager.APP_VERSION])
+ mConnection.setRequestProperty(HttpDnsManager.CHANNEL, HttpDnsManager.metaMap[HttpDnsManager.CHANNEL])
+ mConnection.setRequestProperty(HttpDnsManager.GID, HttpDnsManager.metaMap[HttpDnsManager.GID])
+ mConnection.setRequestProperty(HttpDnsManager.USER_ID, HttpDnsManager.metaMap[HttpDnsManager.USER_ID])
+ mConnection.setRequestProperty(HttpDnsManager.IMEI, HttpDnsManager.metaMap[HttpDnsManager.IMEI])
+ mConnection.setRequestProperty(HttpDnsManager.OAID, HttpDnsManager.metaMap[HttpDnsManager.OAID])
+ mConnection.setRequestProperty(HttpDnsManager.TOKEN, HttpDnsManager.metaMap[HttpDnsManager.TOKEN])
+ mConnection.setRequestProperty(HttpDnsManager.IS_OVERWRITE, HttpDnsManager.metaMap[HttpDnsManager.IS_OVERWRITE])
+
+ val isEmulator = meta?.get("is_emulator")
+ val isForcedRealName = meta?.get("force_real_name")
+ if (!TextUtils.isEmpty(isForcedRealName) && "false" == isForcedRealName) {
+ mConnection.setRequestProperty("force", isForcedRealName)
+ }
+ if (!TextUtils.isEmpty(isEmulator)) {
+ mConnection.setRequestProperty("simulator", isEmulator)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/vspace/HomeRecentVGameViewHolder.kt b/app/src/main/java/com/gh/vspace/HomeRecentVGameViewHolder.kt
index ce112c3b92..a5e4895682 100644
--- a/app/src/main/java/com/gh/vspace/HomeRecentVGameViewHolder.kt
+++ b/app/src/main/java/com/gh/vspace/HomeRecentVGameViewHolder.kt
@@ -188,6 +188,7 @@ class HomeRecentVGameAdapter(context: Context) : DiffUtilAdapter(
DownloadStatus.uncertificated,
DownloadStatus.unqualified,
DownloadStatus.notfound,
+ DownloadStatus.diskisfull,
DownloadStatus.unavailable,
DownloadStatus.overflow -> {
binding.root.setOnClickListener {
diff --git a/app/src/main/java/com/gh/vspace/VArchiveHelper.kt b/app/src/main/java/com/gh/vspace/VArchiveHelper.kt
index b59303f2f8..d15a0cb6bb 100644
--- a/app/src/main/java/com/gh/vspace/VArchiveHelper.kt
+++ b/app/src/main/java/com/gh/vspace/VArchiveHelper.kt
@@ -100,7 +100,7 @@ object VArchiveHelper {
.setHttpClient(DefaultHttpClient())
.setDownloadThreadSize(2)
.setDownloadListener(DownloadMessageHandler)
- .setDownloadExecutor(AppExecutor.ioExecutor)
+ .setDownloadExecutor(AppExecutor.downloadExecutor)
.build()
)
}
diff --git a/app/src/main/java/com/gh/vspace/VDownloadManagerAdapter.kt b/app/src/main/java/com/gh/vspace/VDownloadManagerAdapter.kt
index 3b4640a62c..2329399b52 100644
--- a/app/src/main/java/com/gh/vspace/VDownloadManagerAdapter.kt
+++ b/app/src/main/java/com/gh/vspace/VDownloadManagerAdapter.kt
@@ -499,6 +499,7 @@ class VDownloadManagerAdapter(
DownloadStatus.timeout,
DownloadStatus.neterror,
DownloadStatus.subscribe,
+ DownloadStatus.diskisfull,
DownloadStatus.overflow -> {
btnText = context.getString(R.string.resume)
downloadDes.visibility = View.VISIBLE
diff --git a/app/src/main/java/com/gh/vspace/VGameItemData.kt b/app/src/main/java/com/gh/vspace/VGameItemData.kt
index 2b97be3b77..3f74d40e92 100644
--- a/app/src/main/java/com/gh/vspace/VGameItemData.kt
+++ b/app/src/main/java/com/gh/vspace/VGameItemData.kt
@@ -55,6 +55,7 @@ data class VGameItemData(
DownloadStatus.cancel,
DownloadStatus.timeout,
DownloadStatus.neterror,
+ DownloadStatus.diskisfull,
DownloadStatus.hijack,
DownloadStatus.uncertificated,
DownloadStatus.unqualified,
@@ -62,6 +63,8 @@ data class VGameItemData(
DownloadStatus.unavailable,
DownloadStatus.overflow -> {
controlText = "重试"
+ shouldShowMask = true
+ shouldShowControlTv = true
}
else -> {
// do nothing
diff --git a/app/src/main/java/com/gh/vspace/VSpaceDialogFragment.kt b/app/src/main/java/com/gh/vspace/VSpaceDialogFragment.kt
index 67ba0bb576..f221204b96 100644
--- a/app/src/main/java/com/gh/vspace/VSpaceDialogFragment.kt
+++ b/app/src/main/java/com/gh/vspace/VSpaceDialogFragment.kt
@@ -183,6 +183,7 @@ class VSpaceDialogFragment : BaseDraggableDialogFragment() {
overflow,
timeout,
neterror,
+ diskisfull,
waiting,
subscribe -> {
downloadBtn.setText(R.string.waiting)
diff --git a/app/src/main/java/com/gh/vspace/VSpaceLoadingFragment.kt b/app/src/main/java/com/gh/vspace/VSpaceLoadingFragment.kt
index 374630c8b4..7a027c2c16 100644
--- a/app/src/main/java/com/gh/vspace/VSpaceLoadingFragment.kt
+++ b/app/src/main/java/com/gh/vspace/VSpaceLoadingFragment.kt
@@ -48,6 +48,7 @@ class VSpaceLoadingFragment : BaseFragment() {
hijack,
notfound,
neterror,
+ diskisfull,
overflow -> requireActivity().finish()
unqualified -> {
ToastUtils.toast("暂不支持未成年人下载")
diff --git a/app/src/main/java/com/halo/assistant/HaloApp.java b/app/src/main/java/com/halo/assistant/HaloApp.java
index eac1d7100e..e931f2532b 100644
--- a/app/src/main/java/com/halo/assistant/HaloApp.java
+++ b/app/src/main/java/com/halo/assistant/HaloApp.java
@@ -69,6 +69,7 @@ import com.gh.gamecenter.receiver.NetworkStateReceiver;
import com.gh.vspace.VHelper;
import com.github.piasy.biv.BigImageViewer;
import com.github.piasy.biv.loader.fresco.FrescoImageLoader;
+import com.lg.ndownload.DownloadDbManager;
import com.lightgame.utils.Utils;
import com.llew.huawei.verifier.LoadedApkHuaWei;
import com.shuyu.gsyvideoplayer.cache.CacheFactory;
@@ -218,6 +219,8 @@ public class HaloApp extends MultiDexApplication {
// 异步初始化 SP
SPUtils.getString("");
+
+ DownloadDbManager.init(this);
});
RxJavaPlugins.setIoSchedulerHandler(scheduler -> AppExecutor.INSTANCE.getCachedScheduler());
diff --git a/app/src/main/res/layout/activity_editor_insert_game.xml b/app/src/main/res/layout/activity_editor_insert_game.xml
index ece4c9b7f8..013cf9a008 100644
--- a/app/src/main/res/layout/activity_editor_insert_game.xml
+++ b/app/src/main/res/layout/activity_editor_insert_game.xml
@@ -26,7 +26,7 @@
android:layout_height="wrap_content"
android:background="@color/background"
android:gravity="center"
- app:layout_behavior=".common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
+ app:layout_behavior="com.gh.gamecenter.common.view.FixAppBarLayoutBehavior">
"Wifi"
- ConnectivityManager.TYPE_WIMAX -> "WifiMax"
+ ConnectivityManager.TYPE_WIFI -> "WIFI"
+ ConnectivityManager.TYPE_WIMAX -> "WIMAX"
ConnectivityManager.TYPE_MOBILE -> {
val telephonyManager = application.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
if (telephonyManager.simState != TelephonyManager.SIM_STATE_READY) return "unknown"
when (telephonyManager.networkType) {
// Unknown
- TelephonyManager.NETWORK_TYPE_UNKNOWN -> "Cellular - Unknown"
+ TelephonyManager.NETWORK_TYPE_UNKNOWN -> "unknown"
// Cellular Data–2G
TelephonyManager.NETWORK_TYPE_EDGE, TelephonyManager.NETWORK_TYPE_GPRS, TelephonyManager.NETWORK_TYPE_CDMA,
- TelephonyManager.NETWORK_TYPE_IDEN, TelephonyManager.NETWORK_TYPE_1xRTT -> "Cellular - 2G"
+ TelephonyManager.NETWORK_TYPE_IDEN, TelephonyManager.NETWORK_TYPE_1xRTT -> "2G"
// Cellular Data–3G
TelephonyManager.NETWORK_TYPE_UMTS, TelephonyManager.NETWORK_TYPE_HSDPA, TelephonyManager.NETWORK_TYPE_HSPA,
TelephonyManager.NETWORK_TYPE_HSPAP, TelephonyManager.NETWORK_TYPE_HSUPA, TelephonyManager.NETWORK_TYPE_EVDO_0,
- TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyManager.NETWORK_TYPE_EVDO_B -> "Cellular - 3G"
+ TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyManager.NETWORK_TYPE_EVDO_B -> "3G"
// Cellular Data–4G
- TelephonyManager.NETWORK_TYPE_LTE -> "Cellular - 4G"
- else -> "Cellular - Unknown Generation"
+ TelephonyManager.NETWORK_TYPE_LTE -> "4G"
+ TelephonyManager.NETWORK_TYPE_NR -> "5G"
+ else -> "unknown"
}
}
diff --git a/module_common/src/main/java/com/gh/gamecenter/common/utils/DeviceUtils.java b/module_common/src/main/java/com/gh/gamecenter/common/utils/DeviceUtils.java
index ae6b67ff85..7cbd5b1295 100644
--- a/module_common/src/main/java/com/gh/gamecenter/common/utils/DeviceUtils.java
+++ b/module_common/src/main/java/com/gh/gamecenter/common/utils/DeviceUtils.java
@@ -149,6 +149,9 @@ public class DeviceUtils {
case TelephonyManager.NETWORK_TYPE_LTE:
status = "4G";
break;
+ case TelephonyManager.NETWORK_TYPE_NR:
+ status = "5G";
+ break;
default:
status = "未知";
break;
diff --git a/module_common/src/main/java/com/gh/gamecenter/common/utils/Extensions.kt b/module_common/src/main/java/com/gh/gamecenter/common/utils/Extensions.kt
index 53aa9e6af2..2109cd9632 100644
--- a/module_common/src/main/java/com/gh/gamecenter/common/utils/Extensions.kt
+++ b/module_common/src/main/java/com/gh/gamecenter/common/utils/Extensions.kt
@@ -69,6 +69,7 @@ import okhttp3.RequestBody
import org.json.JSONArray
import org.json.JSONObject
import java.lang.reflect.ParameterizedType
+import java.io.*
import java.net.URI
import java.util.*
import java.util.concurrent.TimeUnit
@@ -413,6 +414,25 @@ fun Context.showRegulationTestDialogIfNeeded(action: (() -> Unit)) {
}
}
+/**
+ * Serializable 相关
+ */
+fun Serializable.deepClone(): T? {
+ Utils.log("深复制对象 $this")
+ return try {
+ val baos = ByteArrayOutputStream()
+ val oos = ObjectOutputStream(baos)
+ oos.writeObject(this)
+ val bais = ByteArrayInputStream(baos.toByteArray())
+ val ois = ObjectInputStream(bais)
+ ois.readObject() as T
+ } catch (e: IOException) {
+ null
+ } catch (e: ClassNotFoundException) {
+ null
+ }
+}
+
/**
* 在限定 interval 里只触发一次 action
*/
diff --git a/module_common/src/main/java/com/gh/gamecenter/common/utils/PermissionHelper.kt b/module_common/src/main/java/com/gh/gamecenter/common/utils/PermissionHelper.kt
index cab57313b4..53ffe7bc0e 100644
--- a/module_common/src/main/java/com/gh/gamecenter/common/utils/PermissionHelper.kt
+++ b/module_common/src/main/java/com/gh/gamecenter/common/utils/PermissionHelper.kt
@@ -17,6 +17,7 @@ import com.alibaba.android.arouter.launcher.ARouter
import com.gh.gamecenter.common.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.RouteConsts
+import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.provider.IActivationProvider
import com.gh.gamecenter.core.provider.IAppProvider
import com.gh.gamecenter.core.provider.IDirectProvider
@@ -102,12 +103,14 @@ object PermissionHelper {
.subscribe { permission ->
when {
permission.granted -> {
- emptyCallback.onCallback()
- SPUtils.setBoolean(Constants.SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION, false)
-
// 获得存储权限后刷新 gid 避免下载仍需实名
- (ARouter.getInstance().build(RouteConsts.provider.app)
- .navigation() as? IAppProvider)?.refreshGid()
+ (ARouter.getInstance().build(RouteConsts.provider.app).navigation() as? IAppProvider)?.refreshGid()
+
+ // 延迟 100ms 确保能够正常获取到 gid
+ AppExecutor.uiExecutor.executeWithDelay({
+ emptyCallback.onCallback()
+ }, 100)
+ SPUtils.setBoolean(Constants.SP_USER_HAS_PERMANENTLY_DENIED_STORAGE_PERMISSION, false)
}
permission.shouldShowRequestPermissionRationale -> {
// do nothing
diff --git a/module_core/src/main/java/com/gh/gamecenter/core/AppExecutor.kt b/module_core/src/main/java/com/gh/gamecenter/core/AppExecutor.kt
index 64bbd95b9b..f3173d99b4 100644
--- a/module_core/src/main/java/com/gh/gamecenter/core/AppExecutor.kt
+++ b/module_core/src/main/java/com/gh/gamecenter/core/AppExecutor.kt
@@ -60,6 +60,10 @@ object AppExecutor {
)
}
+ val downloadExecutor: ExecutorService by lazy {
+ Executors.newCachedThreadPool(GHThreadFactory("GH_DOWNLOAD_THREAD"))
+ }
+
val cachedScheduler by lazy { Schedulers.from(ioExecutor) }
class MainThreadExecutor : Executor {
diff --git a/module_core/src/main/java/com/gh/gamecenter/core/provider/IPkgProvider.kt b/module_core/src/main/java/com/gh/gamecenter/core/provider/IPkgProvider.kt
new file mode 100644
index 0000000000..e296ee8fb9
--- /dev/null
+++ b/module_core/src/main/java/com/gh/gamecenter/core/provider/IPkgProvider.kt
@@ -0,0 +1,9 @@
+package com.gh.gamecenter.core.provider
+
+import com.alibaba.android.arouter.facade.template.IProvider
+
+interface IPkgProvider : IProvider {
+
+ fun requestPkgConfig(configId: String, onConfigReceived: (config: T) -> Unit)
+
+}
\ No newline at end of file
diff --git a/module_pkg/.gitignore b/module_pkg/.gitignore
new file mode 100644
index 0000000000..42afabfd2a
--- /dev/null
+++ b/module_pkg/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/module_pkg/build.gradle b/module_pkg/build.gradle
new file mode 100644
index 0000000000..335b198c04
--- /dev/null
+++ b/module_pkg/build.gradle
@@ -0,0 +1,87 @@
+if (isRelease.toBoolean()) {
+ apply plugin: 'com.android.library'
+} else {
+ apply plugin: 'com.android.application'
+}
+apply plugin: 'org.jetbrains.kotlin.android'
+apply plugin: 'kotlin-kapt'
+apply plugin: 'kotlin-parcelize'
+
+android {
+ compileSdkVersion rootProject.ext.compileSdkVersion
+
+ defaultConfig {
+ if (!isRelease.toBoolean()) {
+ applicationId "com.gh.pkg"
+ multiDexEnabled true
+ }
+ minSdk rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ versionCode rootProject.ext.versionCode
+ versionName rootProject.ext.versionName
+
+ buildConfigField "String", "API_HOST", "\"${API_HOST}\""
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ sourceSets {
+ main {
+ if (isRelease.toBoolean()) {
+ manifest.srcFile 'src/main/AndroidManifest.xml'
+ java {
+ exclude 'manifest/**'
+ }
+ } else {
+ java {
+ srcDirs = ['src/main/java', "src/pkg/java"]
+ }
+ manifest.srcFile 'src/main/manifest/AndroidManifest.xml'
+ res.srcDirs = ['src/main/res','src/pkg/res']
+ }
+ }
+ }
+
+ kapt {
+ arguments {
+ arg("AROUTER_MODULE_NAME", project.name)
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+
+ buildTypes {
+ debug {
+ if (!isRelease.toBoolean()) {
+ buildConfigField "String", "DEV_API_HOST", "\"${DEV_API_HOST}\""
+ }
+ }
+
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+
+ if (!isRelease.toBoolean()) {
+ buildConfigField "String", "DEV_API_HOST", "\"${API_HOST}\""
+ }
+ }
+ }
+
+}
+
+dependencies {
+ implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
+ kapt "com.alibaba:arouter-compiler:$arouterVersion"
+ if (!isRelease.toBoolean()) {
+ implementation "androidx.multidex:multidex:${multiDex}"
+ }
+
+ compileOnly(project(path: ":module_common"))
+}
\ No newline at end of file
diff --git a/module_pkg/proguard-rules.pro b/module_pkg/proguard-rules.pro
new file mode 100644
index 0000000000..817f2247a0
--- /dev/null
+++ b/module_pkg/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
+
+-renamesourcefileattribute SourceFile
+# Keep Attribute
+-keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod,SourceFile,LineNumberTable
\ No newline at end of file
diff --git a/module_pkg/src/main/AndroidManifest.xml b/module_pkg/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..ec6c511cd2
--- /dev/null
+++ b/module_pkg/src/main/AndroidManifest.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/module_pkg/src/main/java/com/gh/gamecenter/pkg/HaloApp.kt b/module_pkg/src/main/java/com/gh/gamecenter/pkg/HaloApp.kt
new file mode 100644
index 0000000000..d53e9c0c2a
--- /dev/null
+++ b/module_pkg/src/main/java/com/gh/gamecenter/pkg/HaloApp.kt
@@ -0,0 +1,44 @@
+package com.gh.gamecenter.pkg
+
+import android.app.Application
+import android.content.res.Configuration
+import com.gh.gamecenter.core.iinterface.IApplication
+import com.google.auto.service.AutoService
+
+@AutoService(IApplication::class)
+class HaloApp : IApplication {
+
+ override fun attachBaseContext() {
+ // Do nothing
+ }
+
+ override fun onCreate(application: Application) {
+ mApp = application
+ }
+
+
+ override fun onLowMemory() {
+ // Do nothing
+ }
+
+ override fun onTerminate() {
+ // Do nothing
+ }
+
+ override fun onTrimMemory(level: Int) {
+ // Do nothing
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ // Do nothing
+ }
+
+ companion object {
+ private lateinit var mApp: Application
+
+ @JvmStatic
+ fun getInstance(): Application {
+ return mApp
+ }
+ }
+}
diff --git a/module_pkg/src/main/java/com/gh/gamecenter/pkg/PkgProviderImpl.kt b/module_pkg/src/main/java/com/gh/gamecenter/pkg/PkgProviderImpl.kt
new file mode 100644
index 0000000000..f120890b16
--- /dev/null
+++ b/module_pkg/src/main/java/com/gh/gamecenter/pkg/PkgProviderImpl.kt
@@ -0,0 +1,32 @@
+package com.gh.gamecenter.pkg
+
+import android.annotation.SuppressLint
+import android.content.Context
+import com.alibaba.android.arouter.facade.annotation.Route
+import com.gh.gamecenter.common.constant.RouteConsts
+import com.gh.gamecenter.common.entity.PkgConfigEntity
+import com.gh.gamecenter.core.provider.IPkgProvider
+import com.gh.gamecenter.pkg.retrofit.RetrofitManager
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+
+@Route(path = RouteConsts.provider.pkg, name = "PKG 暴露服务")
+class PkgProviderImpl : IPkgProvider {
+
+ @SuppressLint("CheckResult")
+ override fun requestPkgConfig(configId: String, onConfigReceived: (config: PkgConfigEntity) -> Unit) {
+ RetrofitManager.getInstance().api.getPkgConfig(configId)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe({
+ onConfigReceived.invoke(it)
+ }, {
+ it.printStackTrace()
+ })
+ }
+
+ override fun init(context: Context?) {
+ // Do nothing
+ }
+
+}
\ No newline at end of file
diff --git a/module_pkg/src/main/java/com/gh/gamecenter/pkg/retrofit/ApiService.kt b/module_pkg/src/main/java/com/gh/gamecenter/pkg/retrofit/ApiService.kt
new file mode 100644
index 0000000000..97d426ccb1
--- /dev/null
+++ b/module_pkg/src/main/java/com/gh/gamecenter/pkg/retrofit/ApiService.kt
@@ -0,0 +1,15 @@
+package com.gh.gamecenter.pkg.retrofit
+
+import com.gh.gamecenter.common.entity.PkgConfigEntity
+import io.reactivex.Single
+import retrofit2.http.*
+
+interface ApiService {
+
+ /**
+ * 获取推广包配置
+ */
+ @GET("pkg/{path}")
+ fun getPkgConfig(@Path("path") config: String): Single
+
+}
\ No newline at end of file
diff --git a/module_pkg/src/main/java/com/gh/gamecenter/pkg/retrofit/RetrofitManager.kt b/module_pkg/src/main/java/com/gh/gamecenter/pkg/retrofit/RetrofitManager.kt
new file mode 100644
index 0000000000..b9c11b65cf
--- /dev/null
+++ b/module_pkg/src/main/java/com/gh/gamecenter/pkg/retrofit/RetrofitManager.kt
@@ -0,0 +1,20 @@
+package com.gh.gamecenter.pkg.retrofit
+
+import com.gh.gamecenter.common.retrofit.BaseRetrofitManager
+import com.gh.gamecenter.common.utils.EnvHelper.getHost
+import com.gh.gamecenter.core.utils.SingletonHolder
+import com.gh.gamecenter.pkg.HaloApp
+
+class RetrofitManager private constructor() : BaseRetrofitManager() {
+
+ val api: ApiService
+
+ init {
+ val context = HaloApp.getInstance().applicationContext
+ val okHttpNormalConfig = getOkHttpConfig(context, 0, 2)
+ api = provideService(okHttpNormalConfig, getHost(), ApiService::class.java)
+ }
+
+ companion object : SingletonHolder(::RetrofitManager)
+
+}
\ No newline at end of file
diff --git a/module_pkg/src/main/manifest/AndroidManifest.xml b/module_pkg/src/main/manifest/AndroidManifest.xml
new file mode 100644
index 0000000000..7ad06ce800
--- /dev/null
+++ b/module_pkg/src/main/manifest/AndroidManifest.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/module_pkg/src/main/res/values/strings.xml b/module_pkg/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..b55f29d59c
--- /dev/null
+++ b/module_pkg/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ PKG
+
diff --git a/module_pkg/src/pkg/java/com/gh/gamecenter/pkg/PkgModuleApp.kt b/module_pkg/src/pkg/java/com/gh/gamecenter/pkg/PkgModuleApp.kt
new file mode 100644
index 0000000000..cf9c45b56a
--- /dev/null
+++ b/module_pkg/src/pkg/java/com/gh/gamecenter/pkg/PkgModuleApp.kt
@@ -0,0 +1,36 @@
+package com.gh.gamecenter.pkg
+
+import androidx.multidex.MultiDexApplication
+import com.alibaba.android.arouter.launcher.ARouter
+import com.gh.gamecenter.core.iinterface.IApplication
+import java.util.*
+
+class PkgModuleApp : MultiDexApplication() {
+
+ private val mApplicationList = ServiceLoader.load(IApplication::class.java, this.javaClass.classLoader)
+
+ override fun onCreate() {
+ super.onCreate()
+ initArouter()
+ mApp = this
+ for (application in mApplicationList) {
+ application.onCreate(this)
+ }
+ }
+
+ private fun initArouter() {
+ if (BuildConfig.DEBUG) { // 这两行必须写在init之前,否则这些配置在init过程中将无效
+ ARouter.openLog() // 打印日志
+ ARouter.openDebug() // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
+ }
+ ARouter.init(this) // 尽可能早,推荐在Application中初始化
+ }
+
+ companion object {
+ private lateinit var mApp: PkgModuleApp
+
+ fun getInstance(): PkgModuleApp {
+ return mApp
+ }
+ }
+}
\ No newline at end of file
diff --git a/module_pkg/src/pkg/java/com/gh/gamecenter/pkg/provider/AppProviderImpl.kt b/module_pkg/src/pkg/java/com/gh/gamecenter/pkg/provider/AppProviderImpl.kt
new file mode 100644
index 0000000000..36d617cca9
--- /dev/null
+++ b/module_pkg/src/pkg/java/com/gh/gamecenter/pkg/provider/AppProviderImpl.kt
@@ -0,0 +1,86 @@
+package com.gh.gamecenter.pkg.provider
+
+import android.app.Activity
+import android.app.Application
+import android.content.Context
+import com.alibaba.android.arouter.facade.annotation.Route
+import com.gh.gamecenter.common.constant.RouteConsts
+import com.gh.gamecenter.core.provider.IAppProvider
+import com.gh.gamecenter.core.provider.IFlavorProvider
+import com.gh.gamecenter.pkg.HaloApp
+import com.gh.gamecenter.pkg.R
+
+@Route(path = RouteConsts.provider.app, name = "Application暴露服务")
+class AppProviderImpl : IAppProvider {
+ override fun init(context: Context?) {
+ // Do nothing
+ }
+
+ override fun get(key: String, isRemove: Boolean): Any? {
+ return ""
+ }
+
+ override fun put(key: String, any: Any) {
+ // do nothing
+ }
+
+ override fun getAppName(): String {
+ return HaloApp.getInstance().getString(R.string.app_name)
+ }
+
+ override fun getGid(): String {
+ return ""
+ }
+
+ override fun refreshGid() {
+ // Do nothing
+ }
+
+ override fun getOaid(): String {
+ return ""
+ }
+
+ override fun getChannel(): String {
+ return ""
+ }
+
+ override fun setChannel(channel: String) {
+ // Do nothing
+ }
+
+ override fun getUserAgent(): String {
+ return ""
+ }
+
+ override fun getServerUserMark(): String {
+ return ""
+ }
+
+ override fun getDeviceRamSize(): Long {
+ return 0L
+ }
+
+ override fun getTemporaryLocalDeviceId(): String {
+ return ""
+ }
+
+ override fun getFlavorProvider(): IFlavorProvider {
+ return object : IFlavorProvider {
+ override fun getChannelStr(application: Application): String {
+ return ""
+ }
+
+ override fun init(application: Application, activity: Activity) {
+ // do nothing
+ }
+
+ override fun logEvent(content: String) {
+ // do nothing
+ }
+ }
+ }
+
+ override fun isUserAcceptPrivacyPolicy(context: Context): Boolean {
+ return true
+ }
+}
\ No newline at end of file
diff --git a/module_pkg/src/pkg/java/com/gh/gamecenter/pkg/view/PkgActivity.kt b/module_pkg/src/pkg/java/com/gh/gamecenter/pkg/view/PkgActivity.kt
new file mode 100644
index 0000000000..957baa097f
--- /dev/null
+++ b/module_pkg/src/pkg/java/com/gh/gamecenter/pkg/view/PkgActivity.kt
@@ -0,0 +1,15 @@
+package com.gh.gamecenter.pkg.view
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import com.gh.gamecenter.pkg.R
+
+class PkgActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContentView(R.layout.activity_pkg)
+ }
+
+}
\ No newline at end of file
diff --git a/module_pkg/src/pkg/res/layout/activity_pkg.xml b/module_pkg/src/pkg/res/layout/activity_pkg.xml
new file mode 100644
index 0000000000..95b55a35a0
--- /dev/null
+++ b/module_pkg/src/pkg/res/layout/activity_pkg.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ndownload b/ndownload
index 54cb6c0c32..89f0ede089 160000
--- a/ndownload
+++ b/ndownload
@@ -1 +1 @@
-Subproject commit 54cb6c0c32c89dd3b5827750a916fb43a70e6942
+Subproject commit 89f0ede089304dac02538dd58fb7c3d0f18a5004
diff --git a/scripts/meta_build.sh b/scripts/meta_build.sh
new file mode 100755
index 0000000000..3b6821b43a
--- /dev/null
+++ b/scripts/meta_build.sh
@@ -0,0 +1,119 @@
+#!/usr/bin/env bash
+# @author juntao
+# @2023.03.06
+
+git_sha=`git rev-parse --short HEAD`
+versionName=$(awk -v FS="versionName = " 'NF>1{print $2}' dependencies.gradle | sed "s/\"//g")
+versionCode=$(awk -v FS="versionCode = " 'NF>1{print $2}' dependencies.gradle | sed "s/\"//g")
+build_time=$(TZ=Asia/Shanghai date +'%Y-%m%d-%H%M')
+
+cwd=$(cd "$(dirname "$0")"; pwd)
+apk_release_path=""
+
+# 重置 app build.gradle
+git checkout app/build.gradle
+# 重置 module_common build.gradle
+git checkout module_common/build.gradle
+
+# 开启 mapping 上传
+if [[ "$OSTYPE" == "darwin"* ]]; then
+ sed -i '' '1 a plugins { id "io.sentry.android.gradle" version "2.1.5" }' app/build.gradle
+else
+ sed -i '1 a plugins { id "io.sentry.android.gradle" version "2.1.5" }' app/build.gradle
+fi
+
+./gradlew --stop
+./gradlew clean
+
+mkdir -p release/
+
+OPTIONS=$(getopt -o '' -l config_id:,sdk_platform:,sdk_version:,channel:,activate_reporting_ratio:,first_launch_jump:,output:,unix_timestamp:, -- "$@")
+
+eval set -- "$OPTIONS"
+
+while true; do
+ case "$1" in
+ --config_id) config_id="$2"; shift 2;;
+ --sdk_platform) sdk_platform="$2"; shift 2;;
+ --sdk_version) sdk_version="$2"; shift 2;;
+ --channel) channel="$2"; shift 2;;
+ --activate_reporting_ratio) activate_reporting_ratio="$2"; shift 2;;
+ --first_launch_jump) first_launch_jump="$2"; shift 2;;
+ --output) output="$2"; shift 2;;
+ --unix_timestamp) unix_timestamp="$2"; shift 2;;
+ --) shift; break;;
+ *) echo "Invalid option: $1" >&2; exit 1;;
+ esac
+done
+
+function updateChannelIfNeeded {
+ if [ "${channel}" != "" ]; then
+ java -jar ${cwd}/ApkChannelPackage.jar put -c $channel $1 release
+ rm $1
+ find . -type f -name "*.apk" -exec mv {} "${apk_release_path}" \;
+ fi
+}
+
+# 保存 output 文件名
+if [ "${output}" != "" ]; then
+ apk_release_path="$output"
+fi
+
+# 保存 config_id
+if [ "${config_id}" != "" ]; then
+ sed -i "s/String CONFIG_ID = \"\"/String CONFIG_ID = \"${config_id}\"/g" app/build.gradle
+fi
+
+# 保存 first_launch_jump
+if [ "${first_launch_jump}" != "" ]; then
+ sed -i "s/String FIRST_LAUNCH = \"\"/String FIRST_LAUNCH = \"${first_launch_jump}\"/g" app/build.gradle
+fi
+
+# 是否选择了 sdk 类型
+if [ "${sdk_platform}" != "" ]; then
+ # 头条包
+ if [ "${sdk_platform}" == "toutiao" ]; then
+ if [ "${activate_reporting_ratio}" == "" ]; then
+ activate_reporting_ratio="100"
+ fi
+ # 调整上报比例
+ sed -i "75i buildConfigField "\"int\"", "\"ACTIVATE_REPORTING_RATIO\"", \""${activate_reporting_ratio}"\"" app/build.gradle
+
+ if [ "${sdk_version}" == "5.3.0" ]; then
+ sed -i "s/bytedanceApplog = \"6.14.1\"/bytedanceApplog = \"${sdk_version}\"/g" dependencies.gradle
+ rm app/src/tea/java/com/gh/gamecenter/TeaHelper.kt
+ mv app/src/tea/java/com/gh/gamecenter/TeaHelper app/src/tea/java/com/gh/gamecenter/TeaHelper.kt
+ else
+ sed -i "s/bytedanceApplog = \"6.14.1\"/bytedanceApplog = \"${sdk_version}\"/g" dependencies.gradle
+ fi
+
+ ./gradlew aTR -I init.gradle
+
+ echo "${sdk_version}_${activate_reporting_ratio}_光环助手_${versionName}_${versionCode}_头条推广包_${git_sha}_${build_time}"
+
+ cp -R app/build/outputs/apk/tea/release/app-tea-release.apk "${apk_release_path}"
+ fi
+ # 广点通包
+ if [ "${sdk_platform}" == "guangdiantong" ]; then
+
+ # 广点通 SDK 执行 ASM 后处理后会有问题
+ ./gradlew aGR
+
+ echo "光环助手_${versionName}_${versionCode}_广点通推广包_${git_sha}_${build_time}"
+ cp -R app/build/outputs/apk/gdt/release/app-gdt-release.apk "${apk_release_path}"
+ fi
+ # 快手包
+ if [ "${sdk_platform}" == "kuaishou" ]; then
+ ./gradlew aKR -I init.gradle
+
+ echo "光环助手_${versionName}_${versionCode}_快手推广包_${git_sha}_${build_time}"
+ cp -R app/build/outputs/apk/kuaishou/release/app-kuaishou-release.apk "${apk_release_path}"
+ fi
+
+ updateChannelIfNeeded ${apk_release_path}
+fi
+
+# 重置 app build.gradle
+git checkout app/build.gradle
+# 重置 module_common build.gradle
+git checkout module_common/build.gradle
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 84a5824a14..0de61fc178 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -14,4 +14,5 @@ include ':ndownload'
include ':module_core_feature'
include ':module_lib'
include ':module_vpn'
+include ':module_pkg'
include ':module_sensors_data'