「Update」

1、修复皮肤包下载存储,使用md5存储;
2、修复重复加载皮肤包导致View设置了图片被还原的bug;
This commit is contained in:
donghongyu
2024-10-23 12:20:20 +08:00
parent 80578feeca
commit 5c42a78ce2
4 changed files with 93 additions and 57 deletions

View File

@@ -11,21 +11,17 @@ public class Skin {
* 文件校验md5值
*/
public String md5 = "";
/**
* 下载地址
*/
public String url = "xxxx";
public String url = "";
/**
* 皮肤名
*/
public String name = "";
/**
* 下载完成后缓存地址
*/
public String path = "";
public File file;
public Skin(String md5, String name, String url) {
@@ -36,10 +32,33 @@ public class Skin {
public File getSkinFile(File theme) {
if (null == file) {
file = new File(theme, name);
file = new File(theme, getSkinFileName());
}
path = file.getAbsolutePath();
return file;
}
/**
* @return 下载完成后缓存地址
*/
public String getPathLocal() {
return file.getAbsolutePath();
}
/**
* @return 获取皮肤包文件名称
*/
public String getSkinFileName() {
return name + "_" + md5 + ".zip";
}
@Override
public String toString() {
return "Skin{" +
"md5='" + md5 + '\'' +
", url='" + url + '\'' +
", name='" + name + '\'' +
", file=" + file +
'}';
}
}

View File

@@ -81,40 +81,52 @@ public class SkinManager extends Observable {
//还原默认皮肤包
SkinPreference.getInstance().setSkin("");
SkinResources.getInstance().reset();
//应用皮肤包
setChanged();
//通知观察者
notifyObservers();
}
// 加载指定目录下的皮肤
else {
try {
//反射创建AssetManager 与 Resource
AssetManager assetManager = AssetManager.class.newInstance();
// 资源路径设置 目录或压缩包
Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
addAssetPath.setAccessible(true);
int result = (int) addAssetPath.invoke(assetManager, skinPath);
if (result == 0) {
Log.e(TAG, "加载皮肤APK失败" + skinPath);
// 判断是否已经加载同样皮肤如果已经加载则不再重复加载防止因为重复加载导致ImageView之类的设置了src、background的控件被重制
if (!SkinPreference.getInstance().getSkin().equals(skinPath)) {
try {
//反射创建AssetManager 与 Resource
AssetManager assetManager = AssetManager.class.newInstance();
// 资源路径设置 目录或压缩包
Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
addAssetPath.setAccessible(true);
int result = (int) addAssetPath.invoke(assetManager, skinPath);
if (result == 0) {
Log.e(TAG, "加载皮肤APK失败" + skinPath);
}
// 获取当前Resources
Resources resources = application.getResources();
//根据当前的设备显示器信息 与 配置(横竖屏、语言等) 创建Resources
Resources skinResource = new Resources(assetManager, resources.getDisplayMetrics(), resources.getConfiguration());
// 获取外部Apk(皮肤包) 包名
PackageManager mPm = application.getPackageManager();
PackageInfo info = mPm.getPackageArchiveInfo(skinPath, PackageManager.GET_ACTIVITIES);
String packageName = info.packageName;
SkinResources.getInstance().applySkin(skinResource, packageName);
//保存当前使用的皮肤包
SkinPreference.getInstance().setSkin(skinPath);
//应用皮肤包
setChanged();
//通知观察者
notifyObservers();
} catch (Exception e) {
e.printStackTrace();
}
// 获取当前Resources
Resources resources = application.getResources();
//根据当前的设备显示器信息 与 配置(横竖屏、语言等) 创建Resources
Resources skinResource = new Resources(assetManager, resources.getDisplayMetrics(), resources.getConfiguration());
// 获取外部Apk(皮肤包) 包名
PackageManager mPm = application.getPackageManager();
PackageInfo info = mPm.getPackageArchiveInfo(skinPath, PackageManager.GET_ACTIVITIES);
String packageName = info.packageName;
SkinResources.getInstance().applySkin(skinResource, packageName);
//保存当前使用的皮肤包
SkinPreference.getInstance().setSkin(skinPath);
} catch (Exception e) {
e.printStackTrace();
} else {
Log.e(TAG, "皮肤已存在,开始换肤……");
}
}
//应用皮肤包
setChanged();
//通知观察者
notifyObservers();
}
public void updateSkin(Activity activity) {
@@ -135,70 +147,71 @@ public class SkinManager extends Observable {
File skinFile = skin.getSkinFile(theme);
// 判断是否存在
if (skinFile.exists()) {
Log.e("SkinActivity", "皮肤已存在,开始换肤……");
SkinManager.getInstance().loadSkin(skin.path);
Log.e(TAG, "皮肤已存在,开始换肤……skin=" + skin);
SkinManager.getInstance().loadSkin(skin.getPathLocal());
return;
}
Log.e("SkinActivity", "皮肤不存在,开始下载……");
Log.e(TAG, "皮肤不存在,开始下载……skin=" + skin);
DownloadManager manager = getDownloadManager(skin, theme);
// 启动文件下载
manager.startDownload();
}
private static DownloadManager getDownloadManager(Skin skin, File theme) {
private static DownloadManager getDownloadManager(Skin skin, File themeDirectory) {
DownloadManager.DownloadListener downloadListener = new DownloadManager.DownloadListener() {
@Override
public void onProgressUpdate(int progress) {
// 更新UI或日志
Log.d("DownloadManager", "onProgressUpdate progress = " + progress);
Log.d(TAG, "DownloadManager onProgressUpdate progress = " + progress);
}
@Override
public void onDownloadSuccess() {
// 下载成功后的处理
Log.d("DownloadManager", "onDownloadSuccess");
File skinFile = skin.getSkinFile(theme);
Log.d(TAG, "DownloadManager onDownloadSuccess");
File skinFile = skin.getSkinFile(themeDirectory);
try {
//下载成功将皮肤包信息insert已下载数据库
Log.e("SkinActivity", "皮肤包下载完成开始校验");
Log.e(TAG, "DownloadManager 皮肤包下载完成开始校验");
//皮肤包的md5校验 防止下载文件损坏(但是会减慢速度。从数据库查询已下载皮肤表数据库中保留md5字段)
if (TextUtils.equals(SkinUtils.getSkinMD5(skinFile), skin.md5)) {
Log.d("SkinActivity", "校验成功,修改文件名。");
Log.d(TAG, "DownloadManager 校验成功,修改文件名。");
// 校验文件签名没问题后删除其他主题
deleteFilesExcept(theme, skin.file.getName());
deleteFilesExcept(themeDirectory, skin.getSkinFileName());
} else {
Log.e("SkinActivity", "皮肤文件校验出错,本地文件MD5 与云端文件MD5 不一致。");
Log.e(TAG, "DownloadManager 皮肤文件校验出错,本地文件MD5 与云端文件MD5 不一致。");
Toast.makeText(mApplication, "皮肤文件校验出错,本地文件MD5 与云端文件MD5 不一致。", Toast.LENGTH_SHORT).show();
// TODO 删除本地皮肤文件并重新下载这个操作比较危险需要严格保证配置文件中的md5与实际皮肤包一致否则将是灾难
}
} catch (Exception e) {
e.printStackTrace();
}
SkinManager.getInstance().loadSkin(skin.path);
SkinManager.getInstance().loadSkin(skin.getPathLocal());
}
@Override
public void onDownloadFailed(Exception e) {
// 下载失败后的处理
Log.e("DownloadManager", "onDownloadFailed");
Log.e(TAG, "DownloadManager onDownloadFailed");
e.printStackTrace();
}
@Override
public void onAlreadyDownloading(String url) {
// 处理重复下载的情况
Log.w("DownloadManager", "onAlreadyDownloading url=" + url);
Log.w(TAG, "DownloadManager onAlreadyDownloading url=" + url);
}
};
return new DownloadManager(skin.url, theme, downloadListener);
return new DownloadManager(skin.url, skin.getSkinFileName(), themeDirectory, downloadListener);
}
public static void deleteFilesExcept(File directory, String fileNameToKeep) {
if (directory == null || !directory.exists() || !directory.isDirectory()) {
throw new IllegalArgumentException("Provided path is not a valid directory: " + directory);
Log.e(TAG, "Provided path is not a valid directory: " + directory);
}
// 获取目录下的所有文件和子目录
@@ -208,9 +221,9 @@ public class SkinManager extends Observable {
// 如果文件名不等于要保留的文件名,并且不是目录,则删除
if (!file.getName().equals(fileNameToKeep) && !file.isDirectory()) {
if (file.delete()) {
System.out.println("Deleted: " + file.getAbsolutePath());
Log.d(TAG, "Deleted file=" + file.getAbsolutePath());
} else {
System.err.println("Failed to delete: " + file.getAbsolutePath());
Log.e(TAG, "Failed to delete file=" + file.getAbsolutePath());
}
}
}

View File

@@ -1,6 +1,7 @@
package com.mogo.skin.net;
import android.os.AsyncTask;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -22,16 +23,19 @@ public class DownloadManager {
public interface DownloadListener {
void onProgressUpdate(int progress);
void onDownloadSuccess();
void onDownloadFailed(Exception e);
void onAlreadyDownloading(String url);
}
public DownloadManager(String url, File directory, DownloadListener listener) {
public DownloadManager(String url, String skinFileName, File directory, DownloadListener listener) {
this.downloadUrl = url;
this.outputDir = directory;
this.listener = listener;
this.outputFile = new File(outputDir, getFileNameFromUrl(url));
this.outputFile = new File(outputDir, skinFileName);
// 确保输出目录存在
if (!outputDir.exists()) {