capacitor-dex-editor 0.0.1

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,400 @@
1
+ package com.aetherlink.dexeditor;
2
+
3
+ import android.util.Log;
4
+
5
+ import com.getcapacitor.JSObject;
6
+ import com.getcapacitor.Plugin;
7
+ import com.getcapacitor.PluginCall;
8
+ import com.getcapacitor.PluginMethod;
9
+ import com.getcapacitor.annotation.CapacitorPlugin;
10
+
11
+ import org.json.JSONObject;
12
+
13
+ /**
14
+ * DEX编辑器 Capacitor 插件
15
+ * 通用执行器模式 - 通过 action 参数分发到对应的 dexlib2 操作
16
+ */
17
+ @CapacitorPlugin(name = "DexEditorPlugin")
18
+ public class DexEditorPluginPlugin extends Plugin {
19
+
20
+ private static final String TAG = "DexEditorPlugin";
21
+ private final DexManager dexManager = new DexManager();
22
+ private final ApkManager apkManager = new ApkManager();
23
+
24
+ @Override
25
+ public void load() {
26
+ super.load();
27
+ apkManager.setContext(getContext());
28
+ }
29
+
30
+ /**
31
+ * 通用执行器入口
32
+ * 所有 dexlib2 操作都通过此方法分发
33
+ */
34
+ @PluginMethod
35
+ public void execute(PluginCall call) {
36
+ String action = call.getString("action");
37
+ JSObject params = call.getObject("params");
38
+
39
+ if (action == null || action.isEmpty()) {
40
+ call.reject("Action is required");
41
+ return;
42
+ }
43
+
44
+ Log.d(TAG, "Executing action: " + action);
45
+
46
+ // 在后台线程执行,避免阻塞UI
47
+ getActivity().runOnUiThread(() -> {
48
+ try {
49
+ JSObject result = dispatchAction(action, params);
50
+ call.resolve(result);
51
+ } catch (Exception e) {
52
+ Log.e(TAG, "Action failed: " + action, e);
53
+ JSObject error = new JSObject();
54
+ error.put("success", false);
55
+ error.put("error", e.getMessage());
56
+ call.resolve(error);
57
+ }
58
+ });
59
+ }
60
+
61
+ /**
62
+ * 分发操作到对应的处理方法
63
+ */
64
+ private JSObject dispatchAction(String action, JSObject params) throws Exception {
65
+ JSObject result = new JSObject();
66
+ result.put("success", true);
67
+
68
+ switch (action) {
69
+ // ============ DEX文件操作 ============
70
+ case "loadDex":
71
+ result.put("data", dexManager.loadDex(
72
+ params.getString("path"),
73
+ params.optString("sessionId", null)
74
+ ));
75
+ break;
76
+
77
+ case "saveDex":
78
+ dexManager.saveDex(
79
+ params.getString("sessionId"),
80
+ params.getString("outputPath")
81
+ );
82
+ break;
83
+
84
+ case "closeDex":
85
+ dexManager.closeDex(params.getString("sessionId"));
86
+ break;
87
+
88
+ case "getDexInfo":
89
+ result.put("data", dexManager.getDexInfo(params.getString("sessionId")));
90
+ break;
91
+
92
+ // ============ 类操作 ============
93
+ case "getClasses":
94
+ result.put("data", dexManager.getClasses(params.getString("sessionId")));
95
+ break;
96
+
97
+ case "getClassInfo":
98
+ result.put("data", dexManager.getClassInfo(
99
+ params.getString("sessionId"),
100
+ params.getString("className")
101
+ ));
102
+ break;
103
+
104
+ case "addClass":
105
+ dexManager.addClass(
106
+ params.getString("sessionId"),
107
+ params.getString("smaliCode")
108
+ );
109
+ break;
110
+
111
+ case "removeClass":
112
+ dexManager.removeClass(
113
+ params.getString("sessionId"),
114
+ params.getString("className")
115
+ );
116
+ break;
117
+
118
+ case "renameClass":
119
+ dexManager.renameClass(
120
+ params.getString("sessionId"),
121
+ params.getString("oldName"),
122
+ params.getString("newName")
123
+ );
124
+ break;
125
+
126
+ // ============ 方法操作 ============
127
+ case "getMethods":
128
+ result.put("data", dexManager.getMethods(
129
+ params.getString("sessionId"),
130
+ params.getString("className")
131
+ ));
132
+ break;
133
+
134
+ case "getMethodInfo":
135
+ result.put("data", dexManager.getMethodInfo(
136
+ params.getString("sessionId"),
137
+ params.getString("className"),
138
+ params.getString("methodName"),
139
+ params.getString("methodSignature")
140
+ ));
141
+ break;
142
+
143
+ case "getMethodSmali":
144
+ result.put("data", dexManager.getMethodSmali(
145
+ params.getString("sessionId"),
146
+ params.getString("className"),
147
+ params.getString("methodName"),
148
+ params.getString("methodSignature")
149
+ ));
150
+ break;
151
+
152
+ case "setMethodSmali":
153
+ dexManager.setMethodSmali(
154
+ params.getString("sessionId"),
155
+ params.getString("className"),
156
+ params.getString("methodName"),
157
+ params.getString("methodSignature"),
158
+ params.getString("smaliCode")
159
+ );
160
+ break;
161
+
162
+ case "addMethod":
163
+ dexManager.addMethod(
164
+ params.getString("sessionId"),
165
+ params.getString("className"),
166
+ params.getString("smaliCode")
167
+ );
168
+ break;
169
+
170
+ case "removeMethod":
171
+ dexManager.removeMethod(
172
+ params.getString("sessionId"),
173
+ params.getString("className"),
174
+ params.getString("methodName"),
175
+ params.getString("methodSignature")
176
+ );
177
+ break;
178
+
179
+ // ============ 字段操作 ============
180
+ case "getFields":
181
+ result.put("data", dexManager.getFields(
182
+ params.getString("sessionId"),
183
+ params.getString("className")
184
+ ));
185
+ break;
186
+
187
+ case "getFieldInfo":
188
+ result.put("data", dexManager.getFieldInfo(
189
+ params.getString("sessionId"),
190
+ params.getString("className"),
191
+ params.getString("fieldName")
192
+ ));
193
+ break;
194
+
195
+ case "addField":
196
+ dexManager.addField(
197
+ params.getString("sessionId"),
198
+ params.getString("className"),
199
+ params.getString("fieldDef")
200
+ );
201
+ break;
202
+
203
+ case "removeField":
204
+ dexManager.removeField(
205
+ params.getString("sessionId"),
206
+ params.getString("className"),
207
+ params.getString("fieldName")
208
+ );
209
+ break;
210
+
211
+ // ============ Smali操作 ============
212
+ case "classToSmali":
213
+ result.put("data", dexManager.classToSmali(
214
+ params.getString("sessionId"),
215
+ params.getString("className")
216
+ ));
217
+ break;
218
+
219
+ case "smaliToClass":
220
+ dexManager.smaliToClass(
221
+ params.getString("sessionId"),
222
+ params.getString("smaliCode")
223
+ );
224
+ break;
225
+
226
+ case "disassemble":
227
+ dexManager.disassemble(
228
+ params.getString("sessionId"),
229
+ params.getString("outputDir")
230
+ );
231
+ break;
232
+
233
+ case "assemble":
234
+ result.put("data", dexManager.assemble(
235
+ params.getString("smaliDir"),
236
+ params.getString("outputPath")
237
+ ));
238
+ break;
239
+
240
+ // ============ 搜索操作 ============
241
+ case "searchString":
242
+ result.put("data", dexManager.searchString(
243
+ params.getString("sessionId"),
244
+ params.getString("query"),
245
+ params.optBoolean("regex", false),
246
+ params.optBoolean("caseSensitive", false)
247
+ ));
248
+ break;
249
+
250
+ case "searchCode":
251
+ result.put("data", dexManager.searchCode(
252
+ params.getString("sessionId"),
253
+ params.getString("query"),
254
+ params.optBoolean("regex", false)
255
+ ));
256
+ break;
257
+
258
+ case "searchMethod":
259
+ result.put("data", dexManager.searchMethod(
260
+ params.getString("sessionId"),
261
+ params.getString("query")
262
+ ));
263
+ break;
264
+
265
+ case "searchField":
266
+ result.put("data", dexManager.searchField(
267
+ params.getString("sessionId"),
268
+ params.getString("query")
269
+ ));
270
+ break;
271
+
272
+ // ============ 工具操作 ============
273
+ case "fixDex":
274
+ dexManager.fixDex(
275
+ params.getString("inputPath"),
276
+ params.getString("outputPath")
277
+ );
278
+ break;
279
+
280
+ case "mergeDex":
281
+ dexManager.mergeDex(
282
+ params.getJSONArray("inputPaths"),
283
+ params.getString("outputPath")
284
+ );
285
+ break;
286
+
287
+ case "splitDex":
288
+ result.put("data", dexManager.splitDex(
289
+ params.getString("sessionId"),
290
+ params.getInt("maxClasses")
291
+ ));
292
+ break;
293
+
294
+ case "getStrings":
295
+ result.put("data", dexManager.getStrings(params.getString("sessionId")));
296
+ break;
297
+
298
+ case "modifyString":
299
+ dexManager.modifyString(
300
+ params.getString("sessionId"),
301
+ params.getString("oldString"),
302
+ params.getString("newString")
303
+ );
304
+ break;
305
+
306
+ // ============ APK 操作 ============
307
+ case "openApk":
308
+ result.put("data", apkManager.openApk(
309
+ params.getString("apkPath"),
310
+ params.optString("extractDir", null)
311
+ ));
312
+ break;
313
+
314
+ case "closeApk":
315
+ apkManager.closeApk(
316
+ params.getString("sessionId"),
317
+ params.optBoolean("deleteExtracted", true)
318
+ );
319
+ break;
320
+
321
+ case "getApkInfo":
322
+ result.put("data", apkManager.getApkInfo(params.getString("apkPath")));
323
+ break;
324
+
325
+ case "listApkContents":
326
+ result.put("data", apkManager.listApkContents(params.getString("apkPath")));
327
+ break;
328
+
329
+ case "extractFile":
330
+ result.put("data", apkManager.extractFile(
331
+ params.getString("apkPath"),
332
+ params.getString("entryName"),
333
+ params.getString("outputPath")
334
+ ));
335
+ break;
336
+
337
+ case "replaceFile":
338
+ apkManager.replaceFile(
339
+ params.getString("sessionId"),
340
+ params.getString("entryName"),
341
+ params.getString("newFilePath")
342
+ );
343
+ break;
344
+
345
+ case "addFile":
346
+ apkManager.addFile(
347
+ params.getString("sessionId"),
348
+ params.getString("entryName"),
349
+ params.getString("filePath")
350
+ );
351
+ break;
352
+
353
+ case "deleteFile":
354
+ apkManager.deleteFile(
355
+ params.getString("sessionId"),
356
+ params.getString("entryName")
357
+ );
358
+ break;
359
+
360
+ case "repackApk":
361
+ result.put("data", apkManager.repackApk(
362
+ params.getString("sessionId"),
363
+ params.getString("outputPath")
364
+ ));
365
+ break;
366
+
367
+ case "signApk":
368
+ result.put("data", apkManager.signApk(
369
+ params.getString("apkPath"),
370
+ params.getString("outputPath"),
371
+ params.getString("keystorePath"),
372
+ params.getString("keystorePassword"),
373
+ params.getString("keyAlias"),
374
+ params.getString("keyPassword")
375
+ ));
376
+ break;
377
+
378
+ case "signApkWithTestKey":
379
+ result.put("data", apkManager.signApkWithTestKey(
380
+ params.getString("apkPath"),
381
+ params.getString("outputPath")
382
+ ));
383
+ break;
384
+
385
+ case "getApkSignature":
386
+ result.put("data", apkManager.getApkSignature(params.getString("apkPath")));
387
+ break;
388
+
389
+ case "getSessionDexFiles":
390
+ result.put("data", apkManager.getSessionDexFiles(params.getString("sessionId")));
391
+ break;
392
+
393
+ default:
394
+ result.put("success", false);
395
+ result.put("error", "Unknown action: " + action);
396
+ }
397
+
398
+ return result;
399
+ }
400
+ }