capacitor-dex-editor 0.0.37 → 0.0.38

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.
@@ -538,6 +538,25 @@ public class DexEditorPluginPlugin extends Plugin {
538
538
  ));
539
539
  break;
540
540
 
541
+ case "listApkFiles":
542
+ result.put("data", dexManager.listApkFiles(
543
+ params.getString("apkPath"),
544
+ params.optString("filter", ""),
545
+ params.optInt("limit", 100),
546
+ params.optInt("offset", 0)
547
+ ));
548
+ break;
549
+
550
+ case "readApkFile":
551
+ result.put("data", dexManager.readApkFile(
552
+ params.getString("apkPath"),
553
+ params.getString("filePath"),
554
+ params.optBoolean("asBase64", false),
555
+ params.optInt("maxBytes", 0),
556
+ params.optInt("offset", 0)
557
+ ));
558
+ break;
559
+
541
560
  default:
542
561
  result.put("success", false);
543
562
  result.put("error", "Unknown action: " + action);
@@ -2973,6 +2973,171 @@ public class DexManager {
2973
2973
  return pos + 2;
2974
2974
  }
2975
2975
 
2976
+ /**
2977
+ * 列出 APK 中的所有文件
2978
+ */
2979
+ public JSObject listApkFiles(String apkPath, String filter, int limit, int offset) throws Exception {
2980
+ JSObject result = new JSObject();
2981
+ JSArray files = new JSArray();
2982
+
2983
+ java.util.zip.ZipFile zipFile = null;
2984
+ try {
2985
+ zipFile = new java.util.zip.ZipFile(apkPath);
2986
+ java.util.Enumeration<? extends java.util.zip.ZipEntry> entries = zipFile.entries();
2987
+
2988
+ java.util.List<JSObject> allFiles = new java.util.ArrayList<>();
2989
+
2990
+ while (entries.hasMoreElements()) {
2991
+ java.util.zip.ZipEntry entry = entries.nextElement();
2992
+ String name = entry.getName();
2993
+
2994
+ // 应用过滤
2995
+ if (!filter.isEmpty() && !name.contains(filter)) {
2996
+ continue;
2997
+ }
2998
+
2999
+ JSObject fileInfo = new JSObject();
3000
+ fileInfo.put("path", name);
3001
+ fileInfo.put("size", entry.getSize());
3002
+ fileInfo.put("compressedSize", entry.getCompressedSize());
3003
+ fileInfo.put("isDirectory", entry.isDirectory());
3004
+
3005
+ // 判断文件类型
3006
+ String type = "unknown";
3007
+ if (name.endsWith(".dex")) type = "dex";
3008
+ else if (name.endsWith(".so")) type = "native";
3009
+ else if (name.endsWith(".xml")) type = "xml";
3010
+ else if (name.startsWith("res/")) type = "resource";
3011
+ else if (name.startsWith("assets/")) type = "asset";
3012
+ else if (name.startsWith("lib/")) type = "native";
3013
+ else if (name.startsWith("META-INF/")) type = "meta";
3014
+ else if (name.equals("AndroidManifest.xml")) type = "manifest";
3015
+ else if (name.equals("resources.arsc")) type = "arsc";
3016
+ fileInfo.put("type", type);
3017
+
3018
+ allFiles.add(fileInfo);
3019
+ }
3020
+
3021
+ int total = allFiles.size();
3022
+
3023
+ // 分页
3024
+ int start = Math.min(offset, total);
3025
+ int end = Math.min(offset + limit, total);
3026
+
3027
+ for (int i = start; i < end; i++) {
3028
+ files.put(allFiles.get(i));
3029
+ }
3030
+
3031
+ result.put("files", files);
3032
+ result.put("total", total);
3033
+ result.put("offset", offset);
3034
+ result.put("limit", limit);
3035
+ result.put("returned", files.length());
3036
+ result.put("hasMore", end < total);
3037
+
3038
+ } finally {
3039
+ if (zipFile != null) {
3040
+ try { zipFile.close(); } catch (Exception ignored) {}
3041
+ }
3042
+ }
3043
+
3044
+ return result;
3045
+ }
3046
+
3047
+ /**
3048
+ * 读取 APK 中的任意文件
3049
+ */
3050
+ public JSObject readApkFile(String apkPath, String filePath, boolean asBase64, int maxBytes, int offset) throws Exception {
3051
+ JSObject result = new JSObject();
3052
+
3053
+ java.util.zip.ZipFile zipFile = null;
3054
+ try {
3055
+ zipFile = new java.util.zip.ZipFile(apkPath);
3056
+ java.util.zip.ZipEntry entry = zipFile.getEntry(filePath);
3057
+
3058
+ if (entry == null) {
3059
+ result.put("error", "File not found: " + filePath);
3060
+ return result;
3061
+ }
3062
+
3063
+ result.put("path", filePath);
3064
+ result.put("size", entry.getSize());
3065
+ result.put("compressedSize", entry.getCompressedSize());
3066
+
3067
+ java.io.InputStream is = zipFile.getInputStream(entry);
3068
+
3069
+ // 跳过偏移量
3070
+ if (offset > 0) {
3071
+ is.skip(offset);
3072
+ }
3073
+
3074
+ // 读取数据
3075
+ int readSize = maxBytes > 0 ? maxBytes : (int) entry.getSize();
3076
+ if (readSize > 1024 * 1024) { // 限制最大 1MB
3077
+ readSize = 1024 * 1024;
3078
+ }
3079
+
3080
+ byte[] buffer = new byte[readSize];
3081
+ int totalRead = 0;
3082
+ int read;
3083
+ while (totalRead < readSize && (read = is.read(buffer, totalRead, readSize - totalRead)) != -1) {
3084
+ totalRead += read;
3085
+ }
3086
+ is.close();
3087
+
3088
+ byte[] data = new byte[totalRead];
3089
+ System.arraycopy(buffer, 0, data, 0, totalRead);
3090
+
3091
+ if (asBase64) {
3092
+ // Base64 编码返回
3093
+ result.put("content", android.util.Base64.encodeToString(data, android.util.Base64.NO_WRAP));
3094
+ result.put("encoding", "base64");
3095
+ } else {
3096
+ // 尝试作为文本返回
3097
+ String content = new String(data, java.nio.charset.StandardCharsets.UTF_8);
3098
+
3099
+ // 检查是否是二进制文件
3100
+ boolean isBinary = false;
3101
+ for (int i = 0; i < Math.min(100, data.length); i++) {
3102
+ if (data[i] == 0) {
3103
+ isBinary = true;
3104
+ break;
3105
+ }
3106
+ }
3107
+
3108
+ if (isBinary && !filePath.endsWith(".xml")) {
3109
+ // 二进制文件自动使用 Base64
3110
+ result.put("content", android.util.Base64.encodeToString(data, android.util.Base64.NO_WRAP));
3111
+ result.put("encoding", "base64");
3112
+ result.put("note", "Binary file, auto-encoded as base64");
3113
+ } else {
3114
+ // 如果是 XML 文件,尝试解码 AXML
3115
+ if (filePath.endsWith(".xml") && data.length > 4) {
3116
+ int magic = (data[0] & 0xFF) | ((data[1] & 0xFF) << 8) |
3117
+ ((data[2] & 0xFF) << 16) | ((data[3] & 0xFF) << 24);
3118
+ if (magic == 0x00080003) {
3119
+ // 是 AXML 格式,解码
3120
+ content = AxmlParser.decode(data);
3121
+ }
3122
+ }
3123
+ result.put("content", content);
3124
+ result.put("encoding", "text");
3125
+ }
3126
+ }
3127
+
3128
+ result.put("offset", offset);
3129
+ result.put("bytesRead", totalRead);
3130
+ result.put("hasMore", offset + totalRead < entry.getSize());
3131
+
3132
+ } finally {
3133
+ if (zipFile != null) {
3134
+ try { zipFile.close(); } catch (Exception ignored) {}
3135
+ }
3136
+ }
3137
+
3138
+ return result;
3139
+ }
3140
+
2976
3141
  /**
2977
3142
  * 清理临时目录
2978
3143
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-dex-editor",
3
- "version": "0.0.37",
3
+ "version": "0.0.38",
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",