Use NestedZip linking with copy fallback

Make APK packaging more robust by conditionally embedding the original APK (based on sigbypassLevel) and opening the source as either a NestedZip or a read-only ZFile. Attempt to add file links via NestedZip.addFileLink for entries, and fall back to copying the entry stream on failure or when source is read-only. Clean up related logic (remove the earlier separate embedding block), improve error messages, and minor reordering (minSdkVersion declaration) to streamline patch processing.
This commit is contained in:
NkBe 2026-02-10 21:45:38 +08:00
parent 834fefe421
commit f2713a342b
No known key found for this signature in database
GPG Key ID: 9FACEE0DB6DF678E
1 changed files with 32 additions and 19 deletions

View File

@ -195,8 +195,12 @@ public class NPatch {
logger.i("Parsing original apk..."); logger.i("Parsing original apk...");
boolean embedOriginal = sigbypassLevel >= Constants.SIGBYPASS_LV_PM_OPENAT;
try (ZFile dstZFile = ZFile.openReadWrite(outputFile, Z_FILE_OPTIONS); try (ZFile dstZFile = ZFile.openReadWrite(outputFile, Z_FILE_OPTIONS);
NestedZip srcZFile = dstZFile.addNestedZip((ignore) -> ORIGINAL_APK_ASSET_PATH, srcApkFile, false)) { ZFile srcZFile = embedOriginal
? dstZFile.addNestedZip((ignore) -> Constants.ORIGINAL_APK_ASSET_PATH, srcApkFile, false)
: ZFile.openReadOnly(srcApkFile)) {
// sign apk // sign apk
try { try {
@ -239,9 +243,9 @@ public class NPatch {
String newPackage = newPackageName; String newPackage = newPackageName;
int minSdkVersion;
// parse the app appComponentFactory full name from the manifest file // parse the app appComponentFactory full name from the manifest file
final String appComponentFactory; final String appComponentFactory;
int minSdkVersion;
ManifestParser.Pair pair; ManifestParser.Pair pair;
try (var is = manifestEntry.open()) { try (var is = manifestEntry.open()) {
pair = ManifestParser.parseManifestFile(is); pair = ManifestParser.parseManifestFile(is);
@ -253,7 +257,7 @@ public class NPatch {
logger.d("original appComponentFactory class: " + appComponentFactory); logger.d("original appComponentFactory class: " + appComponentFactory);
logger.d("original minSdkVersion: " + minSdkVersion); logger.d("original minSdkVersion: " + minSdkVersion);
if (newPackage == null || newPackage.isEmpty()){ if (newPackage == null || newPackage.isEmpty()) {
newPackage = pair.packageName; newPackage = pair.packageName;
} }
@ -270,7 +274,13 @@ public class NPatch {
if (dstZFile.get(name) != null) continue; if (dstZFile.get(name) != null) continue;
if (name.startsWith("META-INF") && (name.endsWith(".SF") || name.endsWith(".MF") || name.endsWith(".RSA"))) if (name.startsWith("META-INF") && (name.endsWith(".SF") || name.endsWith(".MF") || name.endsWith(".RSA")))
continue; continue;
srcZFile.addFileLink(name, name); if (srcZFile instanceof NestedZip) {
((NestedZip) srcZFile).addFileLink(name, name);
} else {
try (InputStream is = entry.open()) {
dstZFile.add(name, is);
}
}
} }
return; return;
} }
@ -309,14 +319,6 @@ public class NPatch {
} catch (Throwable e) { } catch (Throwable e) {
throw new PatchError("Error when adding dex", e); throw new PatchError("Error when adding dex", e);
} }
if (sigbypassLevel >= Constants.SIGBYPASS_LV_PM_OPENAT) {
logger.i("Embedding original apk for SigBypass...");
try (var is = new FileInputStream(srcApkFile)) {
dstZFile.add(Constants.ORIGINAL_APK_ASSET_PATH, is);
} catch (Throwable e) {
throw new PatchError("Error when embedding original apk", e);
}
}
if (isInjectProvider){ if (isInjectProvider){
try (var is = getClass().getClassLoader().getResourceAsStream("assets/mtprovider.dex")) { try (var is = getClass().getClassLoader().getResourceAsStream("assets/mtprovider.dex")) {
@ -371,14 +373,25 @@ public class NPatch {
if (name.startsWith("META-INF") && (name.endsWith(".SF") || name.endsWith(".MF") || name.endsWith(".RSA"))) if (name.startsWith("META-INF") && (name.endsWith(".SF") || name.endsWith(".MF") || name.endsWith(".RSA")))
continue; continue;
try (InputStream is = entry.open()) { boolean linked = false;
if (name.endsWith(".so") || name.equals("resources.arsc")) { if (srcZFile instanceof NestedZip) {
dstZFile.add(name, is, false); try {
} else { linked = ((NestedZip) srcZFile).addFileLink(name, name);
dstZFile.add(name, is); } catch (IOException e) {
logger.e("Failed to link entry: " + name + ", falling back to copy.");
}
}
if (!linked) {
try (InputStream is = entry.open()) {
if (name.endsWith(".so") || name.equals("resources.arsc")) {
dstZFile.add(name, is, false);
} else {
dstZFile.add(name, is);
}
} catch (IOException e) {
throw new PatchError("Failed to copy entry: " + name, e);
} }
} catch (IOException e) {
throw new PatchError("Failed to copy entry: " + name, e);
} }
} }