capacitor-dex-editor 0.0.73 → 0.0.75

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.
@@ -0,0 +1,255 @@
1
+ package com.aetherlink.dexeditor;
2
+
3
+ import android.util.Log;
4
+ import com.getcapacitor.JSArray;
5
+ import com.getcapacitor.JSObject;
6
+ import org.json.JSONArray;
7
+ import org.json.JSONObject;
8
+
9
+ import java.io.File;
10
+ import java.io.FileInputStream;
11
+ import java.io.FileOutputStream;
12
+ import java.util.zip.ZipEntry;
13
+ import java.util.zip.ZipFile;
14
+ import java.io.InputStream;
15
+ import java.io.ByteArrayOutputStream;
16
+
17
+ /**
18
+ * CppApkHelper - C++ APK/资源操作的封装类
19
+ * 处理 AndroidManifest.xml 和 resources.arsc 的解析和编辑
20
+ */
21
+ public class CppApkHelper {
22
+ private static final String TAG = "CppApkHelper";
23
+
24
+ /**
25
+ * 检查 C++ 库是否可用
26
+ */
27
+ public static boolean isAvailable() {
28
+ return CppDex.isAvailable();
29
+ }
30
+
31
+ // ==================== AndroidManifest.xml 操作 ====================
32
+
33
+ /**
34
+ * 解析 AndroidManifest.xml
35
+ */
36
+ public static JSObject parseManifest(byte[] axmlBytes) throws Exception {
37
+ String jsonResult = CppDex.parseAxml(axmlBytes);
38
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
39
+ throw new Exception("C++ parseAxml failed");
40
+ }
41
+
42
+ JSONObject cppResult = new JSONObject(jsonResult);
43
+ JSObject result = new JSObject();
44
+
45
+ result.put("packageName", cppResult.optString("packageName", ""));
46
+ result.put("versionCode", cppResult.optInt("versionCode", 0));
47
+ result.put("versionName", cppResult.optString("versionName", ""));
48
+ result.put("minSdkVersion", cppResult.optInt("minSdkVersion", 0));
49
+ result.put("targetSdkVersion", cppResult.optInt("targetSdkVersion", 0));
50
+
51
+ // 解析 activities
52
+ JSONArray activities = cppResult.optJSONArray("activities");
53
+ if (activities != null) {
54
+ JSArray activityArray = new JSArray();
55
+ for (int i = 0; i < activities.length(); i++) {
56
+ activityArray.put(activities.getString(i));
57
+ }
58
+ result.put("activities", activityArray);
59
+ }
60
+
61
+ // 解析 permissions
62
+ JSONArray permissions = cppResult.optJSONArray("permissions");
63
+ if (permissions != null) {
64
+ JSArray permArray = new JSArray();
65
+ for (int i = 0; i < permissions.length(); i++) {
66
+ permArray.put(permissions.getString(i));
67
+ }
68
+ result.put("permissions", permArray);
69
+ }
70
+
71
+ result.put("engine", "cpp");
72
+ return result;
73
+ }
74
+
75
+ /**
76
+ * 从 APK 文件解析 AndroidManifest.xml
77
+ */
78
+ public static JSObject parseManifestFromApk(String apkPath) throws Exception {
79
+ byte[] axmlBytes = readFileFromApk(apkPath, "AndroidManifest.xml");
80
+ return parseManifest(axmlBytes);
81
+ }
82
+
83
+ /**
84
+ * 编辑 AndroidManifest.xml 属性
85
+ * @param action 操作: set_package, set_version_name, set_version_code, set_min_sdk, set_target_sdk
86
+ */
87
+ public static byte[] editManifest(byte[] axmlBytes, String action, String value) throws Exception {
88
+ byte[] newAxmlBytes = CppDex.editManifest(axmlBytes, action, value);
89
+ if (newAxmlBytes == null) {
90
+ throw new Exception("C++ editManifest failed for action: " + action);
91
+ }
92
+ return newAxmlBytes;
93
+ }
94
+
95
+ /**
96
+ * 在 AndroidManifest.xml 中搜索
97
+ */
98
+ public static JSArray searchManifest(byte[] axmlBytes, String attrName, String value, int limit) throws Exception {
99
+ String jsonResult = CppDex.searchXml(axmlBytes, attrName, value, limit);
100
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
101
+ throw new Exception("C++ searchXml failed");
102
+ }
103
+
104
+ JSONObject cppResult = new JSONObject(jsonResult);
105
+ JSONArray cppResults = cppResult.optJSONArray("results");
106
+ JSArray results = new JSArray();
107
+ if (cppResults != null) {
108
+ for (int i = 0; i < cppResults.length(); i++) {
109
+ JSONObject r = cppResults.getJSONObject(i);
110
+ JSObject item = new JSObject();
111
+ item.put("element", r.optString("element"));
112
+ item.put("attribute", r.optString("attribute"));
113
+ item.put("value", r.optString("value"));
114
+ results.put(item);
115
+ }
116
+ }
117
+ return results;
118
+ }
119
+
120
+ // ==================== resources.arsc 操作 ====================
121
+
122
+ /**
123
+ * 解析 resources.arsc
124
+ */
125
+ public static JSObject parseArsc(byte[] arscBytes) throws Exception {
126
+ String jsonResult = CppDex.parseArsc(arscBytes);
127
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
128
+ throw new Exception("C++ parseArsc failed");
129
+ }
130
+
131
+ JSONObject cppResult = new JSONObject(jsonResult);
132
+ JSObject result = new JSObject();
133
+
134
+ result.put("packageCount", cppResult.optInt("packageCount", 0));
135
+ result.put("stringCount", cppResult.optInt("stringCount", 0));
136
+ result.put("typeCount", cppResult.optInt("typeCount", 0));
137
+
138
+ // 解析资源类型
139
+ JSONArray types = cppResult.optJSONArray("types");
140
+ if (types != null) {
141
+ JSArray typeArray = new JSArray();
142
+ for (int i = 0; i < types.length(); i++) {
143
+ typeArray.put(types.getString(i));
144
+ }
145
+ result.put("types", typeArray);
146
+ }
147
+
148
+ result.put("engine", "cpp");
149
+ return result;
150
+ }
151
+
152
+ /**
153
+ * 从 APK 文件解析 resources.arsc
154
+ */
155
+ public static JSObject parseArscFromApk(String apkPath) throws Exception {
156
+ byte[] arscBytes = readFileFromApk(apkPath, "resources.arsc");
157
+ return parseArsc(arscBytes);
158
+ }
159
+
160
+ /**
161
+ * 搜索 ARSC 字符串
162
+ */
163
+ public static JSArray searchArscStrings(byte[] arscBytes, String pattern, int limit) throws Exception {
164
+ String jsonResult = CppDex.searchArscStrings(arscBytes, pattern, limit);
165
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
166
+ throw new Exception("C++ searchArscStrings failed");
167
+ }
168
+
169
+ JSONObject cppResult = new JSONObject(jsonResult);
170
+ JSONArray cppResults = cppResult.optJSONArray("results");
171
+ JSArray results = new JSArray();
172
+ if (cppResults != null) {
173
+ for (int i = 0; i < cppResults.length(); i++) {
174
+ JSONObject r = cppResults.getJSONObject(i);
175
+ JSObject item = new JSObject();
176
+ item.put("value", r.optString("value"));
177
+ item.put("index", r.optInt("index"));
178
+ results.put(item);
179
+ }
180
+ }
181
+ return results;
182
+ }
183
+
184
+ /**
185
+ * 搜索 ARSC 资源
186
+ */
187
+ public static JSArray searchArscResources(byte[] arscBytes, String pattern, String type, int limit) throws Exception {
188
+ String jsonResult = CppDex.searchArscResources(arscBytes, pattern, type != null ? type : "", limit);
189
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
190
+ throw new Exception("C++ searchArscResources failed");
191
+ }
192
+
193
+ JSONObject cppResult = new JSONObject(jsonResult);
194
+ JSONArray cppResults = cppResult.optJSONArray("results");
195
+ JSArray results = new JSArray();
196
+ if (cppResults != null) {
197
+ for (int i = 0; i < cppResults.length(); i++) {
198
+ JSONObject r = cppResults.getJSONObject(i);
199
+ JSObject item = new JSObject();
200
+ item.put("name", r.optString("name"));
201
+ item.put("type", r.optString("type"));
202
+ item.put("value", r.optString("value"));
203
+ item.put("id", r.optString("id"));
204
+ results.put(item);
205
+ }
206
+ }
207
+ return results;
208
+ }
209
+
210
+ /**
211
+ * 从 APK 搜索 ARSC 字符串
212
+ */
213
+ public static JSArray searchArscStringsFromApk(String apkPath, String pattern, int limit) throws Exception {
214
+ byte[] arscBytes = readFileFromApk(apkPath, "resources.arsc");
215
+ return searchArscStrings(arscBytes, pattern, limit);
216
+ }
217
+
218
+ /**
219
+ * 从 APK 搜索 ARSC 资源
220
+ */
221
+ public static JSArray searchArscResourcesFromApk(String apkPath, String pattern, String type, int limit) throws Exception {
222
+ byte[] arscBytes = readFileFromApk(apkPath, "resources.arsc");
223
+ return searchArscResources(arscBytes, pattern, type, limit);
224
+ }
225
+
226
+ // ==================== 辅助方法 ====================
227
+
228
+ /**
229
+ * 从 APK 中读取文件
230
+ */
231
+ public static byte[] readFileFromApk(String apkPath, String entryName) throws Exception {
232
+ ZipFile zipFile = null;
233
+ try {
234
+ zipFile = new ZipFile(apkPath);
235
+ ZipEntry entry = zipFile.getEntry(entryName);
236
+ if (entry == null) {
237
+ throw new Exception("Entry not found in APK: " + entryName);
238
+ }
239
+
240
+ InputStream is = zipFile.getInputStream(entry);
241
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
242
+ byte[] buffer = new byte[8192];
243
+ int len;
244
+ while ((len = is.read(buffer)) != -1) {
245
+ baos.write(buffer, 0, len);
246
+ }
247
+ is.close();
248
+ return baos.toByteArray();
249
+ } finally {
250
+ if (zipFile != null) {
251
+ try { zipFile.close(); } catch (Exception ignored) {}
252
+ }
253
+ }
254
+ }
255
+ }
@@ -0,0 +1,368 @@
1
+ package com.aetherlink.dexeditor;
2
+
3
+ import android.util.Log;
4
+ import com.getcapacitor.JSArray;
5
+ import com.getcapacitor.JSObject;
6
+ import org.json.JSONArray;
7
+ import org.json.JSONObject;
8
+
9
+ /**
10
+ * CppDexHelper - C++ DEX 操作的封装类
11
+ * 提供高层 API,自动处理 JSON 解析和错误处理
12
+ */
13
+ public class CppDexHelper {
14
+ private static final String TAG = "CppDexHelper";
15
+
16
+ /**
17
+ * 检查 C++ 库是否可用
18
+ */
19
+ public static boolean isAvailable() {
20
+ return CppDex.isAvailable();
21
+ }
22
+
23
+ // ==================== DEX 信息获取 ====================
24
+
25
+ /**
26
+ * 获取 DEX 文件信息
27
+ */
28
+ public static JSObject getDexInfo(byte[] dexBytes) throws Exception {
29
+ String jsonResult = CppDex.getDexInfo(dexBytes);
30
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
31
+ throw new Exception("C++ getDexInfo failed");
32
+ }
33
+
34
+ JSONObject cppResult = new JSONObject(jsonResult);
35
+ JSObject info = new JSObject();
36
+ info.put("classCount", cppResult.optInt("classCount", 0));
37
+ info.put("methodCount", cppResult.optInt("methodCount", 0));
38
+ info.put("fieldCount", cppResult.optInt("fieldCount", 0));
39
+ info.put("stringCount", cppResult.optInt("stringCount", 0));
40
+ info.put("version", cppResult.optInt("version", 35));
41
+ info.put("engine", "cpp");
42
+ return info;
43
+ }
44
+
45
+ /**
46
+ * 列出类
47
+ */
48
+ public static JSArray listClasses(byte[] dexBytes, String packageFilter, int offset, int limit) throws Exception {
49
+ String jsonResult = CppDex.listClasses(dexBytes, packageFilter, offset, limit);
50
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
51
+ throw new Exception("C++ listClasses failed");
52
+ }
53
+
54
+ JSONObject cppResult = new JSONObject(jsonResult);
55
+ JSONArray cppClasses = cppResult.optJSONArray("classes");
56
+ JSArray classes = new JSArray();
57
+ if (cppClasses != null) {
58
+ for (int i = 0; i < cppClasses.length(); i++) {
59
+ classes.put(cppClasses.getString(i));
60
+ }
61
+ }
62
+ return classes;
63
+ }
64
+
65
+ /**
66
+ * 列出方法
67
+ */
68
+ public static JSArray listMethods(byte[] dexBytes, String className) throws Exception {
69
+ String jsonResult = CppDex.listMethods(dexBytes, className);
70
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
71
+ throw new Exception("C++ listMethods failed");
72
+ }
73
+
74
+ JSONObject cppResult = new JSONObject(jsonResult);
75
+ JSONArray cppMethods = cppResult.optJSONArray("methods");
76
+ JSArray methods = new JSArray();
77
+ if (cppMethods != null) {
78
+ for (int i = 0; i < cppMethods.length(); i++) {
79
+ JSONObject m = cppMethods.getJSONObject(i);
80
+ JSObject methodInfo = new JSObject();
81
+ methodInfo.put("name", m.optString("name"));
82
+ methodInfo.put("signature", m.optString("prototype"));
83
+ methodInfo.put("accessFlags", m.optInt("accessFlags"));
84
+ methods.put(methodInfo);
85
+ }
86
+ }
87
+ return methods;
88
+ }
89
+
90
+ /**
91
+ * 列出字段
92
+ */
93
+ public static JSArray listFields(byte[] dexBytes, String className) throws Exception {
94
+ String jsonResult = CppDex.listFields(dexBytes, className);
95
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
96
+ throw new Exception("C++ listFields failed");
97
+ }
98
+
99
+ JSONObject cppResult = new JSONObject(jsonResult);
100
+ JSONArray cppFields = cppResult.optJSONArray("fields");
101
+ JSArray fields = new JSArray();
102
+ if (cppFields != null) {
103
+ for (int i = 0; i < cppFields.length(); i++) {
104
+ JSONObject f = cppFields.getJSONObject(i);
105
+ JSObject fieldInfo = new JSObject();
106
+ fieldInfo.put("name", f.optString("name"));
107
+ fieldInfo.put("type", f.optString("type"));
108
+ fieldInfo.put("accessFlags", f.optInt("accessFlags"));
109
+ fields.put(fieldInfo);
110
+ }
111
+ }
112
+ return fields;
113
+ }
114
+
115
+ /**
116
+ * 列出字符串池
117
+ */
118
+ public static JSObject listStrings(byte[] dexBytes, String filter, int limit) throws Exception {
119
+ String jsonResult = CppDex.listStrings(dexBytes, filter != null ? filter : "", limit);
120
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
121
+ throw new Exception("C++ listStrings failed");
122
+ }
123
+
124
+ JSONObject cppResult = new JSONObject(jsonResult);
125
+ JSObject result = new JSObject();
126
+
127
+ JSONArray cppStrings = cppResult.optJSONArray("strings");
128
+ JSArray strings = new JSArray();
129
+ if (cppStrings != null) {
130
+ for (int i = 0; i < cppStrings.length(); i++) {
131
+ strings.put(cppStrings.getString(i));
132
+ }
133
+ }
134
+ result.put("strings", strings);
135
+ result.put("total", cppResult.optInt("total", strings.length()));
136
+ result.put("engine", "cpp");
137
+ return result;
138
+ }
139
+
140
+ // ==================== Smali 操作 ====================
141
+
142
+ /**
143
+ * 获取类的 Smali 代码
144
+ */
145
+ public static String getClassSmali(byte[] dexBytes, String className) throws Exception {
146
+ String jsonResult = CppDex.getClassSmali(dexBytes, className);
147
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
148
+ throw new Exception("C++ getClassSmali failed");
149
+ }
150
+
151
+ JSONObject cppResult = new JSONObject(jsonResult);
152
+ return cppResult.optString("smali", "");
153
+ }
154
+
155
+ /**
156
+ * 获取方法的 Smali 代码
157
+ */
158
+ public static String getMethodSmali(byte[] dexBytes, String className,
159
+ String methodName, String methodSignature) throws Exception {
160
+ String jsonResult = CppDex.getMethodSmali(dexBytes, className, methodName, methodSignature);
161
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
162
+ throw new Exception("C++ getMethodSmali failed");
163
+ }
164
+
165
+ JSONObject cppResult = new JSONObject(jsonResult);
166
+ return cppResult.optString("smali", "");
167
+ }
168
+
169
+ /**
170
+ * Smali 转 Java 伪代码
171
+ */
172
+ public static String smaliToJava(byte[] dexBytes, String className) throws Exception {
173
+ String jsonResult = CppDex.smaliToJava(dexBytes, className);
174
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
175
+ throw new Exception("C++ smaliToJava failed");
176
+ }
177
+
178
+ JSONObject cppResult = new JSONObject(jsonResult);
179
+ return cppResult.optString("java", "");
180
+ }
181
+
182
+ /**
183
+ * Smali 编译为 DEX
184
+ */
185
+ public static byte[] smaliToDex(String smaliCode) throws Exception {
186
+ byte[] dexBytes = CppDex.smaliToDex(smaliCode);
187
+ if (dexBytes == null || dexBytes.length == 0) {
188
+ throw new Exception("C++ smaliToDex failed");
189
+ }
190
+ return dexBytes;
191
+ }
192
+
193
+ // ==================== 搜索操作 ====================
194
+
195
+ /**
196
+ * 搜索字符串
197
+ */
198
+ public static JSArray searchStrings(byte[] dexBytes, String query,
199
+ boolean caseSensitive, int maxResults) throws Exception {
200
+ String jsonResult = CppDex.searchInDex(dexBytes, query, "string", caseSensitive, maxResults);
201
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
202
+ throw new Exception("C++ searchStrings failed");
203
+ }
204
+
205
+ JSONObject cppResult = new JSONObject(jsonResult);
206
+ JSONArray cppResults = cppResult.optJSONArray("results");
207
+ JSArray results = new JSArray();
208
+ if (cppResults != null) {
209
+ for (int i = 0; i < cppResults.length(); i++) {
210
+ JSONObject r = cppResults.getJSONObject(i);
211
+ JSObject item = new JSObject();
212
+ item.put("value", r.optString("value"));
213
+ item.put("index", r.optInt("index"));
214
+ results.put(item);
215
+ }
216
+ }
217
+ return results;
218
+ }
219
+
220
+ /**
221
+ * 搜索方法
222
+ */
223
+ public static JSArray searchMethods(byte[] dexBytes, String query, int maxResults) throws Exception {
224
+ String jsonResult = CppDex.searchInDex(dexBytes, query, "method", false, maxResults);
225
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
226
+ throw new Exception("C++ searchMethods failed");
227
+ }
228
+
229
+ JSONObject cppResult = new JSONObject(jsonResult);
230
+ JSONArray cppResults = cppResult.optJSONArray("results");
231
+ JSArray results = new JSArray();
232
+ if (cppResults != null) {
233
+ for (int i = 0; i < cppResults.length(); i++) {
234
+ JSONObject r = cppResults.getJSONObject(i);
235
+ JSObject item = new JSObject();
236
+ item.put("className", r.optString("className"));
237
+ item.put("methodName", r.optString("name"));
238
+ item.put("returnType", r.optString("returnType", ""));
239
+ results.put(item);
240
+ }
241
+ }
242
+ return results;
243
+ }
244
+
245
+ /**
246
+ * 搜索字段
247
+ */
248
+ public static JSArray searchFields(byte[] dexBytes, String query, int maxResults) throws Exception {
249
+ String jsonResult = CppDex.searchInDex(dexBytes, query, "field", false, maxResults);
250
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
251
+ throw new Exception("C++ searchFields failed");
252
+ }
253
+
254
+ JSONObject cppResult = new JSONObject(jsonResult);
255
+ JSONArray cppResults = cppResult.optJSONArray("results");
256
+ JSArray results = new JSArray();
257
+ if (cppResults != null) {
258
+ for (int i = 0; i < cppResults.length(); i++) {
259
+ JSONObject r = cppResults.getJSONObject(i);
260
+ JSObject item = new JSObject();
261
+ item.put("className", r.optString("className"));
262
+ item.put("fieldName", r.optString("name"));
263
+ item.put("fieldType", r.optString("type", ""));
264
+ results.put(item);
265
+ }
266
+ }
267
+ return results;
268
+ }
269
+
270
+ // ==================== 交叉引用分析 ====================
271
+
272
+ /**
273
+ * 查找方法交叉引用
274
+ */
275
+ public static JSObject findMethodXrefs(byte[] dexBytes, String className, String methodName) throws Exception {
276
+ String jsonResult = CppDex.findMethodXrefs(dexBytes, className, methodName);
277
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
278
+ throw new Exception("C++ findMethodXrefs failed");
279
+ }
280
+
281
+ JSONObject cppResult = new JSONObject(jsonResult);
282
+ JSObject result = new JSObject();
283
+ result.put("className", className);
284
+ result.put("methodName", methodName);
285
+
286
+ JSONArray xrefs = cppResult.optJSONArray("xrefs");
287
+ JSArray xrefArray = new JSArray();
288
+ if (xrefs != null) {
289
+ for (int i = 0; i < xrefs.length(); i++) {
290
+ JSONObject x = xrefs.getJSONObject(i);
291
+ JSObject xref = new JSObject();
292
+ xref.put("callerClass", x.optString("callerClass"));
293
+ xref.put("callerMethod", x.optString("callerMethod"));
294
+ xref.put("offset", x.optInt("offset"));
295
+ xrefArray.put(xref);
296
+ }
297
+ }
298
+ result.put("xrefs", xrefArray);
299
+ result.put("count", xrefArray.length());
300
+ return result;
301
+ }
302
+
303
+ /**
304
+ * 查找字段交叉引用
305
+ */
306
+ public static JSObject findFieldXrefs(byte[] dexBytes, String className, String fieldName) throws Exception {
307
+ String jsonResult = CppDex.findFieldXrefs(dexBytes, className, fieldName);
308
+ if (jsonResult == null || jsonResult.contains("\"error\"")) {
309
+ throw new Exception("C++ findFieldXrefs failed");
310
+ }
311
+
312
+ JSONObject cppResult = new JSONObject(jsonResult);
313
+ JSObject result = new JSObject();
314
+ result.put("className", className);
315
+ result.put("fieldName", fieldName);
316
+
317
+ JSONArray xrefs = cppResult.optJSONArray("xrefs");
318
+ JSArray xrefArray = new JSArray();
319
+ if (xrefs != null) {
320
+ for (int i = 0; i < xrefs.length(); i++) {
321
+ JSONObject x = xrefs.getJSONObject(i);
322
+ JSObject xref = new JSObject();
323
+ xref.put("accessorClass", x.optString("accessorClass"));
324
+ xref.put("accessorMethod", x.optString("accessorMethod"));
325
+ xref.put("accessType", x.optString("accessType"));
326
+ xrefArray.put(xref);
327
+ }
328
+ }
329
+ result.put("xrefs", xrefArray);
330
+ result.put("count", xrefArray.length());
331
+ return result;
332
+ }
333
+
334
+ // ==================== DEX 修改操作 ====================
335
+
336
+ /**
337
+ * 添加类
338
+ */
339
+ public static byte[] addClass(byte[] dexBytes, String smaliCode) throws Exception {
340
+ byte[] newDexBytes = CppDex.addClass(dexBytes, smaliCode);
341
+ if (newDexBytes == null) {
342
+ throw new Exception("C++ addClass failed");
343
+ }
344
+ return newDexBytes;
345
+ }
346
+
347
+ /**
348
+ * 删除类
349
+ */
350
+ public static byte[] deleteClass(byte[] dexBytes, String className) throws Exception {
351
+ byte[] newDexBytes = CppDex.deleteClass(dexBytes, className);
352
+ if (newDexBytes == null) {
353
+ throw new Exception("C++ deleteClass failed");
354
+ }
355
+ return newDexBytes;
356
+ }
357
+
358
+ /**
359
+ * 修改类
360
+ */
361
+ public static byte[] modifyClass(byte[] dexBytes, String className, String newSmali) throws Exception {
362
+ byte[] newDexBytes = CppDex.modifyClass(dexBytes, className, newSmali);
363
+ if (newDexBytes == null) {
364
+ throw new Exception("C++ modifyClass failed");
365
+ }
366
+ return newDexBytes;
367
+ }
368
+ }
@@ -358,6 +358,63 @@ public class DexEditorPluginPlugin extends Plugin {
358
358
  result.put("data", dexManager.getStrings(params.getString("sessionId")));
359
359
  break;
360
360
 
361
+ case "listStrings":
362
+ // C++ 实现的字符串列表
363
+ if (CppApkHelper.isAvailable()) {
364
+ byte[] dexBytes = dexManager.getSessionDexBytes(params.getString("sessionId"));
365
+ if (dexBytes != null) {
366
+ result.put("data", CppDexHelper.listStrings(
367
+ dexBytes,
368
+ params.optString("filter", ""),
369
+ params.optInt("limit", 100)
370
+ ));
371
+ }
372
+ }
373
+ break;
374
+
375
+ // ============ C++ APK/资源操作 ============
376
+ case "parseManifestCpp":
377
+ result.put("data", CppApkHelper.parseManifestFromApk(
378
+ params.getString("apkPath")
379
+ ));
380
+ break;
381
+
382
+ case "searchManifestCpp":
383
+ byte[] axmlBytes = CppApkHelper.readFileFromApk(
384
+ params.getString("apkPath"),
385
+ "AndroidManifest.xml"
386
+ );
387
+ result.put("data", CppApkHelper.searchManifest(
388
+ axmlBytes,
389
+ params.optString("attrName", ""),
390
+ params.optString("value", ""),
391
+ params.optInt("limit", 50)
392
+ ));
393
+ break;
394
+
395
+ case "parseArscCpp":
396
+ result.put("data", CppApkHelper.parseArscFromApk(
397
+ params.getString("apkPath")
398
+ ));
399
+ break;
400
+
401
+ case "searchArscStrings":
402
+ result.put("data", CppApkHelper.searchArscStringsFromApk(
403
+ params.getString("apkPath"),
404
+ params.getString("pattern"),
405
+ params.optInt("limit", 50)
406
+ ));
407
+ break;
408
+
409
+ case "searchArscResources":
410
+ result.put("data", CppApkHelper.searchArscResourcesFromApk(
411
+ params.getString("apkPath"),
412
+ params.getString("pattern"),
413
+ params.optString("type", ""),
414
+ params.optInt("limit", 50)
415
+ ));
416
+ break;
417
+
361
418
  case "modifyString":
362
419
  dexManager.modifyString(
363
420
  params.getString("sessionId"),
@@ -273,6 +273,14 @@ public class DexManager {
273
273
  Log.d(TAG, "Closed session: " + sessionId);
274
274
  }
275
275
 
276
+ /**
277
+ * 获取会话的 DEX 字节数据(用于 C++ 操作)
278
+ */
279
+ public byte[] getSessionDexBytes(String sessionId) {
280
+ DexSession session = sessions.get(sessionId);
281
+ return session != null ? session.dexBytes : null;
282
+ }
283
+
276
284
  /**
277
285
  * 获取 DEX 文件信息(优先使用 C++ 实现)
278
286
  */
@@ -641,28 +649,39 @@ public class DexManager {
641
649
  }
642
650
 
643
651
  /**
644
- * 设置方法的 Smali 代码
652
+ * 设置方法的 Smali 代码(优先使用 C++ 实现)
645
653
  */
646
654
  public void setMethodSmali(String sessionId, String className,
647
655
  String methodName, String methodSignature,
648
656
  String smaliCode) throws Exception {
649
657
  DexSession session = getSession(sessionId);
658
+
659
+ // 获取原类的 Smali 并替换方法
660
+ String classSmali = classToSmali(sessionId, className).getString("smali");
661
+ String modifiedSmali = replaceMethodInSmali(classSmali, methodName, methodSignature, smaliCode);
662
+
663
+ // 优先使用 C++ 实现
664
+ if (CppDex.isAvailable() && session.dexBytes != null) {
665
+ try {
666
+ byte[] newDexBytes = CppDex.modifyClass(session.dexBytes, className, modifiedSmali);
667
+ if (newDexBytes != null) {
668
+ session.dexBytes = newDexBytes;
669
+ session.modified = true;
670
+ Log.d(TAG, "Modified method via C++: " + className + "->" + methodName);
671
+ return;
672
+ }
673
+ } catch (Exception e) {
674
+ Log.w(TAG, "C++ modifyClass failed, fallback to Java", e);
675
+ }
676
+ }
677
+
678
+ // Java 回退实现
650
679
  ClassDef classDef = findClass(session, className);
651
-
652
680
  if (classDef == null) {
653
681
  throw new IllegalArgumentException("Class not found: " + className);
654
682
  }
655
-
656
- // 获取原类的 Smali
657
- String classSmali = classToSmali(sessionId, className).getString("smali");
658
683
 
659
- // 替换方法
660
- String modifiedSmali = replaceMethodInSmali(classSmali, methodName, methodSignature, smaliCode);
661
-
662
- // 重新编译
663
684
  ClassDef modifiedClass = compileSmaliToClass(modifiedSmali, session.originalDexFile.getOpcodes());
664
-
665
- // 更新会话
666
685
  session.removedClasses.add(className);
667
686
  session.modifiedClasses.add(modifiedClass);
668
687
  session.modified = true;
@@ -933,7 +952,7 @@ public class DexManager {
933
952
  }
934
953
 
935
954
  /**
936
- * 汇编 Smali 目录为 DEX
955
+ * 汇编 Smali 目录为 DEX(优先使用 C++ 实现)
937
956
  */
938
957
  public JSObject assemble(String smaliDir, String outputPath) throws Exception {
939
958
  File inputDir = new File(smaliDir);
@@ -944,7 +963,35 @@ public class DexManager {
944
963
  }
945
964
 
946
965
  outputFile.getParentFile().mkdirs();
966
+
967
+ // 优先使用 C++ 实现
968
+ if (CppDex.isAvailable()) {
969
+ try {
970
+ // 读取所有 smali 文件并合并
971
+ List<File> smaliFiles = collectSmaliFiles(inputDir);
972
+ StringBuilder allSmali = new StringBuilder();
973
+ for (File f : smaliFiles) {
974
+ allSmali.append(readFileContent(f));
975
+ allSmali.append("\n\n");
976
+ }
977
+
978
+ byte[] dexBytes = CppDex.smaliToDex(allSmali.toString());
979
+ if (dexBytes != null && dexBytes.length > 0) {
980
+ try (java.io.FileOutputStream fos = new java.io.FileOutputStream(outputFile)) {
981
+ fos.write(dexBytes);
982
+ }
983
+ JSObject result = new JSObject();
984
+ result.put("success", true);
985
+ result.put("outputPath", outputPath);
986
+ result.put("engine", "cpp");
987
+ return result;
988
+ }
989
+ } catch (Exception e) {
990
+ Log.w(TAG, "C++ smaliToDex failed, fallback to Java", e);
991
+ }
992
+ }
947
993
 
994
+ // Java 回退实现
948
995
  SmaliOptions options = new SmaliOptions();
949
996
  options.outputDexFile = outputPath;
950
997
 
@@ -959,6 +1006,7 @@ public class DexManager {
959
1006
  JSObject result = new JSObject();
960
1007
  result.put("success", success);
961
1008
  result.put("outputPath", outputPath);
1009
+ result.put("engine", "java");
962
1010
  return result;
963
1011
  }
964
1012
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-dex-editor",
3
- "version": "0.0.73",
3
+ "version": "0.0.75",
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",