[dev_opt_2.15.0] patch升级代码提交
This commit is contained in:
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -162,8 +162,8 @@ class BindingCarManager : IMoGoAutopilotCarConfigListener {
|
||||
* 查询app是否需要升级
|
||||
*/
|
||||
fun queryAppUpgrade() {
|
||||
UpgradeAppNetWorkManager.getInstance()
|
||||
.getAppUpgradeInfo(mContext, mAddress, role.toString() + "")
|
||||
UpgradeAppNetWorkManager.instance
|
||||
?.getAppUpgradeInfo(mContext, mAddress ?: "", role.toString() + "")
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ?: "下载失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ dependencies {
|
||||
implementation rootProject.ext.dependencies.cicle_indicator
|
||||
implementation rootProject.ext.dependencies.koomnative
|
||||
implementation rootProject.ext.dependencies.koomxhook
|
||||
|
||||
implementation project(':core:function-impl:mogo-core-function-patch')
|
||||
api project(':test:crashreport-apmbyte')
|
||||
compileOnly project(':core:function-impl:mogo-core-function-datacenter')
|
||||
implementation project(':foudations:mogo-commons')
|
||||
|
||||
@@ -4,10 +4,16 @@ import android.content.Context
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import com.mogo.eagle.core.function.api.devatools.download.DownloadType.APK
|
||||
import com.mogo.eagle.core.function.api.devatools.download.DownloadType.PATCH
|
||||
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager
|
||||
import com.mogo.eagle.core.function.call.patch.*
|
||||
import com.mogo.eagle.core.function.hmi.R
|
||||
import com.mogo.eagle.core.utilcode.util.ToastUtils
|
||||
import com.mogo.eagle.core.function.hmi.dialog.BaseFloatDialog
|
||||
import com.mogo.eagle.core.utilcode.kotlin.*
|
||||
import kotlinx.coroutines.*
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
||||
* @brief APP升级提示弹框
|
||||
@@ -18,7 +24,7 @@ class UpgradeAppDialog(context: Context) : BaseFloatDialog(context), LifecycleOb
|
||||
companion object{
|
||||
private const val TAG = "UpgradeAppDialog"
|
||||
|
||||
private var upgradeAppDialog: UpgradeAppDialog? = null
|
||||
private var upgradeAppDialog: WeakReference<UpgradeAppDialog>? = null
|
||||
|
||||
fun show(context: Context?,
|
||||
name: String,
|
||||
@@ -27,10 +33,12 @@ class UpgradeAppDialog(context: Context) : BaseFloatDialog(context), LifecycleOb
|
||||
content: String,
|
||||
installType: String) {
|
||||
context?.let {
|
||||
if (upgradeAppDialog == null) {
|
||||
upgradeAppDialog = UpgradeAppDialog(it)
|
||||
var dialog = upgradeAppDialog?.get()
|
||||
if (dialog == null) {
|
||||
dialog = UpgradeAppDialog(it)
|
||||
upgradeAppDialog = WeakReference(dialog)
|
||||
}
|
||||
upgradeAppDialog?.let { dialog ->
|
||||
dialog.let { d ->
|
||||
if (dialog.isShowing) {
|
||||
return
|
||||
}
|
||||
@@ -78,10 +86,19 @@ class UpgradeAppDialog(context: Context) : BaseFloatDialog(context), LifecycleOb
|
||||
/**
|
||||
* 去下载
|
||||
*/
|
||||
fun downloadApp() {
|
||||
private fun downloadApp() {
|
||||
ToastUtils.showLong("开始下载APK,稍后可前往downloads文件夹查看,通知栏查看下载进度")
|
||||
tag?.let { downloadUrl?.let { it1 -> CallerDevaToolsManager.downLoadPackage(it, it1) } }
|
||||
|
||||
tag?.let {
|
||||
downloadUrl?.let { url ->
|
||||
window?.decorView?.scope?.launch {
|
||||
if (CallerPatchManager.getPatchInfoByUrl(url) != null) {
|
||||
CallerDevaToolsManager.downLoadPackage(PATCH, it, url)
|
||||
} else {
|
||||
CallerDevaToolsManager.downLoadPackage(APK, it, url)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
|
||||
|
||||
1
core/function-impl/mogo-core-function-patch/.gitignore
vendored
Normal file
1
core/function-impl/mogo-core-function-patch/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
180
core/function-impl/mogo-core-function-patch/build.gradle
Normal file
180
core/function-impl/mogo-core-function-patch/build.gradle
Normal file
@@ -0,0 +1,180 @@
|
||||
import org.gradle.api.execution.*
|
||||
import com.android.build.gradle.tasks.*
|
||||
import com.android.build.gradle.*
|
||||
import org.gradle.process.*
|
||||
import org.gradle.api.invocation.*
|
||||
|
||||
plugins {
|
||||
id 'com.android.library'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
id 'com.alibaba.arouter'
|
||||
id 'kotlin-kapt'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.android.compileSdkVersion
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.android.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.android.targetSdkVersion
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles "consumer-rules.pro"
|
||||
|
||||
//ARouter apt 参数
|
||||
kapt {
|
||||
useBuildCache = false
|
||||
arguments {
|
||||
arg("AROUTER_MODULE_NAME", project.getName())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
jniLibs.srcDirs = ['jniLibs']
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation rootProject.ext.dependencies.androidxccorektx
|
||||
implementation rootProject.ext.dependencies.androidxappcompat
|
||||
implementation rootProject.ext.dependencies.material
|
||||
androidTestImplementation rootProject.ext.dependencies.androidxjunit
|
||||
androidTestImplementation rootProject.ext.dependencies.junit
|
||||
implementation rootProject.ext.dependencies.lancetx_runtime
|
||||
implementation rootProject.ext.dependencies.arouter
|
||||
kapt rootProject.ext.dependencies.aroutercompiler
|
||||
if (Boolean.valueOf(USE_MAVEN_PACKAGE)) {
|
||||
implementation rootProject.ext.dependencies.moduleservice
|
||||
implementation rootProject.ext.dependencies.mogo_core_data
|
||||
implementation rootProject.ext.dependencies.mogo_core_utils
|
||||
implementation rootProject.ext.dependencies.mogo_core_function_api
|
||||
implementation rootProject.ext.dependencies.mogo_core_res
|
||||
} else {
|
||||
implementation project(':core:mogo-core-data')
|
||||
implementation project(':core:mogo-core-utils')
|
||||
implementation project(':core:mogo-core-function-api')
|
||||
implementation project(':core:mogo-core-res')
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.gradle.taskGraph.whenReady { TaskExecutionGraph graph ->
|
||||
def tasks = graph.allTasks.findAll { t0 ->
|
||||
t0 instanceof PackageApplication
|
||||
}
|
||||
def app = rootProject.subprojects.find {
|
||||
it.plugins.hasPlugin("com.android.application")
|
||||
}
|
||||
if (app != null) {
|
||||
def android = (AppExtension)app.extensions.findByName("android")
|
||||
def signConfig = android.signingConfigs.getByName("release")
|
||||
if (signConfig != null && isOnlineReleaseBuild(gradle)) {
|
||||
if (tasks != null) {
|
||||
tasks.forEach { t1 ->
|
||||
t1.doLast { t2 ->
|
||||
def packageTask = (PackageApplication) t2
|
||||
def outDir = packageTask.outputDirectory
|
||||
def apkNames = packageTask.apkNames
|
||||
if (apkNames != null && apkNames.size() > 0) {
|
||||
apkNames.forEach { apkName ->
|
||||
def apk = new File(outDir, apkName)
|
||||
def lp = new File(rootProject.rootDir, "local.properties")
|
||||
if (apk.exists() && lp.exists()) {
|
||||
def p = new Properties()
|
||||
lp.withInputStream { instr ->
|
||||
p.load(instr)
|
||||
}
|
||||
def sdkDir = p.getProperty('sdk.dir')
|
||||
def apkSigner = new File(sdkDir, isWindows() ? "build-tools${File.separator}${android.buildToolsVersion}${File.separator}apksigner.bat" : "build-tools${File.separator}${android.buildToolsVersion}${File.separator}apksigner")
|
||||
|
||||
def newApk = new File(outDir, "normalized_" + apkName)
|
||||
def outApk = new File(outDir, "signed_" + apkName)
|
||||
def workDir = new File(projectDir, "shell")
|
||||
def shell = isMac() ? ".${File.separator}macos${File.separator}ApkNormalized" : (isLinux() ? ".${File.separator}linux64${File.separator}ApkNormalized" : ".${File.separator}windows64${File.separator}ApkNormalized.exe")
|
||||
println "***** apk:${apk.name} -> 开始执行apk文件格式对齐 *****"
|
||||
ExecResult result = exec {
|
||||
workingDir workDir
|
||||
commandLine shell, "${apk.absolutePath}", "${newApk.absolutePath}"
|
||||
}
|
||||
def code = result.exitValue
|
||||
if (code == 0) {
|
||||
println "***** apk:${apk.name} -> apk文件格式对齐完成 *****"
|
||||
}
|
||||
|
||||
println "***** apk:${newApk.name} -> 对文件格式对齐后的apk重新签名 *****"
|
||||
result = exec {
|
||||
workingDir apkSigner.parentFile
|
||||
commandLine ".${File.separator}${apkSigner.name}", "sign", "-v",
|
||||
"--out", "${outApk.absolutePath}",
|
||||
"--ks", "${signConfig.storeFile.absolutePath}",
|
||||
"--ks-key-alias", "${signConfig.keyAlias}",
|
||||
"--ks-pass", "pass:${signConfig.storePassword}",
|
||||
"--key-pass", "pass:${signConfig.keyPassword}",
|
||||
"--pass-encoding", "utf-8",
|
||||
"${newApk.absolutePath}"
|
||||
}
|
||||
code = result.exitValue
|
||||
if (code == 0) {
|
||||
println "***** apk:${newApk.name} -> 签名成功 *****"
|
||||
}
|
||||
println "***** 正在删除临时文件 *****"
|
||||
try {
|
||||
newApk.delete()
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace()
|
||||
throw t
|
||||
}
|
||||
try {
|
||||
outApk.renameTo(apk)
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace()
|
||||
throw t
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isWindows() {
|
||||
return System.getProperty("os.name").toLowerCase().contains('windows')
|
||||
}
|
||||
|
||||
static boolean isLinux() {
|
||||
return System.getProperty("os.name").toLowerCase().contains('linux')
|
||||
}
|
||||
|
||||
static boolean isMac() {
|
||||
return System.getProperty("os.name").toLowerCase().contains('mac')
|
||||
}
|
||||
|
||||
static boolean isOnlineReleaseBuild(Gradle g) {
|
||||
StringBuilder sb = new StringBuilder()
|
||||
for (String s : g.startParameter.taskNames) {
|
||||
sb.append(s)
|
||||
}
|
||||
String buildScript = sb.toString().toLowerCase()
|
||||
return buildScript.endsWith("release") && buildScript.contains("online")
|
||||
}
|
||||
|
||||
|
||||
BIN
core/function-impl/mogo-core-function-patch/jniLibs/arm64-v8a/libapkpatch.so
Executable file
BIN
core/function-impl/mogo-core-function-patch/jniLibs/arm64-v8a/libapkpatch.so
Executable file
Binary file not shown.
BIN
core/function-impl/mogo-core-function-patch/jniLibs/armeabi-v7a/libapkpatch.so
Executable file
BIN
core/function-impl/mogo-core-function-patch/jniLibs/armeabi-v7a/libapkpatch.so
Executable file
Binary file not shown.
BIN
core/function-impl/mogo-core-function-patch/jniLibs/x86/libapkpatch.so
Executable file
BIN
core/function-impl/mogo-core-function-patch/jniLibs/x86/libapkpatch.so
Executable file
Binary file not shown.
BIN
core/function-impl/mogo-core-function-patch/jniLibs/x86_64/libapkpatch.so
Executable file
BIN
core/function-impl/mogo-core-function-patch/jniLibs/x86_64/libapkpatch.so
Executable file
Binary file not shown.
21
core/function-impl/mogo-core-function-patch/proguard-rules.pro
vendored
Normal file
21
core/function-impl/mogo-core-function-patch/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# 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
|
||||
BIN
core/function-impl/mogo-core-function-patch/shell/linux64/ApkNormalized
Executable file
BIN
core/function-impl/mogo-core-function-patch/shell/linux64/ApkNormalized
Executable file
Binary file not shown.
BIN
core/function-impl/mogo-core-function-patch/shell/macos/ApkNormalized
Executable file
BIN
core/function-impl/mogo-core-function-patch/shell/macos/ApkNormalized
Executable file
Binary file not shown.
BIN
core/function-impl/mogo-core-function-patch/shell/windows64/ApkNormalized.exe
Executable file
BIN
core/function-impl/mogo-core-function-patch/shell/windows64/ApkNormalized.exe
Executable file
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
package com.mogo.launcer.patch
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class) class ExampleInstrumentedTest {
|
||||
@Test fun useAppContext() { // Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.mogo.launcer.patch.test", appContext.packageName)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mogo.launcher.patch">
|
||||
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
|
||||
<application>
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileProvider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/provider_paths" />
|
||||
</provider>
|
||||
<meta-data android:name="SUPPORT_PATCH" android:value="1" />
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.github.sisong;
|
||||
|
||||
public class ApkPatch{
|
||||
|
||||
static {
|
||||
System.loadLibrary("apkpatch");
|
||||
}
|
||||
|
||||
// return TPatchResult, 0 is ok; patchFilePath file created by ZipDiff;
|
||||
public static native int patch(String oldApkPath,String patchFilePath,String outNewApkPath,
|
||||
long maxUncompressMemory,String tempUncompressFilePath,int threadNum);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.mogo.launcher.patch
|
||||
|
||||
import android.content.*
|
||||
import android.text.TextUtils
|
||||
import android.util.*
|
||||
import com.github.sisong.*
|
||||
import com.mogo.eagle.core.utilcode.util.AppUtils
|
||||
import com.mogo.launcher.patch.utils.*
|
||||
import java.io.File
|
||||
|
||||
internal object PatchManager {
|
||||
|
||||
private const val TAG = "PatchManager"
|
||||
fun isPatchAccept(context: Context, expectSourceMd5: String, patchSize: Long): Boolean {
|
||||
val apkMd5 = AppUtils.getAppApkMd5()
|
||||
if (TextUtils.isEmpty(apkMd5)) {
|
||||
return false
|
||||
}
|
||||
if (apkMd5 != expectSourceMd5) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun applyPatch(ctx: Context, patch: File, newApk: File): Boolean {
|
||||
val oldApkPath = ctx.packageManager.getPackageInfo(ctx.packageName, 0).applicationInfo.sourceDir
|
||||
if (TextUtils.isEmpty(oldApkPath)) {
|
||||
throw AssertionError("旧的apk文件的文件路径为空.")
|
||||
}
|
||||
val oldApk = File(oldApkPath)
|
||||
Log.d(TAG, "applyPatch -- 1 --:oldApk -> ${oldApk.absolutePath}, patch: -> ${patch.absolutePath}, newApk: ${newApk.absolutePath}")
|
||||
if (!oldApk.exists()) {
|
||||
throw AssertionError("旧的apk文件不存在, 文件所在路径:${oldApk.absolutePath}")
|
||||
}
|
||||
Log.d(TAG, "applyPatch -- 2 --")
|
||||
|
||||
if (!patch.exists()) {
|
||||
throw AssertionError("差分包文件不存在,文件所在路径:${patch.absolutePath}")
|
||||
}
|
||||
Log.d(TAG, "applyPatch -- 3 --")
|
||||
val newApkParent = newApk.parentFile
|
||||
if (newApkParent != null && !newApkParent.exists()) {
|
||||
val ret = newApkParent.mkdirs()
|
||||
if (!ret) {
|
||||
throw AssertionError("新包创建父目录失败")
|
||||
}
|
||||
}
|
||||
Log.d(TAG, "applyPatch -- 4 --")
|
||||
if (newApk.exists()) {
|
||||
newApk.delete()
|
||||
}
|
||||
if (newApkParent == null) {
|
||||
throw AssertionError("新包父目录为空")
|
||||
}
|
||||
Log.d(TAG, "applyPatch -- 5 --")
|
||||
val tempFilePath = File(ctx.getExternalFilesDir(null), "temp/temp.patch")
|
||||
|
||||
if (tempFilePath.exists()) {
|
||||
tempFilePath.delete()
|
||||
}
|
||||
tempFilePath.parentFile?.takeIf { !it.exists() }?.mkdirs()
|
||||
val result = ApkPatch.patch(oldApk.absolutePath, patch.absolutePath, newApk.absolutePath, 4 * 1024 * 1024, "", 4)
|
||||
Log.d(TAG, "applyPatch -- end ---: result: $result")
|
||||
if (result != 0) {
|
||||
throw AssertionError("文件合成失败")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun checkMd5ForMergedApk(mergedApk: File, expectNewApkMd5: String): Boolean {
|
||||
if (!mergedApk.exists()) {
|
||||
return false
|
||||
}
|
||||
val md5 = Md5Util.getMd5FromFile(mergedApk)
|
||||
if (md5 != expectNewApkMd5) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.mogo.launcher.patch.provider
|
||||
|
||||
import android.content.*
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.mogo.eagle.core.data.constants.MogoServicePaths
|
||||
import com.mogo.eagle.core.function.api.patch.*
|
||||
import com.mogo.launcher.patch.*
|
||||
import java.io.*
|
||||
|
||||
|
||||
@Route(path = MogoServicePaths.PATH_PATCH_UPGRADE)
|
||||
class MoGoPatchProviderImpl : IMoGoPatchProvider {
|
||||
|
||||
|
||||
override fun isPatchAccept(context: Context, expectOldApkMd5: String, patchSize: Long): Boolean {
|
||||
return PatchManager.isPatchAccept(context, expectOldApkMd5, patchSize)
|
||||
}
|
||||
|
||||
override fun applyPatch(context: Context, patch: File, newApk: File): Boolean {
|
||||
return try {
|
||||
PatchManager.applyPatch(context, patch, newApk)
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun checkMd5ForMergedApk(context: Context, mergedApk: File, expectNewApkMd5: String): Boolean {
|
||||
return PatchManager.checkMd5ForMergedApk(mergedApk, expectNewApkMd5)
|
||||
}
|
||||
|
||||
override fun init(context: Context?) { }
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.mogo.launcher.patch.utils
|
||||
|
||||
import java.io.*
|
||||
import java.nio.channels.FileChannel.MapMode
|
||||
import java.security.*
|
||||
|
||||
class Md5Util {
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* 获取单个文件的MD5值!
|
||||
* @param file
|
||||
* @return
|
||||
* 解决首位0被省略问题
|
||||
*/
|
||||
fun getMd5FromFile(file: File): String? {
|
||||
var stringbuffer: StringBuffer? = null
|
||||
try {
|
||||
val hexDigits = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f')
|
||||
val input = FileInputStream(file)
|
||||
val ch = input.channel
|
||||
val byteBuffer = ch.map(MapMode.READ_ONLY, 0, file.length())
|
||||
val digest = MessageDigest.getInstance("MD5")
|
||||
digest.update(byteBuffer)
|
||||
val bytes = digest.digest()
|
||||
val n = bytes.size
|
||||
stringbuffer = StringBuffer(2 * n)
|
||||
for (l in 0 until n) {
|
||||
val bt = bytes[l]
|
||||
val c0 = hexDigits[bt.toInt() and 0xf0 shr 4]
|
||||
val c1 = hexDigits[bt.toInt() and 0xf]
|
||||
stringbuffer.append(c0)
|
||||
stringbuffer.append(c1)
|
||||
}
|
||||
} catch (e: java.lang.Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return stringbuffer?.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.mogo.launcer.patch
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user