capacitor-dex-editor 0.0.54 → 0.0.56

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.
@@ -98,6 +98,30 @@ public class DexManager {
98
98
 
99
99
  // 存储多 DEX 会话(MCP 工作流)
100
100
  private final Map<String, MultiDexSession> multiDexSessions = new HashMap<>();
101
+
102
+ // APK DEX 缓存 - 用于加速编译(key: apkPath + ":" + dexPath)
103
+ private final Map<String, ApkDexCache> apkDexCaches = new HashMap<>();
104
+
105
+ /**
106
+ * APK DEX 缓存 - 缓存从 APK 读取的 DEX 数据和 ClassDef
107
+ */
108
+ private static class ApkDexCache {
109
+ String apkPath;
110
+ String dexPath;
111
+ long lastModified;
112
+ Map<String, ClassDef> classDefMap; // type -> ClassDef
113
+ int dexVersion;
114
+
115
+ ApkDexCache(String apkPath, String dexPath) {
116
+ this.apkPath = apkPath;
117
+ this.dexPath = dexPath;
118
+ this.classDefMap = new HashMap<>();
119
+ }
120
+
121
+ String getCacheKey() {
122
+ return apkPath + ":" + dexPath;
123
+ }
124
+ }
101
125
 
102
126
  /**
103
127
  * DEX 会话 - 存储加载的 DEX 文件及其修改状态
@@ -2119,27 +2143,28 @@ public class DexManager {
2119
2143
  }
2120
2144
 
2121
2145
  /**
2122
- * APK 中的 DEX 文件获取类的 Smali 代码
2146
+ * 获取或创建 APK DEX 缓存
2123
2147
  */
2124
- public JSObject getClassSmaliFromApk(String apkPath, String dexPath, String className) throws Exception {
2125
- JSObject result = new JSObject();
2126
- StringBuilder smali = new StringBuilder();
2148
+ private ApkDexCache getOrCreateDexCache(String apkPath, String dexPath) throws Exception {
2149
+ String cacheKey = apkPath + ":" + dexPath;
2150
+ java.io.File apkFile = new java.io.File(apkPath);
2151
+ long currentModified = apkFile.lastModified();
2127
2152
 
2128
- Log.d(TAG, "getClassSmaliFromApk: apkPath=" + apkPath + ", dexPath=" + dexPath + ", className=" + className);
2153
+ ApkDexCache cache = apkDexCaches.get(cacheKey);
2129
2154
 
2130
- if (className == null || className.isEmpty()) {
2131
- result.put("smali", "# 未指定类名");
2132
- return result;
2155
+ // 检查缓存是否有效
2156
+ if (cache != null && cache.lastModified == currentModified && !cache.classDefMap.isEmpty()) {
2157
+ Log.d(TAG, "Using DEX cache for: " + cacheKey + " (" + cache.classDefMap.size() + " classes)");
2158
+ return cache;
2133
2159
  }
2134
2160
 
2135
- String targetType = convertClassNameToType(className);
2136
-
2137
- java.util.zip.ZipFile zipFile = null;
2138
- java.io.InputStream dexInputStream = null;
2161
+ // 需要重新加载
2162
+ Log.d(TAG, "Loading DEX into cache: " + cacheKey);
2163
+ cache = new ApkDexCache(apkPath, dexPath);
2164
+ cache.lastModified = currentModified;
2139
2165
 
2166
+ java.util.zip.ZipFile zipFile = new java.util.zip.ZipFile(apkPath);
2140
2167
  try {
2141
- zipFile = new java.util.zip.ZipFile(apkPath);
2142
-
2143
2168
  // 尝试多种可能的 dexPath 格式
2144
2169
  java.util.zip.ZipEntry dexEntry = zipFile.getEntry(dexPath);
2145
2170
  if (dexEntry == null) {
@@ -2154,33 +2179,70 @@ public class DexManager {
2154
2179
  }
2155
2180
 
2156
2181
  if (dexEntry == null) {
2157
- result.put("smali", "# DEX 文件未找到: " + dexPath);
2158
- return result;
2182
+ throw new Exception("DEX 文件未找到: " + dexPath);
2159
2183
  }
2160
2184
 
2161
- dexInputStream = zipFile.getInputStream(dexEntry);
2162
-
2163
- // 读取 DEX 文件到内存
2185
+ // 读取 DEX 文件
2186
+ java.io.InputStream dexInputStream = zipFile.getInputStream(dexEntry);
2164
2187
  java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
2165
- byte[] buffer = new byte[8192];
2188
+ byte[] buffer = new byte[16384];
2166
2189
  int len;
2167
2190
  while ((len = dexInputStream.read(buffer)) != -1) {
2168
2191
  baos.write(buffer, 0, len);
2169
2192
  }
2193
+ dexInputStream.close();
2170
2194
  byte[] dexBytes = baos.toByteArray();
2171
2195
 
2172
- // 解析 DEX 文件
2196
+ // 解析 DEX 文件并缓存所有 ClassDef
2173
2197
  DexBackedDexFile dexFile = new DexBackedDexFile(Opcodes.getDefault(), dexBytes);
2198
+ cache.dexVersion = 35; // 默认 DEX 版本
2174
2199
 
2175
- // 查找目标类
2176
- ClassDef targetClass = null;
2177
2200
  for (ClassDef classDef : dexFile.getClasses()) {
2178
- if (classDef.getType().equals(targetType)) {
2179
- targetClass = classDef;
2180
- break;
2181
- }
2201
+ cache.classDefMap.put(classDef.getType(), classDef);
2182
2202
  }
2183
2203
 
2204
+ Log.d(TAG, "Cached " + cache.classDefMap.size() + " classes from " + dexPath);
2205
+ } finally {
2206
+ zipFile.close();
2207
+ }
2208
+
2209
+ apkDexCaches.put(cacheKey, cache);
2210
+ return cache;
2211
+ }
2212
+
2213
+ /**
2214
+ * 清除指定 APK 的 DEX 缓存
2215
+ */
2216
+ public void clearDexCache(String apkPath) {
2217
+ java.util.Iterator<String> it = apkDexCaches.keySet().iterator();
2218
+ while (it.hasNext()) {
2219
+ if (it.next().startsWith(apkPath + ":")) {
2220
+ it.remove();
2221
+ }
2222
+ }
2223
+ Log.d(TAG, "Cleared DEX cache for: " + apkPath);
2224
+ }
2225
+
2226
+ /**
2227
+ * 从 APK 中的 DEX 文件获取类的 Smali 代码(使用缓存)
2228
+ */
2229
+ public JSObject getClassSmaliFromApk(String apkPath, String dexPath, String className) throws Exception {
2230
+ JSObject result = new JSObject();
2231
+
2232
+ Log.d(TAG, "getClassSmaliFromApk: apkPath=" + apkPath + ", dexPath=" + dexPath + ", className=" + className);
2233
+
2234
+ if (className == null || className.isEmpty()) {
2235
+ result.put("smali", "# 未指定类名");
2236
+ return result;
2237
+ }
2238
+
2239
+ String targetType = convertClassNameToType(className);
2240
+
2241
+ try {
2242
+ // 使用缓存获取 ClassDef
2243
+ ApkDexCache cache = getOrCreateDexCache(apkPath, dexPath);
2244
+ ClassDef targetClass = cache.classDefMap.get(targetType);
2245
+
2184
2246
  if (targetClass == null) {
2185
2247
  result.put("smali", "# 类未找到: " + className + "\n# 目标类型: " + targetType);
2186
2248
  return result;
@@ -2197,13 +2259,8 @@ public class DexManager {
2197
2259
 
2198
2260
  result.put("smali", stringWriter.toString());
2199
2261
 
2200
- } finally {
2201
- if (dexInputStream != null) {
2202
- try { dexInputStream.close(); } catch (Exception ignored) {}
2203
- }
2204
- if (zipFile != null) {
2205
- try { zipFile.close(); } catch (Exception ignored) {}
2206
- }
2262
+ } catch (Exception e) {
2263
+ result.put("smali", "# 加载失败: " + e.getMessage());
2207
2264
  }
2208
2265
 
2209
2266
  return result;
@@ -2232,112 +2289,74 @@ public class DexManager {
2232
2289
  }
2233
2290
 
2234
2291
  try {
2235
- // 创建临时目录存储 smali 文件(使用系统临时目录)
2236
- java.io.File tempDir = new java.io.File(System.getProperty("java.io.tmpdir"), "smali_temp_" + System.currentTimeMillis());
2237
- if (!tempDir.mkdirs()) {
2238
- result.put("success", false);
2239
- result.put("error", "无法创建临时目录");
2240
- return result;
2241
- }
2242
-
2243
- // 将类名转换为文件路径
2244
- String classPath = className.replace(".", "/") + ".smali";
2245
- java.io.File smaliFile = new java.io.File(tempDir, classPath);
2246
- smaliFile.getParentFile().mkdirs();
2247
-
2248
- // 写入 smali 文件
2249
- try (java.io.FileWriter writer = new java.io.FileWriter(smaliFile)) {
2250
- writer.write(smaliContent);
2251
- }
2292
+ // 使用优化的 smali2.Smali 直接编译成 ClassDef(无需临时文件)
2293
+ reportTitle("编译 Smali");
2294
+ reportMessage("正在编译 " + className + "...");
2295
+ reportProgress(10, 100);
2252
2296
 
2253
- Log.d(TAG, "Smali file written to: " + smaliFile.getAbsolutePath());
2254
-
2255
- // 使用 smali 库编译 smali 文件为 dex
2256
- // 注意:这需要 smali 库的支持
2257
- java.io.File outputDex = new java.io.File(tempDir, "classes_modified.dex");
2258
-
2259
- // 使用 SmaliOptions 编译
2260
2297
  com.android.tools.smali.smali.SmaliOptions options = new com.android.tools.smali.smali.SmaliOptions();
2261
- options.outputDexFile = outputDex.getAbsolutePath();
2262
2298
  options.apiLevel = 30;
2263
2299
 
2264
- java.util.List<String> inputFiles = new java.util.ArrayList<>();
2265
- inputFiles.add(smaliFile.getAbsolutePath());
2266
-
2267
- boolean success = com.android.tools.smali.smali.Smali.assemble(options, inputFiles);
2268
-
2269
- if (!success) {
2270
- result.put("success", false);
2271
- result.put("error", "Smali 编译失败");
2272
- cleanupTempDir(tempDir);
2273
- return result;
2274
- }
2275
-
2276
- Log.d(TAG, "Smali compiled successfully to: " + outputDex.getAbsolutePath());
2277
-
2278
- // 将编译后的类合并到原 DEX 文件中
2279
- // 1. 读取原 APK 中的 DEX 文件
2280
- java.util.zip.ZipFile zipFile = new java.util.zip.ZipFile(apkPath);
2281
- java.util.zip.ZipEntry dexEntry = zipFile.getEntry(dexPath);
2282
-
2283
- if (dexEntry == null) {
2300
+ // 直接编译 Smali 代码为 ClassDef
2301
+ ClassDef newClassDef;
2302
+ try {
2303
+ newClassDef = com.android.tools.smali.smali2.Smali.assemble(smaliContent, options, 35);
2304
+ } catch (Exception e) {
2284
2305
  result.put("success", false);
2285
- result.put("error", "DEX 文件未找到: " + dexPath);
2286
- zipFile.close();
2287
- cleanupTempDir(tempDir);
2306
+ result.put("error", "Smali 编译失败: " + e.getMessage());
2288
2307
  return result;
2289
2308
  }
2290
2309
 
2291
- // 读取原 DEX
2292
- java.io.InputStream dexInputStream = zipFile.getInputStream(dexEntry);
2293
- java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
2294
- byte[] buffer = new byte[8192];
2295
- int len;
2296
- while ((len = dexInputStream.read(buffer)) != -1) {
2297
- baos.write(buffer, 0, len);
2298
- }
2299
- byte[] originalDexBytes = baos.toByteArray();
2300
- dexInputStream.close();
2310
+ reportProgress(20, 100);
2311
+ Log.d(TAG, "Smali compiled successfully to ClassDef");
2301
2312
 
2302
- // 解析原 DEX 和新编译的 DEX
2303
- DexBackedDexFile originalDex = new DexBackedDexFile(Opcodes.getDefault(), originalDexBytes);
2304
- DexBackedDexFile newDex = DexBackedDexFile.fromInputStream(Opcodes.getDefault(),
2305
- new java.io.BufferedInputStream(new java.io.FileInputStream(outputDex)));
2313
+ // 使用缓存获取 ClassDef(核心优化)
2314
+ reportTitle("合并 DEX");
2315
+ reportMessage("获取缓存...");
2306
2316
 
2307
- // 合并 DEX:用新类替换原类
2308
2317
  String targetType = "L" + className.replace(".", "/") + ";";
2309
- java.util.List<ClassDef> mergedClasses = new java.util.ArrayList<>();
2318
+ ApkDexCache cache = getOrCreateDexCache(apkPath, dexPath);
2310
2319
 
2311
- // 添加原 DEX 中除目标类外的所有类
2312
- for (ClassDef classDef : originalDex.getClasses()) {
2313
- if (!classDef.getType().equals(targetType)) {
2314
- mergedClasses.add(classDef);
2315
- }
2316
- }
2320
+ reportProgress(30, 100);
2321
+ reportMessage("更新缓存...");
2317
2322
 
2318
- // 添加新编译的类
2319
- for (ClassDef classDef : newDex.getClasses()) {
2320
- mergedClasses.add(classDef);
2321
- }
2323
+ // 更新缓存中的 ClassDef
2324
+ cache.classDefMap.put(targetType, newClassDef);
2322
2325
 
2323
- Log.d(TAG, "Merged " + mergedClasses.size() + " classes");
2326
+ Log.d(TAG, "Using cached " + cache.classDefMap.size() + " classes");
2327
+
2328
+ // 创建新的 DEX 文件(使用缓存的 ClassDef)
2329
+ reportMessage("写入 DEX (" + cache.classDefMap.size() + " 个类)...");
2330
+ reportProgress(40, 100);
2324
2331
 
2325
- // 创建新的 DEX 文件
2326
- java.io.File mergedDexFile = new java.io.File(tempDir, "classes_merged.dex");
2327
2332
  DexPool dexPool = new DexPool(Opcodes.getDefault());
2328
- for (ClassDef classDef : mergedClasses) {
2333
+ int totalClasses = cache.classDefMap.size();
2334
+ int currentClass = 0;
2335
+ for (ClassDef classDef : cache.classDefMap.values()) {
2329
2336
  dexPool.internClass(classDef);
2337
+ currentClass++;
2338
+ if (currentClass % 200 == 0 || currentClass == totalClasses) {
2339
+ reportProgress(40 + (currentClass * 40 / totalClasses), 100);
2340
+ }
2330
2341
  }
2331
- dexPool.writeTo(new FileDataStore(mergedDexFile));
2332
2342
 
2333
- Log.d(TAG, "Merged DEX written to: " + mergedDexFile.getAbsolutePath());
2343
+ // 使用内存写入 DEX(避免临时文件)
2344
+ reportProgress(80, 100);
2345
+ reportMessage("生成 DEX...");
2346
+ com.android.tools.smali.dexlib2.writer.io.MemoryDataStore memoryStore =
2347
+ new com.android.tools.smali.dexlib2.writer.io.MemoryDataStore();
2348
+ dexPool.writeTo(memoryStore);
2349
+ byte[] newDexBytes = java.util.Arrays.copyOf(memoryStore.getBuffer(), memoryStore.getSize());
2334
2350
 
2335
- zipFile.close();
2351
+ Log.d(TAG, "Merged DEX size: " + newDexBytes.length + " bytes");
2336
2352
 
2337
2353
  // MT 风格:直接替换 APK 内的 DEX
2354
+ reportTitle("更新 APK");
2355
+ reportMessage("正在替换 DEX...");
2356
+ reportProgress(85, 100);
2357
+
2338
2358
  java.io.File apkFile = new java.io.File(apkPath);
2339
2359
  java.io.File tempApkFile = new java.io.File(apkPath + ".tmp");
2340
- byte[] newDexBytes = readFileBytes(mergedDexFile);
2341
2360
 
2342
2361
  Log.d(TAG, "Replacing DEX in APK (MT style)...");
2343
2362
 
@@ -2393,15 +2412,16 @@ public class DexManager {
2393
2412
  }
2394
2413
 
2395
2414
  Log.d(TAG, "APK updated successfully: " + apkPath);
2415
+ reportProgress(100, 100);
2416
+
2417
+ // 更新缓存的 lastModified 以匹配新的 APK
2418
+ cache.lastModified = new java.io.File(apkPath).lastModified();
2396
2419
 
2397
2420
  result.put("success", true);
2398
2421
  result.put("message", "Smali 编译成功!APK 已更新");
2399
2422
  result.put("apkPath", apkPath);
2400
2423
  result.put("needSign", true);
2401
2424
 
2402
- // 清理临时文件
2403
- cleanupTempDir(tempDir);
2404
-
2405
2425
  } catch (Exception e) {
2406
2426
  Log.e(TAG, "Error saving smali: " + e.getMessage(), e);
2407
2427
  result.put("success", false);
@@ -0,0 +1,102 @@
1
+ /*
2
+ * Based on Dex-Editor-Android by developer-krushna
3
+ * Original Author @MikeAndrson
4
+ *
5
+ * 直接将 Smali 代码编译成 ClassDef,无需临时文件
6
+ */
7
+
8
+ package com.android.tools.smali.smali2;
9
+
10
+ import com.android.tools.smali.dexlib2.Opcodes;
11
+ import com.android.tools.smali.dexlib2.iface.ClassDef;
12
+ import com.android.tools.smali.dexlib2.writer.builder.DexBuilder;
13
+ import com.android.tools.smali.smali.SmaliOptions;
14
+
15
+ import java.io.StringReader;
16
+ import org.antlr.runtime.CommonTokenStream;
17
+ import org.antlr.runtime.tree.CommonTree;
18
+ import org.antlr.runtime.tree.CommonTreeNodeStream;
19
+
20
+ public class Smali {
21
+
22
+ public static ClassDef assemble(String smaliCode, SmaliOptions options, int dexVer)
23
+ throws Exception {
24
+ DexBuilder dexBuilder = new DexBuilder(Opcodes.forDexVersion(dexVer));
25
+
26
+ SmaliCatchErrFlexLexer lexer = new SmaliCatchErrFlexLexer(new StringReader(smaliCode), options.apiLevel);
27
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
28
+
29
+ SmaliCatchErrParser parser = new SmaliCatchErrParser(tokens);
30
+ parser.setVerboseErrors(options.verboseErrors);
31
+ parser.setAllowOdex(options.allowOdexOpcodes);
32
+ parser.setApiLevel(dexVer);
33
+
34
+ SmaliCatchErrParser.smali_file_return result = parser.smali_file();
35
+
36
+ if (lexer.getNumberOfSyntaxErrors() > 0) {
37
+ throw new Exception(lexer.getErrorsString());
38
+ }
39
+
40
+ if (parser.getNumberOfSyntaxErrors() > 0) {
41
+ throw new Exception(parser.getErrorsString());
42
+ }
43
+
44
+ CommonTree t = result.getTree();
45
+
46
+ CommonTreeNodeStream treeStream = new CommonTreeNodeStream(t);
47
+ treeStream.setTokenStream(tokens);
48
+
49
+ SmaliCatchErrTreeWalker treeWalker = new SmaliCatchErrTreeWalker(treeStream);
50
+ treeWalker.setApiLevel(dexVer);
51
+ treeWalker.setVerboseErrors(options.verboseErrors);
52
+ treeWalker.setDexBuilder(dexBuilder);
53
+
54
+ ClassDef classDef = treeWalker.smali_file();
55
+
56
+ if (treeWalker.getNumberOfSyntaxErrors() > 0) {
57
+ throw new Exception(treeWalker.getErrorsString());
58
+ }
59
+
60
+ return classDef;
61
+ }
62
+
63
+ public static ClassDef assemble(String smaliCode, SmaliOptions options) throws Exception {
64
+ DexBuilder dexBuilder = new DexBuilder(Opcodes.forApi(options.apiLevel));
65
+
66
+ SmaliCatchErrFlexLexer lexer = new SmaliCatchErrFlexLexer(new StringReader(smaliCode), options.apiLevel);
67
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
68
+
69
+ SmaliCatchErrParser parser = new SmaliCatchErrParser(tokens);
70
+ parser.setVerboseErrors(options.verboseErrors);
71
+ parser.setAllowOdex(options.allowOdexOpcodes);
72
+ parser.setApiLevel(options.apiLevel);
73
+
74
+ SmaliCatchErrParser.smali_file_return result = parser.smali_file();
75
+
76
+ if (lexer.getNumberOfSyntaxErrors() > 0) {
77
+ throw new Exception(lexer.getErrorsString());
78
+ }
79
+
80
+ if (parser.getNumberOfSyntaxErrors() > 0) {
81
+ throw new Exception(parser.getErrorsString());
82
+ }
83
+
84
+ CommonTree t = result.getTree();
85
+
86
+ CommonTreeNodeStream treeStream = new CommonTreeNodeStream(t);
87
+ treeStream.setTokenStream(tokens);
88
+
89
+ SmaliCatchErrTreeWalker treeWalker = new SmaliCatchErrTreeWalker(treeStream);
90
+ treeWalker.setApiLevel(options.apiLevel);
91
+ treeWalker.setVerboseErrors(options.verboseErrors);
92
+ treeWalker.setDexBuilder(dexBuilder);
93
+
94
+ ClassDef classDef = treeWalker.smali_file();
95
+
96
+ if (treeWalker.getNumberOfSyntaxErrors() > 0) {
97
+ throw new Exception(treeWalker.getErrorsString());
98
+ }
99
+
100
+ return classDef;
101
+ }
102
+ }
@@ -0,0 +1,54 @@
1
+ /*
2
+ * Based on Dex-Editor-Android by developer-krushna
3
+ * Original Author @MikeAndrson
4
+ */
5
+
6
+ package com.android.tools.smali.smali2;
7
+
8
+ import com.android.tools.smali.smali.InvalidToken;
9
+ import com.android.tools.smali.smali.smaliFlexLexer;
10
+
11
+ import java.io.Reader;
12
+ import java.util.ArrayList;
13
+ import java.util.List;
14
+
15
+ public class SmaliCatchErrFlexLexer extends smaliFlexLexer {
16
+
17
+ private StringBuilder errors = new StringBuilder();
18
+ private List<SyntaxError> syntaxErrors = new ArrayList<>();
19
+
20
+ public SmaliCatchErrFlexLexer(Reader reader, int apiLevel) {
21
+ super(reader, apiLevel);
22
+ }
23
+
24
+ @Override
25
+ public String getErrorHeader(InvalidToken invalidToken) {
26
+ errors.append("[")
27
+ .append(invalidToken.getLine())
28
+ .append(",")
29
+ .append(invalidToken.getCharPositionInLine())
30
+ .append("] Error for input '")
31
+ .append(invalidToken.getText())
32
+ .append("': ")
33
+ .append(invalidToken.getMessage())
34
+ .append("\n");
35
+
36
+ syntaxErrors.add(new SyntaxError(
37
+ invalidToken.getLine(),
38
+ invalidToken.getCharPositionInLine(),
39
+ invalidToken.getLine(),
40
+ invalidToken.getCharPositionInLine() + invalidToken.getText().length(),
41
+ invalidToken.getMessage()
42
+ ));
43
+
44
+ return super.getErrorHeader(invalidToken);
45
+ }
46
+
47
+ public String getErrorsString() {
48
+ return errors.toString();
49
+ }
50
+
51
+ public List<SyntaxError> getErrors() {
52
+ return syntaxErrors;
53
+ }
54
+ }
@@ -0,0 +1,49 @@
1
+ /*
2
+ * Based on Dex-Editor-Android by developer-krushna
3
+ * Original Author @MikeAndrson
4
+ */
5
+
6
+ package com.android.tools.smali.smali2;
7
+
8
+ import org.antlr.runtime.CommonTokenStream;
9
+ import org.antlr.runtime.RecognitionException;
10
+ import com.android.tools.smali.smali.smaliParser;
11
+
12
+ import java.util.ArrayList;
13
+ import java.util.List;
14
+
15
+ public class SmaliCatchErrParser extends smaliParser {
16
+
17
+ private StringBuilder errors = new StringBuilder();
18
+ private List<SyntaxError> syntaxErrors = new ArrayList<>();
19
+
20
+ public SmaliCatchErrParser(CommonTokenStream tokens) {
21
+ super(tokens);
22
+ }
23
+
24
+ @Override
25
+ public void emitErrorMessage(String msg) {
26
+ errors.append(msg).append("\n");
27
+ }
28
+
29
+ public String getErrorsString() {
30
+ return errors.toString();
31
+ }
32
+
33
+ @Override
34
+ public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
35
+ syntaxErrors.add(new SyntaxError(
36
+ e.line,
37
+ e.charPositionInLine,
38
+ e.line,
39
+ e.charPositionInLine + (e.token != null ? e.token.getText().length() : 1),
40
+ getErrorMessage(e, tokenNames)
41
+ ));
42
+
43
+ super.displayRecognitionError(tokenNames, e);
44
+ }
45
+
46
+ public List<SyntaxError> getErrors() {
47
+ return syntaxErrors;
48
+ }
49
+ }
@@ -0,0 +1,49 @@
1
+ /*
2
+ * Based on Dex-Editor-Android by developer-krushna
3
+ * Original Author @MikeAndrson
4
+ */
5
+
6
+ package com.android.tools.smali.smali2;
7
+
8
+ import org.antlr.runtime.RecognitionException;
9
+ import org.antlr.runtime.tree.CommonTreeNodeStream;
10
+ import com.android.tools.smali.smali.smaliTreeWalker;
11
+
12
+ import java.util.ArrayList;
13
+ import java.util.List;
14
+
15
+ public class SmaliCatchErrTreeWalker extends smaliTreeWalker {
16
+
17
+ private StringBuilder errors = new StringBuilder();
18
+ private List<SyntaxError> syntaxErrors = new ArrayList<>();
19
+
20
+ public SmaliCatchErrTreeWalker(CommonTreeNodeStream treeStream) {
21
+ super(treeStream);
22
+ }
23
+
24
+ @Override
25
+ public void emitErrorMessage(String msg) {
26
+ errors.append(msg);
27
+ errors.append("\n");
28
+ }
29
+
30
+ public String getErrorsString() {
31
+ return errors.toString();
32
+ }
33
+
34
+ @Override
35
+ public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
36
+ syntaxErrors.add(new SyntaxError(
37
+ e.line,
38
+ e.charPositionInLine,
39
+ e.line,
40
+ e.charPositionInLine + (e.token != null ? e.token.getText().length() : 1),
41
+ getErrorMessage(e, tokenNames)
42
+ ));
43
+ super.displayRecognitionError(tokenNames, e);
44
+ }
45
+
46
+ public List<SyntaxError> getErrors() {
47
+ return syntaxErrors;
48
+ }
49
+ }
@@ -0,0 +1,42 @@
1
+ /*
2
+ * Based on Dex-Editor-Android by developer-krushna
3
+ * Original Author @MikeAndrson
4
+ */
5
+
6
+ package com.android.tools.smali.smali2;
7
+
8
+ public class SyntaxError {
9
+ private final int startLine;
10
+ private final int startColumn;
11
+ private final int endLine;
12
+ private final int endColumn;
13
+ private final String message;
14
+
15
+ public SyntaxError(int startLine, int startColumn, int endLine, int endColumn, String message) {
16
+ this.startLine = startLine;
17
+ this.startColumn = startColumn;
18
+ this.endLine = endLine;
19
+ this.endColumn = endColumn;
20
+ this.message = message;
21
+ }
22
+
23
+ public int getStartLine() {
24
+ return startLine;
25
+ }
26
+
27
+ public int getStartColumn() {
28
+ return startColumn;
29
+ }
30
+
31
+ public int getEndLine() {
32
+ return endLine;
33
+ }
34
+
35
+ public int getEndColumn() {
36
+ return endColumn;
37
+ }
38
+
39
+ public String getMessage() {
40
+ return message;
41
+ }
42
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-dex-editor",
3
- "version": "0.0.54",
3
+ "version": "0.0.56",
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",