From f2713a342be8f26ecaf271ac9bd046553f96124d Mon Sep 17 00:00:00 2001 From: NkBe Date: Tue, 10 Feb 2026 21:45:38 +0800 Subject: [PATCH] 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. --- .../main/java/org/lsposed/patch/NPatch.java | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/patch/src/main/java/org/lsposed/patch/NPatch.java b/patch/src/main/java/org/lsposed/patch/NPatch.java index 876eb85..bdb9a97 100644 --- a/patch/src/main/java/org/lsposed/patch/NPatch.java +++ b/patch/src/main/java/org/lsposed/patch/NPatch.java @@ -195,8 +195,12 @@ public class NPatch { logger.i("Parsing original apk..."); + boolean embedOriginal = sigbypassLevel >= Constants.SIGBYPASS_LV_PM_OPENAT; + 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 try { @@ -239,9 +243,9 @@ public class NPatch { String newPackage = newPackageName; + int minSdkVersion; // parse the app appComponentFactory full name from the manifest file final String appComponentFactory; - int minSdkVersion; ManifestParser.Pair pair; try (var is = manifestEntry.open()) { pair = ManifestParser.parseManifestFile(is); @@ -253,7 +257,7 @@ public class NPatch { logger.d("original appComponentFactory class: " + appComponentFactory); logger.d("original minSdkVersion: " + minSdkVersion); - if (newPackage == null || newPackage.isEmpty()){ + if (newPackage == null || newPackage.isEmpty()) { newPackage = pair.packageName; } @@ -270,7 +274,13 @@ public class NPatch { if (dstZFile.get(name) != null) continue; if (name.startsWith("META-INF") && (name.endsWith(".SF") || name.endsWith(".MF") || name.endsWith(".RSA"))) 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; } @@ -309,14 +319,6 @@ public class NPatch { } catch (Throwable 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){ 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"))) continue; - try (InputStream is = entry.open()) { - if (name.endsWith(".so") || name.equals("resources.arsc")) { - dstZFile.add(name, is, false); - } else { - dstZFile.add(name, is); + boolean linked = false; + if (srcZFile instanceof NestedZip) { + try { + linked = ((NestedZip) srcZFile).addFileLink(name, name); + } 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); } }