「Skin」

1、修复皮肤包MD5不一致导致换肤加载失败的情况
This commit is contained in:
donghongyu
2024-11-05 12:59:28 +08:00
parent 91cc600c0d
commit 82dc52df7d
5 changed files with 61 additions and 31 deletions

View File

@@ -85,18 +85,18 @@ public class MainActivity extends AppCompatActivity {
btnChangeSkin.setOnCheckedChangeListener((view, isCheck) -> { btnChangeSkin.setOnCheckedChangeListener((view, isCheck) -> {
Skin skin; Skin skin;
if (isCheck) { if (isCheck) {
skin = new Skin(
"ee3e1b0ed6e33a51366949294b07787d",
"YiXin-skin_v1_2024_10_25.zip",
"https://carlife-static-1255510688.cos.ap-beijing.myqcloud.com/MoGoEagleEye/YiXin-skin_v1_2024_10_25.zip"
);
// skin = new Skin( // skin = new Skin(
// "a841e8819f06cfefa646f7adc697e070", // "ee3e1b0ed6e33a51366949294b07787d",
// "DeQing-skin_v1_2024_10_25.apk", // "YiXin-skin_v1_2024_10_25.zip",
// "https://carlife-static-1255510688.cos.ap-beijing.myqcloud.com/MoGoEagleEye/DeQing-skin_v1_2024_10_25.apk" // "https://carlife-static-1255510688.cos.ap-beijing.myqcloud.com/MoGoEagleEye/YiXin-skin_v1_2024_10_25.zip"
// ); // );
skin = new Skin(
"465a214dcbc65bdfbe860bdbcde95879",
"DeQing-skin_v1_2024_10_28.apk",
"https://carlife-static-1255510688.cos.ap-beijing.myqcloud.com/MoGoEagleEye/DeQing-skin_v1_2024_10_28.zip"
);
//换肤 //换肤
SkinManager.getInstance().downloadSkin(this, skin, new SkinManager.SkinLoadListener() { SkinManager.getInstance().downloadSkin(this, skin, new SkinManager.SkinLoadListener() {
@Override @Override

View File

@@ -58,7 +58,7 @@ MOGO_TELEMATIC_VERSION=1.4.7.42
# v2x # v2x
MOGO_V2X_VERSION=1.4.7.42 MOGO_V2X_VERSION=1.4.7.42
# SKIN # SKIN
MOGO_SKIN_VERSION=1.4.7.49.19-debug MOGO_SKIN_VERSION=1.4.7.49.19
# SDK # SDK
SDK_VERSION=1.4.7.49.18-debug SDK_VERSION=1.4.7.49.18-debug
SDK_NATIVE_VERSION=1.4.7.49.18-debug SDK_NATIVE_VERSION=1.4.7.49.18-debug

View File

@@ -1,5 +1,9 @@
package com.mogo.skin; package com.mogo.skin;
import android.text.TextUtils;
import com.mogo.skin.utils.SkinUtils;
import java.io.File; import java.io.File;
/** /**

View File

@@ -83,7 +83,7 @@ public class SkinManager extends Observable {
Log.d(TAG, "加载皮肤路径:" + skinPath); Log.d(TAG, "加载皮肤路径:" + skinPath);
if (TextUtils.isEmpty(skinPath)) { if (TextUtils.isEmpty(skinPath)) {
Log.d(TAG, "还原默认皮肤包,开始换肤……"); Log.d(TAG, "皮肤包路径为空,还原默认皮肤包,开始还原换肤。");
//还原默认皮肤包 //还原默认皮肤包
SkinPreference.getInstance().setSkin(""); SkinPreference.getInstance().setSkin("");
SkinResources.getInstance().reset(); SkinResources.getInstance().reset();
@@ -97,7 +97,7 @@ public class SkinManager extends Observable {
else { else {
// 判断是否已经加载同样皮肤如果已经加载则不再重复加载防止因为重复加载导致ImageView之类的设置了src、background的控件被重制 // 判断是否已经加载同样皮肤如果已经加载则不再重复加载防止因为重复加载导致ImageView之类的设置了src、background的控件被重制
try { try {
Log.d(TAG, "切换的皮肤与之前不一样,开始换肤……"); Log.d(TAG, "皮肤路径非空,开始换肤");
//反射创建AssetManager 与 Resource //反射创建AssetManager 与 Resource
AssetManager assetManager = AssetManager.class.newInstance(); AssetManager assetManager = AssetManager.class.newInstance();
// 资源路径设置 目录或压缩包 // 资源路径设置 目录或压缩包
@@ -151,11 +151,18 @@ public class SkinManager extends Observable {
File skinFile = skin.getSkinFile(theme); File skinFile = skin.getSkinFile(theme);
// 判断是否存在 // 判断是否存在
if (skinFile.exists()) { if (skinFile.exists()) {
Log.d(TAG, "皮肤已存在,开始换肤……skin=" + skin); // 检验皮肤包完整性即MD5是否一致不一致则删除
SkinManager.getInstance().loadSkin(skin.getPathLocal()); String localSkinFileMd5 = SkinUtils.getSkinMD5(skinFile);
return; if (!TextUtils.equals(localSkinFileMd5, skin.md5)) {
Log.w(TAG, "皮肤包 皮肤文件 MD5校验出错, 本地文件 MD5 = " + localSkinFileMd5 + " 与云端文件 MD5 = " + skin.md5 + " 不一致。删除本地皮肤包,重新下载。");
skinFile.delete();
} else {
Log.d(TAG, "皮肤包 皮肤文件 MD5校验成功, 本地文件 MD5 =" + localSkinFileMd5 + " 与云端文件 MD5 = " + skin.md5 + " 开始换肤……skin=" + skin);
SkinManager.getInstance().loadSkin(skin.getPathLocal());
return;
}
} }
Log.e(TAG, "皮肤不存在,开始下载……skin=" + skin); Log.w(TAG, "皮肤不存在,开始下载……skin=" + skin);
DownloadManager manager = getDownloadManager(skin, theme, skinLoadListener); DownloadManager manager = getDownloadManager(skin, theme, skinLoadListener);
// 启动文件下载 // 启动文件下载
manager.startDownload(); manager.startDownload();
@@ -167,34 +174,35 @@ public class SkinManager extends Observable {
@Override @Override
public void onProgressUpdate(int progress) { public void onProgressUpdate(int progress) {
// 更新UI或日志 // 更新UI或日志
Log.d(TAG, "DownloadManager onProgressUpdate progress = " + progress); Log.d(TAG, "皮肤包下载进度 onProgressUpdate progress = " + progress);
} }
@Override @Override
public void onDownloadSuccess() { public void onDownloadSuccess() {
// 下载成功后的处理 // 下载成功后的处理
Log.d(TAG, "DownloadManager onDownloadSuccess"); Log.d(TAG, "皮肤包 下载成功 onDownloadSuccess");
File skinFile = skin.getSkinFile(themeDirectory); File skinFile = skin.getSkinFile(themeDirectory);
try { try {
//下载成功将皮肤包信息insert已下载数据库 //下载成功将皮肤包信息insert已下载数据库
Log.e(TAG, "DownloadManager 皮肤包下载完成开始校验"); Log.d(TAG, "皮肤包下载完成开始校验……");
//皮肤包的md5校验 防止下载文件损坏(但是会减慢速度。从数据库查询已下载皮肤表数据库中保留md5字段) //皮肤包的md5校验 防止下载文件损坏(但是会减慢速度。从数据库查询已下载皮肤表数据库中保留md5字段)
String localSkinFileMd5 = SkinUtils.getSkinMD5(skinFile); String localSkinFileMd5 = SkinUtils.getSkinMD5(skinFile);
if (TextUtils.equals(localSkinFileMd5, skin.md5)) { if (TextUtils.equals(localSkinFileMd5, skin.md5)) {
Log.d(TAG, "DownloadManager 校验成功,修改文件名"); Log.d(TAG, "皮肤包 MD5 校验成功,本地文件 MD5 = " + localSkinFileMd5 + " 与云端文件 MD5 = " + skin.md5 + " 删除其它皮肤包");
// 加载指定皮肤包 // 加载指定皮肤包
SkinManager.getInstance().loadSkin(skin.getPathLocal()); SkinManager.getInstance().loadSkin(skin.getPathLocal());
// 回调给使用方成功
skinLoadListener.onLoadSuccess();
// 校验文件签名没问题后删除其他主题 // 校验文件签名没问题后删除其他主题
deleteFilesExcept(themeDirectory, skin.getSkinFileName()); deleteFilesExcept(themeDirectory, skin.getSkinFileName());
} else {
// 回调给使用方成功 // 回调给使用方成功
skinLoadListener.onLoadFailed(new Exception("皮肤文件校验出错,本地文件MD5 与云端文件MD5 不一致。")); skinLoadListener.onLoadSuccess();
Log.e(TAG, "DownloadManager 皮肤文件校验出错,本地文件 MD5 = " + localSkinFileMd5 + " 与云端文件 MD5 = " + skin.md5 + " 不一致。"); } else {
Log.e(TAG, "皮肤包 皮肤文件 MD5校验出错, 本地文件 MD5 = " + localSkinFileMd5 + " 与云端文件 MD5 = " + skin.md5 + " 不一致。");
Toast.makeText(mApplication, "皮肤文件校验出错,本地文件 MD5 = " + localSkinFileMd5 + " 与云端文件 MD5 = " + skin.md5 + " 不一致。", Toast.LENGTH_LONG).show(); Toast.makeText(mApplication, "皮肤文件校验出错,本地文件 MD5 = " + localSkinFileMd5 + " 与云端文件 MD5 = " + skin.md5 + " 不一致。", Toast.LENGTH_LONG).show();
// TODO 删除本地皮肤文件并重新下载这个操作比较危险需要严格保证配置文件中的md5与实际皮肤包一致否则将是灾难 // TODO 删除本地皮肤文件并重新下载这个操作比较危险需要严格保证配置文件中的md5与实际皮肤包一致否则将是灾难
skinFile.delete();
// 回调给使用方成功
skinLoadListener.onLoadFailed(new Exception("皮肤文件校验出错,本地文件MD5 与云端文件MD5 不一致。"));
} }
} catch (Exception e) { } catch (Exception e) {
skinLoadListener.onLoadFailed(e); skinLoadListener.onLoadFailed(e);
@@ -205,7 +213,7 @@ public class SkinManager extends Observable {
@Override @Override
public void onDownloadFailed(Exception e) { public void onDownloadFailed(Exception e) {
// 下载失败后的处理 // 下载失败后的处理
Log.e(TAG, "DownloadManager onDownloadFailed"); Log.e(TAG, "皮肤包下载出错 onDownloadFailed");
skinLoadListener.onLoadFailed(e); skinLoadListener.onLoadFailed(e);
e.printStackTrace(); e.printStackTrace();
} }
@@ -213,7 +221,7 @@ public class SkinManager extends Observable {
@Override @Override
public void onAlreadyDownloading(String url) { public void onAlreadyDownloading(String url) {
// 处理重复下载的情况 // 处理重复下载的情况
Log.w(TAG, "DownloadManager onAlreadyDownloading url=" + url); Log.w(TAG, "皮肤包 onAlreadyDownloading url=" + url);
skinLoadListener.onLoadFailed(new Exception("DownloadManager onAlreadyDownloading url=" + url)); skinLoadListener.onLoadFailed(new Exception("DownloadManager onAlreadyDownloading url=" + url));
} }
}; };

View File

@@ -1,6 +1,7 @@
package com.mogo.skin.net; package com.mogo.skin.net;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.util.Log;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -12,6 +13,8 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class DownloadManager { public class DownloadManager {
private static final String TAG = "DownloadManager";
private static final int BUFFER_SIZE = 1024 * 1024; // 1MB private static final int BUFFER_SIZE = 1024 * 1024; // 1MB
private static final Map<String, DownloadTask> activeDownloads = new HashMap<>(); private static final Map<String, DownloadTask> activeDownloads = new HashMap<>();
private String downloadUrl; private String downloadUrl;
@@ -32,6 +35,7 @@ public class DownloadManager {
} }
public DownloadManager(String url, String skinFileName, File directory, DownloadListener listener) { public DownloadManager(String url, String skinFileName, File directory, DownloadListener listener) {
Log.d(TAG, "皮肤包下载参数……url = " + url + " skinFileName = " + skinFileName + " directory = " + directory);
this.downloadUrl = url; this.downloadUrl = url;
this.outputDir = directory; this.outputDir = directory;
this.listener = listener; this.listener = listener;
@@ -39,11 +43,24 @@ public class DownloadManager {
// 确保输出目录存在 // 确保输出目录存在
if (!outputDir.exists()) { if (!outputDir.exists()) {
Log.d(TAG, "输出目录不存在,创建目录 outputDir = " + outputDir);
outputDir.mkdirs(); outputDir.mkdirs();
} }
// 如果文件不存在,则创建空文件 // 如果文件不存在,则创建空文件
if (!outputFile.exists()) { if (!outputFile.exists()) {
Log.d(TAG, "皮肤包不存在,创建 outputFile = " + outputFile);
try {
outputFile.createNewFile();
} catch (IOException e) {
if (listener != null) {
listener.onDownloadFailed(e);
}
return;
}
} else {
Log.w(TAG, "皮肤包已存在,删除后创建 outputFile = " + outputFile);
outputFile.delete();
try { try {
outputFile.createNewFile(); outputFile.createNewFile();
} catch (IOException e) { } catch (IOException e) {
@@ -92,9 +109,10 @@ public class DownloadManager {
connection.setRequestMethod("GET"); connection.setRequestMethod("GET");
connection.setConnectTimeout(15000); // 15 seconds connection.setConnectTimeout(15000); // 15 seconds
connection.setReadTimeout(15000); // 15 seconds connection.setReadTimeout(15000); // 15 seconds
if (downloadedLength > 0) { // if (downloadedLength > 0) {
connection.setRequestProperty("Range", "bytes=" + downloadedLength + "-"); // Log.d(TAG, "皮肤包下载中……,之前有未下载完成的任务,继续下载。 downloadedLength =" + downloadedLength);
} // connection.setRequestProperty("Range", "bytes=" + downloadedLength + "-");
// }
InputStream in = connection.getInputStream(); InputStream in = connection.getInputStream();
byte[] buffer = new byte[BUFFER_SIZE]; byte[] buffer = new byte[BUFFER_SIZE];
int read; int read;