[dev_opt_2.15.0] patch升级代码提交

This commit is contained in:
renwj
2023-03-06 19:50:41 +08:00
parent 91547ae873
commit 3c58608ca6
55 changed files with 2100 additions and 156 deletions

View File

@@ -16,8 +16,10 @@ import com.mogo.eagle.core.data.deva.scene.SceneTAG
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
import com.mogo.eagle.core.function.api.devatools.IDevaToolsProvider
import com.mogo.eagle.core.function.api.devatools.apm.*
import com.mogo.eagle.core.function.api.devatools.download.*
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.zhjt.mogo_core_function_devatools.apm.*
import com.mogo.eagle.core.function.api.upgrade.*
import com.zhjt.mogo_core_function_devatools.badcase.BadCaseManager
import com.zhjt.mogo_core_function_devatools.badcase.consts.BadCaseConfig
import com.zhjt.mogo_core_function_devatools.binding.BindingCarManager.Companion.bindingCarManager
@@ -167,8 +169,8 @@ class DevaToolsProvider : IDevaToolsProvider {
iPCReportManager.showReportListWindow(context, isShow)
}
override fun downLoadPackage(downloadKey: String, downloadUrl: String) {
upgradeManager.downLoadPackage(mContext!!, downloadKey, downloadUrl)
override fun downLoadPackage(type: DownloadType, downloadKey: String, downloadUrl: String) {
upgradeManager.downLoadPackage(mContext!!,type, downloadKey, downloadUrl)
}
override fun updateUpgradeProgress() {
@@ -249,4 +251,8 @@ class DevaToolsProvider : IDevaToolsProvider {
override fun queryObuUpgrade(obuVersionName: String) {
bindingCarManager.queryObuUpgrade(obuVersionName)
}
override fun upgradeProvider(): IMoGoUpgradeProvider? {
return upgradeManager.upgradeProvider()
}
}

View File

@@ -162,8 +162,8 @@ class BindingCarManager : IMoGoAutopilotCarConfigListener {
* 查询app是否需要升级
*/
fun queryAppUpgrade() {
UpgradeAppNetWorkManager.getInstance()
.getAppUpgradeInfo(mContext, mAddress, role.toString() + "")
UpgradeAppNetWorkManager.instance
?.getAppUpgradeInfo(mContext, mAddress ?: "", role.toString() + "")
}

View File

@@ -7,6 +7,7 @@ import android.content.Context;
import com.mogo.cloud.passport.MoGoAiCloudClientConfig;
import com.mogo.commons.constants.HostConst;
import com.mogo.eagle.core.data.deva.bindingcar.UpgradeAppInfo;
import com.mogo.eagle.core.function.api.devatools.download.DownloadType;
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager;
import com.mogo.eagle.core.function.call.obu.CallerObuApiManager;
import com.mogo.eagle.core.network.MoGoRetrofitFactory;
@@ -58,7 +59,7 @@ public class ObuUpgradeAppNetWorkManager {
String sn = MoGoAiCloudClientConfig.getInstance().getSn();
CallerLogger.INSTANCE.d(M_BINDING + TAG, "getObuUpgradeInfo mac = " + mac + " ---sn = " + sn + " ---versionName = " + versionName);
UpgradeAppRequest request = new UpgradeAppRequest(sn, mac, "7");
UpgradeAppRequest request = new UpgradeAppRequest(sn, mac, "7", null, "0");
RequestBody requestBody = RequestBody.create(MediaType.get("application/json;charset=UTF-8"), GsonUtil.jsonFromObject(request));
mUpgradeApiService.getUpgradeInfo(requestBody)
.subscribeOn(Schedulers.io())
@@ -73,7 +74,7 @@ public class ObuUpgradeAppNetWorkManager {
if (info != null && info.result != null) {
CallerLogger.INSTANCE.d(M_BINDING + TAG, "getObuUpgradeInfo appFileName = " + info.result.getAppFileName() + " ----url = " + info.result.getAppUrl() + " ----name = " + info.result.getVersionName() + " --obuVersionName =" + versionName + " ---info.result = " + info.result);
if (!String.valueOf(info.result.getVersionName()).equals(versionName)) { //判断是否下载,当文件名称不一致的时候,就下载
CallerDevaToolsManager.INSTANCE.downLoadPackage(info.result.getAppFileName(), info.result.getAppUrl());
CallerDevaToolsManager.INSTANCE.downLoadPackage(DownloadType.OBU, info.result.getAppFileName(), info.result.getAppUrl());
}
} else {
CallerLogger.INSTANCE.d(M_BINDING + TAG, "getObuUpgradeInfo onNext info == null");

View File

@@ -1,111 +0,0 @@
package com.zhjt.mogo_core_function_devatools.upgrade;
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_BINDING;
import android.content.Context;
import com.elegant.utils.UiThreadHandler;
import com.mogo.cloud.passport.MoGoAiCloudClientConfig;
import com.mogo.commons.constants.HostConst;
import com.mogo.eagle.core.data.deva.bindingcar.UpgradeAppInfo;
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager;
import com.mogo.eagle.core.network.MoGoRetrofitFactory;
import com.mogo.eagle.core.network.utils.GsonUtil;
import com.mogo.eagle.core.utilcode.breakpoint.Config;
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
import com.mogo.eagle.core.utilcode.util.AppUtils;
import com.mogo.eagle.core.utilcode.util.FileUtils;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;
/**
* @author lixiaopeng
* @description 获取升级信息
* @since: 3/25/22
*/
public class UpgradeAppNetWorkManager {
private static volatile UpgradeAppNetWorkManager requestNoticeManager;
private final UpgradeApiService mUpgradeApiService;
private static final String TAG = "Upgrade";
private UpgradeAppNetWorkManager() {
mUpgradeApiService = MoGoRetrofitFactory.getInstance(HostConst.getHost())
.create(UpgradeApiService.class);
}
public static UpgradeAppNetWorkManager getInstance() {
if (requestNoticeManager == null) {
synchronized (UpgradeAppNetWorkManager.class) {
if (requestNoticeManager == null) {
requestNoticeManager = new UpgradeAppNetWorkManager();
}
}
}
return requestNoticeManager;
}
/**
* 获取app升级信息
*/
public void getAppUpgradeInfo(Context context, String mac, String screenType) {
// String sn = "X20202203105S688HZ";
// String mac = "48:b0:2d:3a:bc:78";
String sn = MoGoAiCloudClientConfig.getInstance().getSn();
int versionCode = AppUtils.getAppVersionCode();
CallerLogger.INSTANCE.d(M_BINDING + TAG, "getAppUpgradeInfo mac = " + mac + "---type = " + screenType + "---sn = " + sn + "---versionCode =" + versionCode);
UpgradeAppRequest request = new UpgradeAppRequest(sn, mac, screenType);
RequestBody requestBody = RequestBody.create(MediaType.get("application/json;charset=UTF-8"), GsonUtil.jsonFromObject(request));
mUpgradeApiService.getUpgradeInfo(requestBody)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<UpgradeAppInfo>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull UpgradeAppInfo info) {
if (info != null && info.result != null) {
CallerLogger.INSTANCE.d(M_BINDING + TAG, "UpgradeAppInfo url = " + info.result.getAppUrl() + "----code = " + info.result.getVersionCode() + "--versionCode =" + versionCode + "--info.result = " + info.result);
if (info.result.getVersionCode() > versionCode) {
CallerHmiManager.INSTANCE.showUpgradeDialog(info.result.getAppUrl().substring(info.result.getAppUrl().lastIndexOf("/")+1), info.result.getAppUrl(), info.result.getInstallTitle(), info.result.getInstallContent(), info.result.getInstallType());
} else {
deleteApkFile();
}
} else {
CallerLogger.INSTANCE.d(M_BINDING + TAG, "UpgradeAppInfo onNext info == null");
deleteApkFile();
}
}
@Override
public void onError(Throwable e) {
deleteApkFile();
}
@Override
public void onComplete() {
}
});
}
/**
* 删除APK 相关的文件
*/
private void deleteApkFile(){
UiThreadHandler.post(new Runnable() {
@Override
public void run() {
FileUtils.delete(Config.downLoadPath);
}
});
}
}

View File

@@ -0,0 +1,150 @@
package com.zhjt.mogo_core_function_devatools.upgrade
import android.content.*
import android.text.*
import android.util.*
import com.elegant.utils.UiThreadHandler
import com.mogo.cloud.passport.*
import com.mogo.commons.constants.*
import com.mogo.eagle.core.data.config.*
import com.mogo.eagle.core.data.deva.bindingcar.*
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager.upgradeProvider
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager.showUpgradeDialog
import com.mogo.eagle.core.function.call.patch.CallerPatchManager.addPatchInfo
import com.mogo.eagle.core.function.call.patch.CallerPatchManager.isPatchAccept
import com.mogo.eagle.core.network.*
import com.mogo.eagle.core.network.utils.*
import com.mogo.eagle.core.utilcode.breakpoint.*
import com.mogo.eagle.core.utilcode.breakpoint.Config
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
import com.mogo.eagle.core.utilcode.mogo.logger.scene.*
import com.mogo.eagle.core.utilcode.util.*
import com.mogo.eagle.core.utilcode.util.FileUtils
import io.reactivex.*
import io.reactivex.android.schedulers.*
import io.reactivex.disposables.*
import io.reactivex.schedulers.*
import kotlinx.coroutines.*
import okhttp3.*
/**
* @author lixiaopeng
* @description 获取升级信息
* @since: 3/25/22
*/
class UpgradeAppNetWorkManager private constructor() {
private val mUpgradeApiService: UpgradeApiService = MoGoRetrofitFactory.getInstance(HostConst.getHost()).create(UpgradeApiService::class.java)
private val scope by lazy { CoroutineScope(Dispatchers.IO + SupervisorJob()) }
/**
* 获取app升级信息
*/
fun getAppUpgradeInfo(context: Context?, mac: String, screenType: String) { // String sn = "X20202203105S688HZ";
// String mac = "48:b0:2d:3a:bc:78";
var mac = mac
var screenType = screenType
var sn = MoGoAiCloudClientConfig.getInstance().sn
val versionCode = AppUtils.getAppVersionCode()
val versionName = AppUtils.getAppVersionName()
d(SceneConstant.M_BINDING + TAG, "getAppUpgradeInfo mac = $mac---type = $screenType---sn = $sn---versionCode =$versionCode---versionName =$versionName")
//TODO renwj undo start
mac = "48:b0:2d:4d:31:7f"
sn = null
screenType = "10" //TODO renwj undo end
val request = UpgradeAppRequest(sn, mac, screenType, versionName, "1")
val requestBody = RequestBody.create(MediaType.get("application/json;charset=UTF-8"), GsonUtil.jsonFromObject(request))
mUpgradeApiService.getUpgradeInfo(requestBody).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : Observer<UpgradeAppInfo> {
override fun onSubscribe(d: Disposable) {}
override fun onNext(info: UpgradeAppInfo) {
doUpgrade(info)
}
override fun onError(e: Throwable) {
deleteApkFile()
}
override fun onComplete() {}
})
}
private fun doUpgrade(info: UpgradeAppInfo) {
scope.launch {
if (info.result != null) {
val versionCode = AppUtils.getAppVersionCode()
d(SceneConstant.M_BINDING + TAG, "UpgradeAppInfo url = " + info.result.appUrl + "----code = " + info.result.versionCode + "--versionCode =" + versionCode + "--info.result = " + info.result)
if (info.result.versionCode > versionCode) {
val patchInfo = info.result.patchInfo
var downloadUrl: String = info.result.appUrl
val provider = upgradeProvider()
if (patchInfo != null) {
val f1 = FunctionBuildConfig.isSupportPatchUpgrade
if (!f1) {
Log.d("ApkInstaller", "当前版本配置不支持增量升级...")
}
val f2 = provider != null
if (f1 && !f2) {
Log.d("ApkInstaller", "provider为空...")
}
var f3 = true
if (f2 && provider != null && !provider.isNeedGoPatchUpgrade()) {
Log.d("ApkInstaller", "上次patch升级失败了...")
f3 = false
}
var f4 = true
if (f3) {
provider?.recordUpgradeRecord(patchInfo.targetVersion, patchInfo.targetMd5, 1)
provider?.recordSourceMd5CheckStart()
f4 = isPatchAccept(Utils.getApp(), patchInfo.sourceMd5, patchInfo.patchSize.toLong())
if (!f4) {
Log.d("ApkInstaller", "旧版本apk包的md5与服务端上的md5不匹配...")
provider?.recordSourceMd5CheckFailed("旧apk的md5与服务端的md5不一致:[server_md5: ${patchInfo.sourceMd5}, apk_md5: ${AppUtils.getAppApkMd5()}]")
} else {
provider?.recordSourceMd5CheckSuccess()
}
}
if (f4) {
downloadUrl = patchInfo.patchDownloadUrl
addPatchInfo(patchInfo)
}
} else {
provider?.recordUpgradeRecord(info.result.versionName, null, 0)
}
withContext(Dispatchers.Main) {
showUpgradeDialog(downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1), downloadUrl, info.result.installTitle, info.result.installContent, info.result.installType)
}
} else {
deleteApkFile()
}
} else {
d(SceneConstant.M_BINDING + TAG, "UpgradeAppInfo onNext info == null")
deleteApkFile()
}
}
}
/**
* 删除APK 相关的文件
*/
private fun deleteApkFile() {
UiThreadHandler.post { FileUtils.delete(Config.downLoadPath) }
}
companion object {
@Volatile private var requestNoticeManager: UpgradeAppNetWorkManager? = null
private const val TAG = "Upgrade"
val instance: UpgradeAppNetWorkManager?
get() {
if (requestNoticeManager == null) {
synchronized(UpgradeAppNetWorkManager::class.java) {
if (requestNoticeManager == null) {
requestNoticeManager = UpgradeAppNetWorkManager()
}
}
}
return requestNoticeManager
}
}
}

View File

@@ -1,20 +1,27 @@
package com.zhjt.mogo_core_function_devatools.upgrade;
import java.io.Serializable;
/**
* @author lixiaopeng
* @description 获取app升级信息
* @since: 11/15/21
*/
public class UpgradeAppRequest {
public class UpgradeAppRequest implements Serializable {
private String mac;
private String sn;
private String screenType;
private String currentVersion;
public UpgradeAppRequest( String sn, String mac, String screenType) {
private String patchStatus;
public UpgradeAppRequest( String sn, String mac, String screenType, String versionName, String patchStatus) {
this.sn = sn;
this.mac = mac;
this.screenType = screenType;
this.currentVersion = versionName;
this.patchStatus = patchStatus;
}
public String getSn() {
@@ -41,4 +48,19 @@ public class UpgradeAppRequest {
this.screenType = screenType;
}
public String getVersionName() {
return currentVersion;
}
public void setVersionName(String versionName) {
this.currentVersion = versionName;
}
public String getPatchStatus() {
return patchStatus;
}
public void setPatchStatus(String patchStatus) {
this.patchStatus = patchStatus;
}
}

View File

@@ -2,11 +2,18 @@ package com.zhjt.mogo_core_function_devatools.upgrade
import android.app.NotificationManager
import android.content.Context
import android.content.pm.PackageInstaller
import com.mogo.eagle.core.data.constants.MogoServicePaths
import com.mogo.eagle.core.function.api.upgrade.IMoGoUpgradeProvider
import com.mogo.eagle.core.function.call.base.CallerBase
import androidx.core.app.NotificationCompat
import com.elegant.utils.UiThreadHandler
import com.mogo.eagle.core.data.obu.MogoObuConst
import com.mogo.eagle.core.function.api.devatools.IMogoDevaToolsUpgradeListener
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsUpgradeListenerManager
import com.mogo.eagle.core.function.api.devatools.download.*
import com.mogo.eagle.core.function.api.devatools.download.DownloadType.*
import com.mogo.eagle.core.function.call.devatools.*
import com.mogo.eagle.core.function.call.patch.CallerPatchManager
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager.updateStatusBarDownloadView
import com.mogo.eagle.core.function.call.obu.CallerObuApiManager
import com.mogo.eagle.core.utilcode.breakpoint.Config
@@ -15,10 +22,15 @@ import com.mogo.eagle.core.utilcode.breakpoint.callback.IDownload
import com.mogo.eagle.core.utilcode.breakpoint.utils.DownloadUtils
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
import com.mogo.eagle.core.utilcode.mogo.logger.Logger
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_DEVA
import com.mogo.eagle.core.utilcode.util.AppUtils
import com.mogo.eagle.core.utilcode.util.ZipUtils
import com.mogo.eagle.core.utilcode.util.*
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import kotlinx.coroutines.*
import java.io.IOException
import java.util.concurrent.ConcurrentHashMap
class UpgradeManager : IDownload {
@@ -34,16 +46,24 @@ class UpgradeManager : IDownload {
private var map: Map<String, String>? = null
private var mDownloadFileName: String? = null
fun downLoadPackage(context: Context, downloadKey: String,downloadUrl: String) {
CallerLogger.d("${SceneConstant.M_OBU}${MogoObuConst.TAG_UPGRADE_OBU}", "UpgradeManager downLoadPackage = " + downloadUrl?.contains(".zip") + "----downloadKey = $downloadKey ---downloadUrl = $downloadUrl")
if (downloadUrl?.contains(".zip")) {
private val upgradeProvider: IMoGoUpgradeProvider? by lazy { CallerBase.getApiInstance(IMoGoUpgradeProvider::class.java, MogoServicePaths.PATH_UPGRADE_TYPE_API) }
private val types by lazy { ConcurrentHashMap<String, DownloadType>() }
fun upgradeProvider(): IMoGoUpgradeProvider? = upgradeProvider
fun downLoadPackage(context: Context, type: DownloadType, downloadKey: String, downloadUrl: String) {
CallerLogger.d("${SceneConstant.M_OBU}${MogoObuConst.TAG_UPGRADE_OBU}", "UpgradeManager downLoadPackage = " + downloadUrl.contains(".zip") + "----downloadKey = $downloadKey ---downloadUrl = $downloadUrl")
if (type == OBU) {
mDownloadFileName = downloadKey
}
types[downloadUrl] = type
DownloadUtils.downLoad(
context,
downloadUrl,
if (downloadUrl?.contains(".zip")) Config.downLoadObuPath else Config.downLoadPath,
if (type == OBU) Config.downLoadObuPath else Config.downLoadPath,
downloadKey,
5,
this
@@ -60,6 +80,12 @@ class UpgradeManager : IDownload {
CallerDevaToolsUpgradeListenerManager.invokeUpgradeStart(it)
}
}
val type = types[downloadUrl]
if (type == PATCH || type == APK) {
runBlocking {
CallerDevaToolsManager.upgradeProvider()?.recordDownloadStart()
}
}
}
}
@@ -90,8 +116,118 @@ class UpgradeManager : IDownload {
}
override fun onFinished(downloadUrl: String?, threadBean: ThreadBean?) {
if (downloadUrl != null) { //TODO 需要判断是否是apk文件
AppUtils.installApp(Config.downLoadPath + downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1))
if (downloadUrl != null) {
val type = types[downloadUrl]
if (type == APK || type == PATCH) {
val patchInfo = CallerPatchManager.getPatchInfoByUrl(downloadUrl)
if (patchInfo != null) {
var isPatchInstallFailed = false
var patchInstallFailedReason = ""
CallerPatchManager.removePatchInfoByUrl(downloadUrl)
val patch = File(Config.downLoadPath, downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1))
if (patch.exists()) {
try {
val newApk = File(Utils.getApp().getExternalFilesDir(null), "patch/merged/${SimpleDateFormat("yyyy_MM_dd_HH_mm_ss", Locale.ROOT).format(Date()) }.apk")
val dir = newApk.parentFile
if (dir != null && !dir.exists()) {
val ret = dir.mkdirs()
if (!ret) {
Logger.w(TAG, "create new apk path failed.")
throw AssertionError("创建目录失败")
}
}
if (dir != null){
try {
if (newApk.exists()) {
newApk.delete()
}
} catch (t: Throwable) {
t.printStackTrace()
}
runBlocking {
upgradeProvider?.recordInstallApplyPatchStart()
}
var ret = CallerPatchManager.applyPatch(Utils.getApp(), patch, newApk)
if (!ret) {
runBlocking {
upgradeProvider?.recordInstallApplyPatchFailed("合成patch失败")
}
Logger.w(TAG, "合成patch失败...")
throw AssertionError("合成patch失败...")
} else {
runBlocking {
upgradeProvider?.recordInstallApplyPatchSuccess()
upgradeProvider?.recordTargetMd5CheckStart()
}
ret = CallerPatchManager.checkMd5ForMergedApk(Utils.getApp(), newApk, patchInfo.targetMd5)
if (!ret) {
runBlocking {
upgradeProvider?.recordTargetMd5CheckFailed("合成后的apk的md5与服务端上的目标版本的md5不一致:[server_target_md5: ${patchInfo.targetMd5}, merged_md5: ${Md5Util.getMd5FromFile(newApk)}]")
}
Logger.w(TAG, "md5校验失败...")
throw AssertionError("md5校验失败:[target:${patchInfo.targetMd5}]")
} else {
Logger.w(TAG, "md5校验成功...")
runBlocking {
upgradeProvider?.recordTargetMd5CheckSuccess()
upgradeProvider?.recordInstallStart()
}
ApkInstaller.installApp(Utils.getApp(), newApk) { code, reason ->
if (code != PackageInstaller.STATUS_SUCCESS) {
upgradeProvider?.also {
try {
newApk.delete()
} catch (t: Throwable) {
t.printStackTrace()
}
try {
patch.delete()
} catch (t: Throwable) {
t.printStackTrace()
}
runBlocking {
it.recordInstallFailed(code, reason)
}
}
}
}
}
}
}
} catch (t: Throwable) {
t.printStackTrace()
isPatchInstallFailed = true
patchInstallFailedReason = t.message ?: "安装失败: code -1"
}
} else {
patchInstallFailedReason = "patch下载后文件不存在"
isPatchInstallFailed = true
}
if (isPatchInstallFailed) {
runBlocking {
CallerDevaToolsManager.upgradeProvider()?.recordInstallFailed(ApkInstaller.INSTALL_CODE_INVLID, patchInstallFailedReason)
}
}
} else {
val apkPath = Config.downLoadPath + downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1)
val apk = File(apkPath)
ApkInstaller.installApp(Utils.getApp(), apk) { code, reason ->
if (code != PackageInstaller.STATUS_SUCCESS) {
upgradeProvider?.also { itx ->
try {
apk.delete()
} catch (t: Throwable) {
t.printStackTrace()
}
runBlocking {
itx.recordInstallFailed(code, reason)
}
}
}
}
}
}
}
if (downloadUrl != null) {
if (map.isNullOrEmpty()) {
@@ -114,6 +250,12 @@ class UpgradeManager : IDownload {
CallerDevaToolsUpgradeListenerManager.invokeUpgradeError(it, errorMsg ?: "未知错误")
}
}
val type = types[downloadUrl]
if (type == APK || type == PATCH) {
runBlocking {
CallerDevaToolsManager.upgradeProvider()?.recordDownloadFailed(errorMsg ?: "下载失败")
}
}
}
}

View File

@@ -0,0 +1,185 @@
package com.zhjt.mogo_core_function_devatools.upgrade.provider
import android.content.*
import android.content.pm.PackageInstaller
import com.alibaba.android.arouter.facade.annotation.Route
import com.mogo.eagle.core.data.constants.MogoServicePaths
import com.mogo.eagle.core.function.api.upgrade.*
import com.mogo.eagle.core.utilcode.util.*
import com.zhjt.mogo_core_function_devatools.upgrade.provider.db.UpgradeDbHelper
import com.zhjt.mogo_core_function_devatools.upgrade.provider.db.vo.*
@Route(path = MogoServicePaths.PATH_UPGRADE_TYPE_API)
class MoGoUpgradeProviderImpl: IMoGoUpgradeProvider {
override fun init(context: Context?) {}
override suspend fun recordUpgradeRecord(newVersion: String, newMd5: String?, type: Int) {
UpgradeDbHelper.insertUpgradeRecord(UpgradeRecord(AppUtils.getAppVersionName(), newVersion, AppUtils.getAppApkMd5(), newMd5, if (type == 0) UpgradeType.FULL else UpgradeType.PATCH))
}
override suspend fun recordDownloadStart() {
UpgradeDbHelper.insertDownloadRecord(DownloadRecord(version = AppUtils.getAppVersionName(), status = DownloadStatus.DownloadStart))
}
override suspend fun recordDownloadFailed(error: String) {
UpgradeDbHelper.insertDownloadRecord(DownloadRecord(version = AppUtils.getAppVersionName(), status = DownloadStatus.DownloadFailed, failReason = error))
}
override suspend fun recordDownloadSuccess() {
UpgradeDbHelper.insertDownloadRecord(DownloadRecord(version = AppUtils.getAppVersionName(), status = DownloadStatus.DownloadComplete))
}
override suspend fun recordInstallStart() {
UpgradeDbHelper.insertInstallRecord(InstallRecord(version = AppUtils.getAppVersionName(), status = InstallStatus.InstallStart))
}
override suspend fun recordSourceMd5CheckStart() {
UpgradeDbHelper.insertInstallRecord(InstallRecord(version = AppUtils.getAppVersionName(), status = InstallStatus.SourceMd5CheckStart))
}
override suspend fun recordSourceMd5CheckFailed(error: String) {
UpgradeDbHelper.insertInstallRecord(InstallRecord(version = AppUtils.getAppVersionName(), status = InstallStatus.SourceMd5CheckFailed, failReason = error))
}
override suspend fun recordSourceMd5CheckSuccess() {
UpgradeDbHelper.insertInstallRecord(InstallRecord(version = AppUtils.getAppVersionName(), status = InstallStatus.SourceMd5CheckSuccess))
}
override suspend fun recordInstallApplyPatchStart() {
UpgradeDbHelper.insertInstallRecord(InstallRecord(version = AppUtils.getAppVersionName(), status = InstallStatus.ApplyPatchStart))
}
override suspend fun recordInstallApplyPatchFailed(error: String) {
UpgradeDbHelper.insertInstallRecord(InstallRecord(version = AppUtils.getAppVersionName(), status = InstallStatus.ApplyPatchFailed, failReason = error))
}
override suspend fun recordInstallApplyPatchSuccess() {
UpgradeDbHelper.insertInstallRecord(InstallRecord(version = AppUtils.getAppVersionName(), status = InstallStatus.ApplyPatchSuccess))
}
override suspend fun recordTargetMd5CheckStart() {
UpgradeDbHelper.insertInstallRecord(InstallRecord(version = AppUtils.getAppVersionName(), status = InstallStatus.TargetMd5CheckStart))
}
override suspend fun recordTargetMd5CheckFailed(error: String) {
UpgradeDbHelper.insertInstallRecord(InstallRecord(version = AppUtils.getAppVersionName(), status = InstallStatus.TargetMd5CheckFailed, failReason = error))
}
override suspend fun recordTargetMd5CheckSuccess() {
UpgradeDbHelper.insertInstallRecord(InstallRecord(version = AppUtils.getAppVersionName(), status = InstallStatus.TargetMd5CheckSuccess))
}
override suspend fun recordInstallFailed(code: Int, error: String) {
UpgradeDbHelper.insertInstallRecord(InstallRecord(version = AppUtils.getAppVersionName(), status = InstallStatus.InstallFailed, code = code, failReason = error))
}
override suspend fun isUpgradeSuccessByPatch(): Boolean {
val record = UpgradeDbHelper.getUpgradeRecordOnlyByTarget(AppUtils.getAppVersionName())
return record?.toVersion == AppUtils.getAppVersionName() && record.type == UpgradeType.PATCH
}
override suspend fun isUpgradeSuccessByFull(): Boolean {
val record = UpgradeDbHelper.getUpgradeRecordOnlyByTarget(AppUtils.getAppVersionName())
return record?.toVersion == AppUtils.getAppVersionName() && record.type == UpgradeType.FULL
}
override suspend fun removeRecordByTargetVersion(version: String) {
UpgradeDbHelper.deleteRecordByTargetVersion(version)
}
override suspend fun removeRecordBySourceVersion(version: String) {
UpgradeDbHelper.deleteRecordBySourceVersion(version)
}
override suspend fun getFullUpgradeFailedReason(): Map<String,List<Pair<Int, String>>>? {
if (isUpgradeSuccessByFull()) {
return null
}
if (isUpgradeSuccessByPatch()) {
return null
}
val full = UpgradeDbHelper.getUpgradeRecordFull(AppUtils.getAppVersionName())
if (full == null || full.upgrade?.type != UpgradeType.FULL) {
return null
}
val map = HashMap<String, List<Pair<Int, String>>>()
full.downloads?.takeIf {
it.isNotEmpty()
}?.sortedBy {
it.status.ordinal
}?.map {
it.status.ordinal to (it.failReason ?: "")
}?.also {
map["download"] = it
}
full.installs?.takeIf {
it.isNotEmpty()
}?.sortedBy {
it.status.ordinal
}?.map {
it.status.ordinal to (it.failReason ?: "")
}?.also {
map["install"] = it
}
return map
}
override suspend fun getPatchUpgradeFailedReason(): Map<String,List<Pair<Int, String>>>? {
if (isUpgradeSuccessByFull()) {
return null
}
if (isUpgradeSuccessByPatch()) {
return null
}
val full = UpgradeDbHelper.getUpgradeRecordFull(AppUtils.getAppVersionName())
if (full == null || full.upgrade?.type != UpgradeType.PATCH) {
return null
}
val map = HashMap<String, List<Pair<Int, String>>>()
full.downloads?.takeIf {
it.isNotEmpty()
}?.sortedBy {
it.status.ordinal
}?.map {
it.status.ordinal to (it.failReason ?: "")
}?.also {
map["download"] = it
}
full.installs?.takeIf {
it.isNotEmpty()
}?.sortedBy {
it.status.ordinal
}?.map {
it.status.ordinal to (it.failReason ?: "")
}?.also {
map["install"] = it
}
return map
}
override suspend fun hasUpgradeRecord(): Boolean {
return UpgradeDbHelper.hasRecords()
}
override suspend fun isNeedGoPatchUpgrade(): Boolean {
val reasons = getPatchUpgradeFailedReason()
return reasons?.let { itx ->
itx["install"]?.takeIf {
it.isNotEmpty()
}?.let {
val last = it.last()
val ordinal = last.first
val status = InstallStatus.values().find { v -> v.ordinal == ordinal }
if (status != null && status.isReallyFailed()) {
val code = UpgradeDbHelper.getUpgradeRecordFull(AppUtils.getAppVersionName())?.installs?.find { s -> s.status == status }?.code
code != PackageInstaller.STATUS_FAILURE_INVALID &&
code != PackageInstaller.STATUS_FAILURE_CONFLICT &&
code != PackageInstaller.STATUS_FAILURE &&
code != PackageInstaller.STATUS_FAILURE_STORAGE
} else {
true
}
} ?: true
} ?: true
}
}

View File

@@ -0,0 +1,20 @@
package com.zhjt.mogo_core_function_devatools.upgrade.provider.db
import androidx.room.Database
import androidx.room.RoomDatabase
import com.zhjt.mogo_core_function_devatools.upgrade.provider.db.dao.IUpgradeRecordDao
import com.zhjt.mogo_core_function_devatools.upgrade.provider.db.vo.DownloadRecord
import com.zhjt.mogo_core_function_devatools.upgrade.provider.db.vo.InstallRecord
import com.zhjt.mogo_core_function_devatools.upgrade.provider.db.vo.UpgradeRecord
@Database(
entities = [
UpgradeRecord::class,
DownloadRecord::class,
InstallRecord::class],
version = 1,
exportSchema = false)
internal abstract class UpgradeRecordDb: RoomDatabase() {
abstract fun dao(): IUpgradeRecordDao
}

View File

@@ -0,0 +1,69 @@
package com.zhjt.mogo_core_function_devatools.upgrade.provider.db
import androidx.room.Room
import com.mogo.eagle.core.utilcode.util.Utils
import com.zhjt.mogo_core_function_devatools.upgrade.provider.db.vo.DownloadRecord
import com.zhjt.mogo_core_function_devatools.upgrade.provider.db.vo.InstallRecord
import com.zhjt.mogo_core_function_devatools.upgrade.provider.db.vo.UpgradeRecord
import com.zhjt.mogo_core_function_devatools.upgrade.provider.db.vo.UpgradeRecordFull
internal object UpgradeDbHelper {
private val db by lazy {
Room.databaseBuilder(Utils.getApp(), UpgradeRecordDb::class.java, "upgrade_records").build()
}
suspend fun insertUpgradeRecord(record: UpgradeRecord): Long = try {
db.dao().insertUpgradeRecord(record)
} catch (e: Exception) {
e.printStackTrace()
-1
}
suspend fun insertDownloadRecord(record: DownloadRecord): Long = try {
db.dao().insertDownloadRecord(record)
} catch (e: Exception) {
e.printStackTrace()
-1
}
suspend fun insertInstallRecord(record: InstallRecord): Long = try {
db.dao().insertInstallRecord(record)
} catch (e: Exception) {
e.printStackTrace()
-1
}
suspend fun getUpgradeRecordFull(oldVersion: String): UpgradeRecordFull? = try {
db.dao().getUpgradeRecordFull(oldVersion)
} catch (e: Exception) {
e.printStackTrace()
null
}
suspend fun getUpgradeRecordOnlyByTarget(targetVersion: String): UpgradeRecord? = try {
db.dao().getUpgradeRecordOnlyByTarget(targetVersion)
} catch (e: Exception) {
e.printStackTrace()
null
}
suspend fun deleteRecordBySourceVersion(version: String) = try {
db.dao().deleteRecordBySourceVersion(version)
} catch (e: Exception) {
e.printStackTrace()
}
suspend fun deleteRecordByTargetVersion(version: String) = try {
db.dao().deleteRecordByTargetVersion(version)
} catch (e: Exception) {
e.printStackTrace()
}
suspend fun hasRecords() = try {
db.dao().getRecordCount() > 0
} catch (e: Exception) {
e.printStackTrace()
false
}
}

View File

@@ -0,0 +1,44 @@
package com.zhjt.mogo_core_function_devatools.upgrade.provider.db.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy.IGNORE
import androidx.room.OnConflictStrategy.REPLACE
import androidx.room.Query
import androidx.room.Transaction
import com.zhjt.mogo_core_function_devatools.upgrade.provider.db.vo.*
@Dao
internal interface IUpgradeRecordDao {
@Insert(onConflict = REPLACE)
@Transaction
suspend fun insertUpgradeRecord(record: UpgradeRecord): Long
@Insert(onConflict = IGNORE)
@Transaction
suspend fun insertDownloadRecord(record: DownloadRecord): Long
@Insert(onConflict = IGNORE)
@Transaction
suspend fun insertInstallRecord(record: InstallRecord): Long
@Query("SELECT * FROM upgrade_record WHERE f_v = :oldVersion")
@Transaction
suspend fun getUpgradeRecordFull(oldVersion: String): UpgradeRecordFull?
@Query("SELECT * FROM upgrade_record WHERE f_v = :oldVersion")
suspend fun getUpgradeRecordOnly(oldVersion: String): UpgradeRecord?
@Query("SELECT * FROM upgrade_record WHERE t_v = :toVersion")
suspend fun getUpgradeRecordOnlyByTarget(toVersion: String): UpgradeRecord?
@Query("DELETE FROM upgrade_record WHERE f_v = :version")
suspend fun deleteRecordBySourceVersion(version: String)
@Query("DELETE FROM upgrade_record WHERE t_v = :version")
suspend fun deleteRecordByTargetVersion(version: String)
@Query("SELECT COUNT(*) FROM upgrade_record")
suspend fun getRecordCount(): Int
}

View File

@@ -0,0 +1,187 @@
package com.zhjt.mogo_core_function_devatools.upgrade.provider.db.vo
import androidx.room.*
import androidx.room.ForeignKey.CASCADE
import com.mogo.eagle.core.utilcode.util.*
@Entity(tableName = "upgrade_record")
data class UpgradeRecord(
@PrimaryKey
@ColumnInfo(name = "f_v")
var fromVersion: String,
@ColumnInfo(name = "t_v")
var toVersion: String,
@ColumnInfo(name = "f_m")
var fromMD5: String?,
@ColumnInfo(name = "t_m")
var toMD5: String?,
@field:TypeConverters(UpgradeType::class)
var type: UpgradeType
)
enum class UpgradeType {
FULL,
PATCH;
companion object {
@JvmStatic
@TypeConverter
fun to(value: Int?) = values().find { it.ordinal == value }
@JvmStatic
@TypeConverter
fun from(type: UpgradeType?) = type?.ordinal
}
}
@Entity(
tableName = "download_record",
foreignKeys = [
ForeignKey(
entity = UpgradeRecord::class,
parentColumns = arrayOf("f_v"),
childColumns = arrayOf("d_v"),
deferred = true,
onDelete = CASCADE
)],
indices = [
Index(value = arrayOf("id"), unique = true),
Index(value = arrayOf("d_v"))
]
)
data class DownloadRecord(
@PrimaryKey(autoGenerate = true)
var id: Long = 0,
@ColumnInfo(name = "d_v")
var version: String,
@field:TypeConverters(DownloadStatus::class)
var status: DownloadStatus,
@ColumnInfo(name = "reason")
var failReason: String? = null
)
enum class DownloadStatus {
DownloadStart,
DownloadFailed,
DownloadComplete;
companion object {
@JvmStatic
@TypeConverter
fun to(value: Int?) = values().find { it.ordinal == value }
@JvmStatic
@TypeConverter
fun from(type: DownloadStatus?) = type?.ordinal
}
}
@Entity(
tableName = "install_record",
foreignKeys = [ForeignKey(
entity = UpgradeRecord::class,
parentColumns = arrayOf("f_v"),
childColumns = arrayOf("i_v"),
deferred = true,
onDelete = CASCADE
)],
indices = [
Index(value = arrayOf("id"), unique = true),
Index(value = arrayOf("i_v"))
]
)
data class InstallRecord(
@PrimaryKey(autoGenerate = true)
var id: Long = 0,
@ColumnInfo(name = "i_v")
var version: String,
@field:TypeConverters(InstallStatus::class)
var status: InstallStatus,
@ColumnInfo(defaultValue = "${ApkInstaller.INSTALL_CODE_INVLID}")
var code: Int = 0,
@ColumnInfo(name = "reason")
var failReason: String? = null
)
enum class InstallStatus {
SourceMd5CheckStart,
SourceMd5CheckFailed,
SourceMd5CheckSuccess,
ApplyPatchStart,
ApplyPatchFailed,
ApplyPatchSuccess,
TargetMd5CheckStart,
TargetMd5CheckFailed,
TargetMd5CheckSuccess,
InstallStart,
InstallFailed,
InstallSuccess;
companion object {
@JvmStatic
@TypeConverter
fun to(value: Int?) = values().find { it.ordinal == value }
@JvmStatic
@TypeConverter
fun from(status: InstallStatus?) = status?.ordinal
}
fun isReallyFailed() = (this == SourceMd5CheckFailed || this == ApplyPatchFailed || this == TargetMd5CheckFailed)
}
class UpgradeRecordFull {
@Embedded
var upgrade: UpgradeRecord? = null
@Relation(
parentColumn = "f_v",
entityColumn = "d_v",
entity = DownloadRecord::class
)
var downloads: List<DownloadRecord>? = null
@Relation(
parentColumn = "f_v",
entityColumn = "i_v",
entity = InstallRecord::class
)
var installs: List<InstallRecord>? = null
}