From 99b8127934a148992ec92d256596a7e2861bd65f Mon Sep 17 00:00:00 2001 From: tongtongstudio Date: Wed, 9 Apr 2025 00:22:18 +0800 Subject: [PATCH] add bsdiff --- .gitignore | 10 +- bsdiff/win/bsdiff.exe | Bin 0 -> 57344 bytes bsdiff/win/bspatch.exe | Bin 0 -> 34816 bytes .../controller/apk/CheckUpdateController.java | 8 +- .../controller/apk/CreateDiffPatchFile.java | 97 ++++++++++++++++++ .../controller/apk/UploadApkController.java | 51 +++++---- .../apk/UploadPakFileController.java | 2 +- .../backend/repository/ApkInfoRepository.java | 1 + .../backend/service/ApkInfoService.java | 4 + 9 files changed, 143 insertions(+), 30 deletions(-) create mode 100644 bsdiff/win/bsdiff.exe create mode 100644 bsdiff/win/bspatch.exe create mode 100644 src/main/java/com/mir4updater/backend/controller/apk/CreateDiffPatchFile.java diff --git a/.gitignore b/.gitignore index e6578fd..c75cc3b 100644 --- a/.gitignore +++ b/.gitignore @@ -31,13 +31,9 @@ build/ ### VS Code ### .vscode/ -/uploadApk/file/config.mdpi.apk -/uploadApk/file/FLYSN-68-V3.2.8-20240829-192522-G6Release.apk -/uploadApk/file/FLYSN-71-V3.3.1-20250307-175850-Huaruian8768Release.apk -/uploadApk/file/MIR4_0.442318_APKPure.xapk -/uploadApk/icon/7110e12ad7dec55cf925b72f266df7ed.png -/uploadApk/icon/268119212d35253700c802830449316a.png -/uploadApk/icon/d016c8c75162d1ae4c3ffbf7a178a111.png +/uploadApk/file/ +/uploadApk/icon/ +/uploadApk/patch/ /hs_err_pid14160.log /hs_err_pid19016.log /hs_err_pid28008.log diff --git a/bsdiff/win/bsdiff.exe b/bsdiff/win/bsdiff.exe new file mode 100644 index 0000000000000000000000000000000000000000..99ef9c614f8dad228c1b90b9cceb07c8cb1bec5f GIT binary patch literal 57344 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 literal 0 HcmV?d00001 diff --git a/bsdiff/win/bspatch.exe b/bsdiff/win/bspatch.exe new file mode 100644 index 0000000000000000000000000000000000000000..d8f5f70dfc308123b6a338459be2125689564b6e GIT binary patch literal 34816 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 OXD%)FKg@qe3;Z9*#g$qB literal 0 HcmV?d00001 diff --git a/src/main/java/com/mir4updater/backend/controller/apk/CheckUpdateController.java b/src/main/java/com/mir4updater/backend/controller/apk/CheckUpdateController.java index 90d8db6..b7fa35b 100644 --- a/src/main/java/com/mir4updater/backend/controller/apk/CheckUpdateController.java +++ b/src/main/java/com/mir4updater/backend/controller/apk/CheckUpdateController.java @@ -16,7 +16,7 @@ import java.util.Optional; @RestController public class CheckUpdateController { - public static Logger logger = LogManager.getLogger(UploadApkController.class); + public static Logger logger = LogManager.getLogger(CheckUpdateController.class); @Autowired private ApkInfoService apkInfoService; @@ -49,6 +49,10 @@ public class CheckUpdateController { @GetMapping("/android/get_all") public Result getAll() { List apkInfoList = apkInfoService.getAll(); - return Result.success().setData(apkInfoList); + if (apkInfoList==null||apkInfoList.isEmpty()){ + return Result.notFound(); + }else { + return Result.success().setData(apkInfoList); + } } } diff --git a/src/main/java/com/mir4updater/backend/controller/apk/CreateDiffPatchFile.java b/src/main/java/com/mir4updater/backend/controller/apk/CreateDiffPatchFile.java new file mode 100644 index 0000000..0653587 --- /dev/null +++ b/src/main/java/com/mir4updater/backend/controller/apk/CreateDiffPatchFile.java @@ -0,0 +1,97 @@ +package com.mir4updater.backend.controller.apk; + +import com.mir4updater.backend.entity.ApkInfo; +import com.mir4updater.backend.result.Result; +import com.mir4updater.backend.service.ApkInfoService; +import com.mir4updater.backend.utils.HashUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +@RestController +public class CreateDiffPatchFile { + public static Logger logger = LogManager.getLogger(CreateDiffPatchFile.class); + + private static final String UPLOAD_PATH = "uploadApk"; + + public static final String PATCH_PATH = "patch"; + @Autowired + private ApkInfoService apkInfoService; + + @PostMapping("/android/create_patch") + public Result uploadApk(@RequestParam("old_id") int oldId, @RequestParam("new_id") int newId) throws Exception { + String projectPath = System.getProperty("user.dir"); + String patchPath = projectPath + File.separator + UPLOAD_PATH + File.separator + PATCH_PATH + File.separator; + File patchFileDir = new File(patchPath); + if (!patchFileDir.exists()) { + patchFileDir.mkdirs(); + } + + ApkInfo oldApkInfo = apkInfoService.getApkInfo(oldId); + ApkInfo newApkInfo = apkInfoService.getApkInfo(newId); + if (oldApkInfo == null || newApkInfo == null) { + return Result.notFound(); + } + if (!Objects.equals(oldApkInfo.getPackageName(), newApkInfo.getPackageName())) { + return Result.error("包名不一致"); + } + if (oldApkInfo.getVersionCode() >= newApkInfo.getVersionCode()) { + return Result.error("旧版本号不能大于等于新版本号"); + } + File patchFile = new File(patchPath + oldApkInfo.getPackageName() + "_" + oldApkInfo.getVersionCode() + "_" + newApkInfo.getVersionCode() + ".patch"); + + // 根据操作系统选择命令 + String os = System.getProperty("os.name").toLowerCase(); + String command; + if (os.contains("win")) { + command = "bsdiff" + File.separator + "win" + File.separator + "bsdiff.exe"; + } else if (os.contains("nix") || os.contains("mac")) { + command = "bsdiff" + File.separator + "linux" + File.separator + "bsdiff"; + } else { + throw new UnsupportedOperationException("Unsupported OS"); + } + File file = new File(command); + logger.info("bsdiff file exists = " + file.exists()); + + // 将 command 和 arg 合并成一个数组,command 作为第一个参数 + List cmdArgs = new ArrayList<>(); + cmdArgs.add(command); // 第一个参数是命令本身 + cmdArgs.add(oldApkInfo.getFilePath());// 后续参数 + cmdArgs.add(newApkInfo.getFilePath()); + cmdArgs.add(patchFile.getAbsolutePath()); + + logger.info("bsdiff args = " + cmdArgs); + + ProcessBuilder pb = new ProcessBuilder(cmdArgs); // 传入合并后的参数列表 + pb.redirectErrorStream(true); // 合并错误流和输入流 + Process process = pb.start(); + + int exitCode = process.waitFor(); + logger.info("退出码: " + exitCode); + + // 读取输出 + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String result = reader.lines().collect(Collectors.joining("\n")); + if (exitCode == 0) { + String md5 = HashUtils.getFileMD5(patchFile); + logger.info("patchFile md5 = " + md5); + return Result.success(md5); + } else { + return Result.error(result); + } + } + +} diff --git a/src/main/java/com/mir4updater/backend/controller/apk/UploadApkController.java b/src/main/java/com/mir4updater/backend/controller/apk/UploadApkController.java index 2208fc4..1f2e755 100644 --- a/src/main/java/com/mir4updater/backend/controller/apk/UploadApkController.java +++ b/src/main/java/com/mir4updater/backend/controller/apk/UploadApkController.java @@ -33,32 +33,43 @@ import java.util.zip.ZipFile; @RestController public class UploadApkController { + private static final String UPLOAD_PATH = "uploadApk"; + private static final String APK_FILE_PATH = "file"; + private static final String ICON_PATH = "icon"; + private static final String TEMP_PATH = "tmp"; + public static Logger logger = LogManager.getLogger(UploadApkController.class); @Autowired private ApkInfoService apkInfoService; - private static final String UPLOAD_PATH = "uploadApk"; - private static final String ApkFilePath = "file"; - private static final String ICON_PATH = "icon"; + @PostMapping("/android/upload_apk") public Result uploadApk(@RequestParam("file") MultipartFile multipartFile) throws Exception { if (multipartFile != null && !multipartFile.isEmpty()) { String projectPath = System.getProperty("user.dir"); logger.info("当前项目路径为:" + projectPath); - String dirPath = projectPath + File.separator + UPLOAD_PATH + File.separator + ApkFilePath; + + String apkPath = projectPath + File.separator + UPLOAD_PATH + File.separator + APK_FILE_PATH; String iconPath = projectPath + File.separator + UPLOAD_PATH + File.separator + ICON_PATH + File.separator; - File dirFile = new File(dirPath); - if (!dirFile.exists()) { - dirFile.mkdirs(); + String tempPath = projectPath + File.separator + UPLOAD_PATH + File.separator + TEMP_PATH + File.separator; + + File apkFileDir = new File(apkPath); + if (!apkFileDir.exists()) { + apkFileDir.mkdirs(); } - File iconFilePath = new File(iconPath); - if (!iconFilePath.exists()) { - iconFilePath.mkdirs(); + File iconFileDir = new File(iconPath); + if (!iconFileDir.exists()) { + iconFileDir.mkdirs(); } + File tempFileDir = new File(tempPath); + if (!tempFileDir.exists()) { + tempFileDir.mkdirs(); + } + //1.接收上传的应用,写入到硬盘 String originalFilename = multipartFile.getOriginalFilename(); - File file = new File(dirPath + File.separator + originalFilename); + File file = new File(apkPath + File.separator + originalFilename); logger.info("file path = " + file.getAbsolutePath()); try { @@ -82,7 +93,7 @@ public class UploadApkController { if (isAPK(file)) { logger.info("file type is apk"); //调用工具类解析apk - //analysisAPK(dirFile.getAbsolutePath(), file.getAbsolutePath()); + //analysisAPK(apkFileDir.getAbsolutePath(), file.getAbsolutePath()); ApkFile apkFile = new ApkFile(file); ApkMeta apkMeta = apkFile.getApkMeta(); @@ -118,9 +129,9 @@ public class UploadApkController { } catch (DataIntegrityViolationException e) { e.printStackTrace(); logger.info(e.getMessage()); - File file1 = new File(file.getAbsolutePath()); - logger.info("delete:" + file1.delete()); return Result.error().setMessage("apk文件无效"); + } finally { + apkFile.close(); } return Result.success().setMessage("上传成功"); @@ -200,15 +211,14 @@ public class UploadApkController { } // 判断是否为APK - public static boolean isAPK(File file) { + public static boolean isAPK(File file) throws IOException { // 检查扩展名是否为.apk if (file.getName().toLowerCase().endsWith(".apk")) { // 进一步验证是否为有效的APK文件 - try (ZipFile zipFile = new ZipFile(file)) { - return zipFile.getEntry("AndroidManifest.xml") != null; - } catch (IOException e) { - return false; - } + ZipFile zipFile = new ZipFile(file); + boolean apkFile = zipFile.getEntry("AndroidManifest.xml") != null; + zipFile.close(); + return apkFile; } return false; } @@ -241,6 +251,7 @@ public class UploadApkController { // hasOBB = true; // } } + zipFile.close(); // XAPK通常包含至少一个APK或OBB数据 return hasAPK || hasJson; } catch (IOException e) { diff --git a/src/main/java/com/mir4updater/backend/controller/apk/UploadPakFileController.java b/src/main/java/com/mir4updater/backend/controller/apk/UploadPakFileController.java index 51b310c..18bc8e0 100644 --- a/src/main/java/com/mir4updater/backend/controller/apk/UploadPakFileController.java +++ b/src/main/java/com/mir4updater/backend/controller/apk/UploadPakFileController.java @@ -20,7 +20,7 @@ import java.util.Collections; @RestController public class UploadPakFileController { - public static Logger logger = LogManager.getLogger(UploadApkController.class); + public static Logger logger = LogManager.getLogger(UploadPakFileController.class); private static final String UPLOAD_PATH = "uploadPak"; static { diff --git a/src/main/java/com/mir4updater/backend/repository/ApkInfoRepository.java b/src/main/java/com/mir4updater/backend/repository/ApkInfoRepository.java index 6c0e8ed..f8294ff 100644 --- a/src/main/java/com/mir4updater/backend/repository/ApkInfoRepository.java +++ b/src/main/java/com/mir4updater/backend/repository/ApkInfoRepository.java @@ -9,5 +9,6 @@ import java.util.List; public interface ApkInfoRepository extends JpaRepository { // 自定义查询方法(可选) List findApkInfosByPackageName(String pkg); + ApkInfo findApkInfoByAppId(int id); List findAll(); } diff --git a/src/main/java/com/mir4updater/backend/service/ApkInfoService.java b/src/main/java/com/mir4updater/backend/service/ApkInfoService.java index 4912b09..046903c 100644 --- a/src/main/java/com/mir4updater/backend/service/ApkInfoService.java +++ b/src/main/java/com/mir4updater/backend/service/ApkInfoService.java @@ -20,6 +20,10 @@ public class ApkInfoService { return apkInfoRepository.findApkInfosByPackageName(pkg); } + public ApkInfo getApkInfo(int id) { + return apkInfoRepository.findApkInfoByAppId(id); + } + public List getAll() { return apkInfoRepository.findAll(); }