6.7.0 - Alpha12 - 修复 APK Parser 库可能无法正常解析部分 APK 文件类型信息的问题

This commit is contained in:
SuperMonster003
2025-12-09 12:12:26 +08:00
parent d3a6212f99
commit b4a87e6639
4 changed files with 107 additions and 34 deletions

View File

@@ -6,6 +6,7 @@ import android.content.pm.PackageInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.pm.PackageManager.GET_META_DATA import android.content.pm.PackageManager.GET_META_DATA
import android.os.Build import android.os.Build
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View.MeasureSpec.UNSPECIFIED import android.view.View.MeasureSpec.UNSPECIFIED
import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.content.res.AppCompatResources
@@ -37,6 +38,8 @@ import java.io.File
object ApkInfoDialogManager { object ApkInfoDialogManager {
private const val TAG = "ApkInfoDialogManager"
@JvmStatic @JvmStatic
@JvmOverloads @JvmOverloads
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
@@ -179,7 +182,11 @@ object ApkInfoDialogManager {
private fun getApkInfo(apkFile: File): ApkInfo? = runCatching { private fun getApkInfo(apkFile: File): ApkInfo? = runCatching {
ApkFile(apkFile).use { parser -> ApkFile(apkFile).use { parser ->
val meta = runCatching { parser.apkMeta }.getOrNull() val meta = runCatching { parser.apkMeta }
.onFailure {
Log.d(TAG, "Failed to parse apk meta: ${apkFile.absolutePath}", it)
}
.getOrNull()
val label = meta?.label val label = meta?.label
val packageName = meta?.packageName val packageName = meta?.packageName
val minSdkVersion = meta?.minSdkVersion?.toIntOrNull() val minSdkVersion = meta?.minSdkVersion?.toIntOrNull()

View File

@@ -47,6 +47,7 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.IllformedLocaleException;
/** /**
* Common Apk Parser methods. * Common Apk Parser methods.
@@ -332,9 +333,17 @@ public abstract class AbstractApkFile implements Closeable {
} }
final ByteBuffer buffer = ByteBuffer.wrap(data); final ByteBuffer buffer = ByteBuffer.wrap(data);
final ResourceTableParser resourceTableParser = new ResourceTableParser(buffer); final ResourceTableParser resourceTableParser = new ResourceTableParser(buffer);
try {
resourceTableParser.parse(); resourceTableParser.parse();
this.resourceTable = resourceTableParser.getResourceTable(); this.resourceTable = resourceTableParser.getResourceTable();
this.locales = resourceTableParser.locales; this.locales = resourceTableParser.locales;
} catch (final IllformedLocaleException | IllegalArgumentException e) {
// 容错回退: 当资源表中的语言/地区字段不合法或解析实现不兼容时,
// 退化为无资源表模式,允许后续 Manifest 解析继续进行。
this.resourceTable = new ResourceTable(null);
this.locales = Collections.emptySet();
// 如需记录日志,可在此处接入项目日志系统;为保持通用性,此处不抛出异常
}
} }
/** /**

View File

@@ -2,7 +2,6 @@ package net.dongliu.apk.parser.struct.resource;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import net.dongliu.apk.parser.struct.ResourceValue; import net.dongliu.apk.parser.struct.ResourceValue;
import net.dongliu.apk.parser.struct.StringPool; import net.dongliu.apk.parser.struct.StringPool;
import net.dongliu.apk.parser.utils.Buffers; import net.dongliu.apk.parser.utils.Buffers;
@@ -15,32 +14,90 @@ import java.util.Locale;
* @author dongliu * @author dongliu
*/ */
public class Type { public class Type {
private String name;
public final short id; public final short id;
@NonNull @NonNull
public final Locale locale; public final Locale locale;
/**
* see Densities.java for values
*/
public final int density;
private String name;
private StringPool keyStringPool; private StringPool keyStringPool;
private ByteBuffer buffer; private ByteBuffer buffer;
private long[] offsets; private long[] offsets;
private StringPool stringPool; private StringPool stringPool;
/**
* see Densities.java for values
*/
public final int density;
public Type(final @NonNull TypeHeader header) { public Type(final @NonNull TypeHeader header) {
this.id = header.getId(); this.id = header.getId();
final ResTableConfig config = header.config; final ResTableConfig config = header.config;
this.locale = new Locale.Builder()
.setLanguage(config.getLanguage()) // Normalize and handle language/region safely to avoid IllformedLocaleException.
.setRegion(config.getCountry()) // zh-CN: 规范化并容错处理 language/region, 避免 IllformedLocaleException.
.build(); final String rawLang = config.getLanguage();
final String rawRegion = config.getCountry();
final String lang = sanitizeLanguage(rawLang);
final String region = sanitizeRegion(rawRegion);
Locale tmpLocale;
try {
final Locale.Builder builder = new Locale.Builder();
if (lang != null) {
builder.setLanguage(lang);
}
if (region != null) {
builder.setRegion(region);
}
tmpLocale = builder.build();
} catch (final RuntimeException e) {
// Handle all invalid data including IllformedLocaleException.
// zh-CN: 包含 IllformedLocaleException 在内的所有非法数据的兜底.
if (lang != null) {
// At least keep valid language.
// zh-CN: 至少保留合法 language.
tmpLocale = new Locale(lang);
} else {
tmpLocale = Locale.ROOT;
}
}
this.locale = tmpLocale;
this.density = config.getDensity(); this.density = config.getDensity();
} }
// Only allows 2 or 3 letter characters (BCP-47 common language subtags).
// zh-CN: 仅允许 2 或 3 位字母 (BCP-47 常见语言子标签).
private static String sanitizeLanguage(@Nullable String lang) {
if (lang == null) return null;
lang = lang.trim();
if (lang.isEmpty()) return null;
// Filter out non-letter characters.
// zh-CN: 过滤非字母字符.
final String cleaned = lang.replaceAll("[^A-Za-z]", "");
if (cleaned.length() == 2 || cleaned.length() == 3) {
return cleaned.toLowerCase(Locale.ROOT);
}
return null;
}
// Only allows 2 letter or 3 digit characters (e.g. CN/US/419).
// zh-CN: 仅允许 2 位字母或 3 位数字 (如 CN/US/419).
private static String sanitizeRegion(@Nullable String region) {
if (region == null) return null;
region = region.trim();
if (region.isEmpty()) return null;
final String letters = region.replaceAll("[^A-Za-z]", "");
if (letters.length() == 2) {
return letters.toUpperCase(Locale.ROOT);
}
final String digits = region.replaceAll("[^0-9]", "");
if (digits.length() == 3) {
return digits;
}
return null;
}
@Nullable @Nullable
public ResourceEntry getResourceEntry(final int resId) { public ResourceEntry getResourceEntry(final int resId) {
if (resId >= this.offsets.length) { if (resId >= this.offsets.length) {

View File

@@ -1,5 +1,5 @@
#Tue Dec 09 11:33:43 CST 2025 #Tue Dec 09 12:09:37 CST 2025
BUILD_TIME=1765251223946 BUILD_TIME=1765253377144
COMPILE_SDK_VERSION=36 COMPILE_SDK_VERSION=36
IMAGE_QUANT_CMAKE_VERSION=3.22.1 IMAGE_QUANT_CMAKE_VERSION=3.22.1
IMAGE_QUANT_NDK_VERSION=26.1.10909125 IMAGE_QUANT_NDK_VERSION=26.1.10909125