fix(res): use safe number parsing for android manifest, refactor params object (#2857)

This commit is contained in:
Skylot
2026-04-25 20:06:02 +01:00
parent 044c75ab9f
commit 55e79fb70f
4 changed files with 131 additions and 95 deletions
@@ -31,9 +31,6 @@ public class AndroidGradleGenerator implements IExportGradleGenerator {
private static final Logger LOG = LoggerFactory.getLogger(AndroidGradleGenerator.class);
private static final Pattern ILLEGAL_GRADLE_CHARS = Pattern.compile("[/\\\\:>\"?*|]");
private static final ApplicationParams UNKNOWN_APP_PARAMS =
new ApplicationParams("UNKNOWN", 0, 0, 0, 0, "UNKNOWN", "UNKNOWN", "UNKNOWN");
private final RootNode root;
private final File projectDir;
private final List<ResourceFile> resources;
@@ -83,8 +80,8 @@ public class AndroidGradleGenerator implements IExportGradleGenerator {
try {
ResourceFile androidManifest = AndroidManifestParser.getAndroidManifest(resources);
if (androidManifest == null) {
LOG.warn("AndroidManifest.xml not found, exported files will contains 'UNKNOWN' fields");
return UNKNOWN_APP_PARAMS;
LOG.warn("AndroidManifest.xml not found, exported files will contains 'null' fields");
return new ApplicationParams();
}
ResContainer strings = null;
if (exportApp) {
@@ -118,7 +115,7 @@ public class AndroidGradleGenerator implements IExportGradleGenerator {
return parser.parse();
} catch (Exception t) {
LOG.warn("Failed to parse AndroidManifest.xml", t);
return UNKNOWN_APP_PARAMS;
return new ApplicationParams();
}
}
@@ -143,7 +140,7 @@ public class AndroidGradleGenerator implements IExportGradleGenerator {
private void saveSettingsGradle() throws IOException {
TemplateFile tmpl = TemplateFile.fromResources("/export/android/settings.gradle.tmpl");
String appName = applicationParams.getApplicationName();
String appName = applicationParams.getApplicationLabel();
String projectName;
if (appName != null) {
projectName = ILLEGAL_GRADLE_CHARS.matcher(appName).replaceAll("");
@@ -672,4 +672,26 @@ public class Utils {
}
return Integer.parseInt(strValue);
}
public static int safeParseInt(String value, int defValue) {
if (value == null || value.isEmpty()) {
return defValue;
}
try {
return Integer.parseInt(value);
} catch (Exception e) {
return defValue;
}
}
public static @Nullable Integer safeParseInteger(@Nullable String value) {
if (value == null || value.isEmpty()) {
return null;
}
try {
return Integer.parseInt(value);
} catch (Exception e) {
return null;
}
}
}
@@ -18,6 +18,8 @@ import jadx.api.security.IJadxSecurity;
import jadx.core.utils.exceptions.JadxRuntimeException;
import jadx.core.xmlgen.ResContainer;
import static jadx.core.utils.Utils.safeParseInteger;
public class AndroidManifestParser {
private final Document androidManifest;
private final @Nullable Document appStrings;
@@ -41,8 +43,7 @@ public class AndroidManifestParser {
return androidManifest != null;
}
@Nullable
public static ResourceFile getAndroidManifest(List<ResourceFile> resources) {
public static @Nullable ResourceFile getAndroidManifest(List<ResourceFile> resources) {
return resources.stream()
.filter(resourceFile -> resourceFile.getType() == ResourceType.MANIFEST)
.findFirst()
@@ -53,19 +54,11 @@ public class AndroidManifestParser {
if (!isManifestFound()) {
throw new JadxRuntimeException("AndroidManifest.xml is missing");
}
return parseAttributes();
}
private ApplicationParams parseAttributes() {
String applicationLabel = null;
Integer minSdkVersion = null;
Integer targetSdkVersion = null;
Integer compileSdkVersion = null;
Integer versionCode = null;
String versionName = null;
String mainActivity = null;
String application = null;
ApplicationParams appParams = new ApplicationParams();
@Nullable
Element manifest = (Element) androidManifest.getElementsByTagName("manifest").item(0);
@@ -73,49 +66,47 @@ public class AndroidManifestParser {
Element usesSdk = (Element) androidManifest.getElementsByTagName("uses-sdk").item(0);
if (parseAttrs.contains(AppAttribute.APPLICATION_LABEL)) {
applicationLabel = getApplicationLabel();
appParams.setApplicationLabel(getApplicationLabel());
}
if (usesSdk != null) {
if (parseAttrs.contains(AppAttribute.MIN_SDK_VERSION)) {
minSdkVersion = Integer.valueOf(usesSdk.getAttribute("android:minSdkVersion"));
appParams.setMinSdkVersion(safeParseInteger(usesSdk.getAttribute("android:minSdkVersion")));
}
if (parseAttrs.contains(AppAttribute.TARGET_SDK_VERSION)) {
String stringTargetSdk = usesSdk.getAttribute("android:targetSdkVersion");
if (!stringTargetSdk.isEmpty()) {
targetSdkVersion = Integer.valueOf(stringTargetSdk);
appParams.setTargetSdkVersion(safeParseInteger(stringTargetSdk));
} else {
if (minSdkVersion == null) {
minSdkVersion = Integer.valueOf(usesSdk.getAttribute("android:minSdkVersion"));
if (appParams.getMinSdkVersion() == null) {
appParams.setMinSdkVersion(safeParseInteger(usesSdk.getAttribute("android:minSdkVersion")));
}
targetSdkVersion = minSdkVersion;
appParams.setTargetSdkVersion(appParams.getMinSdkVersion());
}
}
if (parseAttrs.contains(AppAttribute.COMPILE_SDK_VERSION)) {
String stringCompileSdk = usesSdk.getAttribute("android:compileSdkVersion");
if (!stringCompileSdk.isEmpty()) {
compileSdkVersion = Integer.valueOf(stringCompileSdk);
appParams.setCompileSdkVersion(safeParseInteger(stringCompileSdk));
} else {
compileSdkVersion = targetSdkVersion;
appParams.setCompileSdkVersion(appParams.getTargetSdkVersion());
}
}
}
if (manifest != null) {
if (parseAttrs.contains(AppAttribute.VERSION_CODE)) {
versionCode = Integer.valueOf(manifest.getAttribute("android:versionCode"));
appParams.setVersionCode(safeParseInteger(manifest.getAttribute("android:versionCode")));
}
if (parseAttrs.contains(AppAttribute.VERSION_NAME)) {
versionName = manifest.getAttribute("android:versionName");
appParams.setVersionName(manifest.getAttribute("android:versionName"));
}
}
if (parseAttrs.contains(AppAttribute.MAIN_ACTIVITY)) {
mainActivity = getMainActivityName();
appParams.setMainActivity(getMainActivityName());
}
if (parseAttrs.contains(AppAttribute.APPLICATION)) {
application = getApplicationName();
appParams.setApplication(getApplicationName());
}
return new ApplicationParams(applicationLabel, minSdkVersion, targetSdkVersion, compileSdkVersion,
versionCode, versionName, mainActivity, application);
return appParams;
}
private String getApplicationLabel() {
@@ -143,11 +134,10 @@ public class AndroidManifestParser {
return appLabelName;
}
}
return "UNKNOWN";
}
private String getMainActivityName() {
private @Nullable String getMainActivityName() {
String mainActivityName = getMainActivityNameThroughActivityTag();
if (mainActivityName == null) {
mainActivityName = getMainActivityNameThroughActivityAliasTag();
@@ -155,7 +145,7 @@ public class AndroidManifestParser {
return mainActivityName;
}
private String getApplicationName() {
private @Nullable String getApplicationName() {
Element application = (Element) androidManifest.getElementsByTagName("application").item(0);
if (application.hasAttribute("android:name")) {
return application.getAttribute("android:name");
@@ -163,7 +153,7 @@ public class AndroidManifestParser {
return null;
}
private String getMainActivityNameThroughActivityAliasTag() {
private @Nullable String getMainActivityNameThroughActivityAliasTag() {
NodeList activityAliasNodes = androidManifest.getElementsByTagName("activity-alias");
for (int i = 0; i < activityAliasNodes.getLength(); i++) {
Element activityElement = (Element) activityAliasNodes.item(i);
@@ -174,7 +164,7 @@ public class AndroidManifestParser {
return null;
}
private String getMainActivityNameThroughActivityTag() {
private @Nullable String getMainActivityNameThroughActivityTag() {
NodeList activityNodes = androidManifest.getElementsByTagName("activity");
for (int i = 0; i < activityNodes.getLength(); i++) {
Element activityElement = (Element) activityNodes.item(i);
@@ -230,7 +220,7 @@ public class AndroidManifestParser {
}
}
private Document parseAppStrings(ResContainer appStrings) {
private @Nullable Document parseAppStrings(@Nullable ResContainer appStrings) {
if (appStrings == null) {
return null;
}
@@ -238,7 +228,7 @@ public class AndroidManifestParser {
return parseXml(content);
}
private Document parseAndroidManifest(ResourceFile androidManifest) {
private @Nullable Document parseAndroidManifest(ResourceFile androidManifest) {
if (androidManifest == null) {
return null;
}
@@ -1,68 +1,95 @@
package jadx.core.utils.android;
import org.jetbrains.annotations.Nullable;
import jadx.api.JadxDecompiler;
import jadx.api.JavaClass;
public class ApplicationParams {
private @Nullable String applicationLabel;
private @Nullable Integer minSdkVersion;
private @Nullable Integer targetSdkVersion;
private @Nullable Integer compileSdkVersion;
private @Nullable Integer versionCode;
private @Nullable String versionName;
private @Nullable String mainActivity;
private @Nullable String application;
private final String applicationLabel;
private final Integer minSdkVersion;
private final Integer targetSdkVersion;
private final Integer compileSdkVersion;
private final Integer versionCode;
private final String versionName;
private final String mainActivity;
private final String application;
public ApplicationParams(String applicationLabel, Integer minSdkVersion, Integer targetSdkVersion, Integer compileSdkVersion,
Integer versionCode, String versionName, String mainActivity, String application) {
this.applicationLabel = applicationLabel;
this.minSdkVersion = minSdkVersion;
this.targetSdkVersion = targetSdkVersion;
this.compileSdkVersion = compileSdkVersion;
this.versionCode = versionCode;
this.versionName = versionName;
this.mainActivity = mainActivity;
this.application = application;
}
public String getApplicationName() {
return applicationLabel;
}
public Integer getMinSdkVersion() {
return minSdkVersion;
}
public Integer getTargetSdkVersion() {
return targetSdkVersion;
}
public Integer getCompileSdkVersion() {
return compileSdkVersion;
}
public Integer getVersionCode() {
return versionCode;
}
public String getVersionName() {
return versionName;
}
public String getMainActivity() {
return mainActivity;
}
public JavaClass getMainActivityJavaClass(JadxDecompiler decompiler) {
return decompiler.searchJavaClassByAliasFullName(mainActivity);
}
public String getApplication() {
public @Nullable String getApplication() {
return application;
}
public JavaClass getApplicationJavaClass(JadxDecompiler decompiler) {
public void setApplication(@Nullable String application) {
this.application = application;
}
public @Nullable JavaClass getApplicationJavaClass(JadxDecompiler decompiler) {
if (application == null) {
return null;
}
return decompiler.searchJavaClassByAliasFullName(application);
}
public @Nullable String getApplicationLabel() {
return applicationLabel;
}
public void setApplicationLabel(@Nullable String applicationLabel) {
this.applicationLabel = applicationLabel;
}
public @Nullable String getMainActivity() {
return mainActivity;
}
public void setMainActivity(@Nullable String mainActivity) {
this.mainActivity = mainActivity;
}
public @Nullable JavaClass getMainActivityJavaClass(JadxDecompiler decompiler) {
if (mainActivity == null) {
return null;
}
return decompiler.searchJavaClassByAliasFullName(mainActivity);
}
public @Nullable Integer getCompileSdkVersion() {
return compileSdkVersion;
}
public void setCompileSdkVersion(@Nullable Integer compileSdkVersion) {
this.compileSdkVersion = compileSdkVersion;
}
public @Nullable Integer getMinSdkVersion() {
return minSdkVersion;
}
public void setMinSdkVersion(@Nullable Integer minSdkVersion) {
this.minSdkVersion = minSdkVersion;
}
public @Nullable Integer getTargetSdkVersion() {
return targetSdkVersion;
}
public void setTargetSdkVersion(@Nullable Integer targetSdkVersion) {
this.targetSdkVersion = targetSdkVersion;
}
public @Nullable Integer getVersionCode() {
return versionCode;
}
public void setVersionCode(@Nullable Integer versionCode) {
this.versionCode = versionCode;
}
public @Nullable String getVersionName() {
return versionName;
}
public void setVersionName(@Nullable String versionName) {
this.versionName = versionName;
}
}