6.7.0 - Alpha12 - 修复 APK Parser 库可能无法正常解析部分 APK 文件类型信息的问题
This commit is contained in:
@@ -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()
|
||||||
|
|||||||
@@ -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();
|
||||||
|
// 如需记录日志,可在此处接入项目日志系统;为保持通用性,此处不抛出异常
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user