From a3a34326e2f736f52b6da684d34dede2c3f3f08c Mon Sep 17 00:00:00 2001 From: TongTongStudio Date: Sat, 15 Aug 2026 00:30:41 +0800 Subject: [PATCH] =?UTF-8?q?fix(packages):=20=E4=BF=AE=E5=A4=8D=20XAPK=20?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E5=85=BC=E5=AE=B9=E6=80=A7=E5=B9=B6=E8=A1=A5?= =?UTF-8?q?=E5=85=85=E6=9C=AC=E5=9C=B0=E5=8C=96=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 忽略 manifest.json 中未声明字段,避免反序列化失败 - 直接解压 base APK 字节,移除对 ContainerEntry 的依赖 - 主 APK 解析失败时降级使用容器 JSON 信息 - 记录解析异常日志,便于排查位置越界问题 - XapkJsonInfo 新增 locales_name 字段 --- .../app/packages/component/ApkMetaParser.java | 34 ++++++++++--------- .../app/packages/model/dto/XapkJsonInfo.java | 5 +++ 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/youlai/boot/app/packages/component/ApkMetaParser.java b/src/main/java/com/youlai/boot/app/packages/component/ApkMetaParser.java index 9c0207fd..64511263 100644 --- a/src/main/java/com/youlai/boot/app/packages/component/ApkMetaParser.java +++ b/src/main/java/com/youlai/boot/app/packages/component/ApkMetaParser.java @@ -15,6 +15,7 @@ import net.dongliu.apk.parser.ApkFile; import net.dongliu.apk.parser.bean.ApkMeta; import net.dongliu.apk.parser.bean.Icon; import org.apache.commons.lang3.StringUtils; +import org.glassfish.jaxb.core.v2.TODO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.zeroturnaround.zip.ZipUtil; @@ -45,7 +46,10 @@ import java.util.zip.ZipInputStream; */ public class ApkMetaParser { private static final String ANDROID_NS = "http://schemas.android.com/apk/res/android"; - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() + // manifest.json / info.json 可能包含本类未声明的额外字段(如 locales_name), + // 忽略未知字段避免反序列化失败 + .configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); private static final Logger LOGGER = LoggerFactory.getLogger(ApkMetaParser.class); /** @@ -470,9 +474,7 @@ public class ApkMetaParser { throw new IOException("容器内未找到 manifest.json 文件: " + xapkFile.getName()); } - XapkContent content = readXapkContent(xapkFile); - List apks = content.apks; - byte[] manifestJson = content.manifestJson; + byte[] manifestJson = ZipUtil.unpackEntry(xapkFile, "manifest.json"); XapkJsonInfo xapkJsonInfo = OBJECT_MAPPER.readValue(manifestJson, XapkJsonInfo.class); @@ -498,26 +500,24 @@ public class ApkMetaParser { apkMetaResult.setSplitApkList(fileList); SplitApks baseApk = splitApksList.stream().filter(splitApks -> splitApks.getId().equals("base")).findFirst().orElse(null); + if (baseApk == null) { throw new IOException("容器内未找到 base apk 文件: " + xapkFile.getName()); } - ContainerEntry baseApkEntry = apks.stream().filter(containerEntry -> containerEntry.name.equals(baseApk.getFile())).findFirst().orElse(null); - if (baseApkEntry == null) { - throw new IOException("容器内未找到 base apk 文件: " + xapkFile.getName()); - } + LOGGER.info("baseApk info = " + baseApk); + + byte[] baseApkBytes = ZipUtil.unpackEntry(xapkFile, baseApk.getFile()); // 2) 若经验法则未命中,兜底:逐个尝试解析,第一个拿到 packageName 的即为主包 - ApkMetaResult result = tryParseApkBytes(baseApkEntry.data); - if (result == null) { - throw new IOException("容器内未找到 base apk 文件: " + xapkFile.getName()); + ApkMetaResult result = tryParseApkBytes(baseApkBytes); + if (result != null) { + // 主 APK 解析出的字段优先(覆盖容器 JSON 中的值) + overrideIfDifferent(apkMetaResult, result); + apkMetaResult.setCompileSdk(result.getCompileSdk()); + apkMetaResult.setAbiList(result.getAbiList()); } - // 主 APK 解析出的字段优先(覆盖容器 JSON 中的值) - overrideIfDifferent(apkMetaResult, result); - apkMetaResult.setCompileSdk(result.getCompileSdk()); - apkMetaResult.setAbiList(result.getAbiList()); - return apkMetaResult; } @@ -766,6 +766,8 @@ public class ApkMetaParser { return result; } } catch (Exception e) { + // TODO 2026.08.15 有些会报错 newPosition > limit: (524301 > 228) + LOGGER.error("tryParseApkBytes error", e); return null; } finally { if (tmp != null && tmp.exists()) { diff --git a/src/main/java/com/youlai/boot/app/packages/model/dto/XapkJsonInfo.java b/src/main/java/com/youlai/boot/app/packages/model/dto/XapkJsonInfo.java index 26c480d7..6d983b3b 100644 --- a/src/main/java/com/youlai/boot/app/packages/model/dto/XapkJsonInfo.java +++ b/src/main/java/com/youlai/boot/app/packages/model/dto/XapkJsonInfo.java @@ -6,6 +6,7 @@ import lombok.Data; import java.io.Serializable; import java.util.List; +import java.util.Map; @Data @@ -16,6 +17,10 @@ public class XapkJsonInfo implements Serializable { private int xapk_version; private String package_name; private String name; + /** + * 各语言代码到本地化应用名的映射(如 "zh-CN": "GitHub")。 + */ + private Map locales_name; private long version_code; private String version_name; private int min_sdk_version;