capacitor-dex-editor 0.0.17 → 0.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1679,20 +1679,127 @@ public class DexManager {
1679
1679
 
1680
1680
  Log.d(TAG, "Smali compiled successfully to: " + outputDex.getAbsolutePath());
1681
1681
 
1682
- // TODO: 将编译后的 dex 合并回原 APK
1683
- // 这是一个复杂的操作,需要:
1684
- // 1. 解压 APK
1685
- // 2. 替换/合并 DEX 文件中的类
1686
- // 3. 重新打包 APK
1687
- // 4. 重新签名 APK
1688
-
1689
- // 目前先返回成功,实际保存功能需要更多实现
1682
+ // 将编译后的类合并到原 DEX 文件中
1683
+ // 1. 读取原 APK 中的 DEX 文件
1684
+ java.util.zip.ZipFile zipFile = new java.util.zip.ZipFile(apkPath);
1685
+ java.util.zip.ZipEntry dexEntry = zipFile.getEntry(dexPath);
1686
+
1687
+ if (dexEntry == null) {
1688
+ result.put("success", false);
1689
+ result.put("error", "DEX 文件未找到: " + dexPath);
1690
+ zipFile.close();
1691
+ cleanupTempDir(tempDir);
1692
+ return result;
1693
+ }
1694
+
1695
+ // 读取原 DEX
1696
+ java.io.InputStream dexInputStream = zipFile.getInputStream(dexEntry);
1697
+ java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
1698
+ byte[] buffer = new byte[8192];
1699
+ int len;
1700
+ while ((len = dexInputStream.read(buffer)) != -1) {
1701
+ baos.write(buffer, 0, len);
1702
+ }
1703
+ byte[] originalDexBytes = baos.toByteArray();
1704
+ dexInputStream.close();
1705
+
1706
+ // 解析原 DEX 和新编译的 DEX
1707
+ DexBackedDexFile originalDex = new DexBackedDexFile(Opcodes.getDefault(), originalDexBytes);
1708
+ DexBackedDexFile newDex = DexBackedDexFile.fromInputStream(Opcodes.getDefault(),
1709
+ new java.io.BufferedInputStream(new java.io.FileInputStream(outputDex)));
1710
+
1711
+ // 合并 DEX:用新类替换原类
1712
+ String targetType = "L" + className.replace(".", "/") + ";";
1713
+ java.util.List<ClassDef> mergedClasses = new java.util.ArrayList<>();
1714
+
1715
+ // 添加原 DEX 中除目标类外的所有类
1716
+ for (ClassDef classDef : originalDex.getClasses()) {
1717
+ if (!classDef.getType().equals(targetType)) {
1718
+ mergedClasses.add(classDef);
1719
+ }
1720
+ }
1721
+
1722
+ // 添加新编译的类
1723
+ for (ClassDef classDef : newDex.getClasses()) {
1724
+ mergedClasses.add(classDef);
1725
+ }
1726
+
1727
+ Log.d(TAG, "Merged " + mergedClasses.size() + " classes");
1728
+
1729
+ // 创建新的 DEX 文件
1730
+ java.io.File mergedDexFile = new java.io.File(tempDir, "classes_merged.dex");
1731
+ DexPool dexPool = new DexPool(Opcodes.getDefault());
1732
+ for (ClassDef classDef : mergedClasses) {
1733
+ dexPool.internClass(classDef);
1734
+ }
1735
+ dexPool.writeTo(new FileDataStore(mergedDexFile));
1736
+
1737
+ Log.d(TAG, "Merged DEX written to: " + mergedDexFile.getAbsolutePath());
1738
+
1739
+ // 2. 创建新的 APK(复制原 APK 并替换 DEX)
1740
+ java.io.File outputApk = new java.io.File(apkPath + ".modified.apk");
1741
+ java.util.zip.ZipOutputStream zos = new java.util.zip.ZipOutputStream(
1742
+ new java.io.FileOutputStream(outputApk));
1743
+
1744
+ // 复制原 APK 中的所有条目(除了要替换的 DEX)
1745
+ java.util.Enumeration<? extends java.util.zip.ZipEntry> entries = zipFile.entries();
1746
+ while (entries.hasMoreElements()) {
1747
+ java.util.zip.ZipEntry entry = entries.nextElement();
1748
+ if (entry.getName().equals(dexPath)) {
1749
+ // 跳过原 DEX,稍后添加新的
1750
+ continue;
1751
+ }
1752
+
1753
+ // 复制其他条目
1754
+ java.util.zip.ZipEntry newEntry = new java.util.zip.ZipEntry(entry.getName());
1755
+ zos.putNextEntry(newEntry);
1756
+
1757
+ if (!entry.isDirectory()) {
1758
+ java.io.InputStream is = zipFile.getInputStream(entry);
1759
+ while ((len = is.read(buffer)) != -1) {
1760
+ zos.write(buffer, 0, len);
1761
+ }
1762
+ is.close();
1763
+ }
1764
+ zos.closeEntry();
1765
+ }
1766
+
1767
+ // 添加修改后的 DEX
1768
+ java.util.zip.ZipEntry newDexEntry = new java.util.zip.ZipEntry(dexPath);
1769
+ zos.putNextEntry(newDexEntry);
1770
+ java.io.FileInputStream fis = new java.io.FileInputStream(mergedDexFile);
1771
+ while ((len = fis.read(buffer)) != -1) {
1772
+ zos.write(buffer, 0, len);
1773
+ }
1774
+ fis.close();
1775
+ zos.closeEntry();
1776
+
1777
+ zos.close();
1778
+ zipFile.close();
1779
+
1780
+ Log.d(TAG, "Modified APK written to: " + outputApk.getAbsolutePath());
1781
+
1782
+ // 3. 替换原 APK(先备份)
1783
+ java.io.File backupApk = new java.io.File(apkPath + ".backup");
1784
+ java.io.File originalApkFile = new java.io.File(apkPath);
1785
+
1786
+ // 复制原 APK 作为备份
1787
+ copyFile(originalApkFile, backupApk);
1788
+
1789
+ // 用修改后的 APK 替换原 APK
1790
+ copyFile(outputApk, originalApkFile);
1791
+
1792
+ // 删除临时修改的 APK
1793
+ outputApk.delete();
1794
+
1795
+ Log.d(TAG, "APK updated successfully. Backup at: " + backupApk.getAbsolutePath());
1796
+
1690
1797
  result.put("success", true);
1691
- result.put("message", "Smali 编译成功,但完整保存功能需要进一步实现");
1692
- result.put("compiledDexPath", outputDex.getAbsolutePath());
1798
+ result.put("message", "Smali 保存成功!已更新 APK");
1799
+ result.put("backupPath", backupApk.getAbsolutePath());
1693
1800
 
1694
- // 清理临时文件(暂时保留以便调试)
1695
- // cleanupTempDir(tempDir);
1801
+ // 清理临时文件
1802
+ cleanupTempDir(tempDir);
1696
1803
 
1697
1804
  } catch (Exception e) {
1698
1805
  Log.e(TAG, "Error saving smali: " + e.getMessage(), e);
@@ -1703,6 +1810,21 @@ public class DexManager {
1703
1810
  return result;
1704
1811
  }
1705
1812
 
1813
+ /**
1814
+ * 复制文件
1815
+ */
1816
+ private void copyFile(java.io.File src, java.io.File dst) throws java.io.IOException {
1817
+ java.io.FileInputStream fis = new java.io.FileInputStream(src);
1818
+ java.io.FileOutputStream fos = new java.io.FileOutputStream(dst);
1819
+ byte[] buffer = new byte[8192];
1820
+ int len;
1821
+ while ((len = fis.read(buffer)) != -1) {
1822
+ fos.write(buffer, 0, len);
1823
+ }
1824
+ fis.close();
1825
+ fos.close();
1826
+ }
1827
+
1706
1828
  /**
1707
1829
  * 清理临时目录
1708
1830
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-dex-editor",
3
- "version": "0.0.17",
3
+ "version": "0.0.18",
4
4
  "description": "Capacitor-plugin-for-editing-DEX-files-in-APK",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",