capacitor-dex-editor 0.0.28 → 0.0.30
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.
|
@@ -1,289 +1,298 @@
|
|
|
1
1
|
package com.aetherlink.dexeditor;
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import java.nio.ByteBuffer;
|
|
5
|
-
import java.nio.ByteOrder;
|
|
3
|
+
import android.util.Log;
|
|
6
4
|
|
|
7
5
|
/**
|
|
8
6
|
* 简单的 AXML (Android Binary XML) 解析器
|
|
9
7
|
* 用于解码 APK 中的二进制 XML 文件
|
|
10
8
|
*/
|
|
11
9
|
public class AxmlParser {
|
|
12
|
-
|
|
10
|
+
|
|
11
|
+
private static final String TAG = "AxmlParser";
|
|
12
|
+
|
|
13
13
|
// AXML 文件头魔数
|
|
14
14
|
private static final int AXML_MAGIC = 0x00080003;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
private static final int
|
|
18
|
-
private static final int
|
|
19
|
-
private static final int
|
|
20
|
-
|
|
21
|
-
private
|
|
22
|
-
private
|
|
23
|
-
private static final int CHUNK_TEXT = 0x00100104;
|
|
24
|
-
|
|
25
|
-
private ByteBuffer buffer;
|
|
15
|
+
private static final int STRING_POOL_TYPE = 0x0001;
|
|
16
|
+
private static final int XML_START_TAG = 0x0102;
|
|
17
|
+
private static final int XML_END_TAG = 0x0103;
|
|
18
|
+
private static final int XML_START_NAMESPACE = 0x0100;
|
|
19
|
+
private static final int XML_END_NAMESPACE = 0x0101;
|
|
20
|
+
|
|
21
|
+
private byte[] data;
|
|
22
|
+
private int position;
|
|
26
23
|
private String[] stringPool;
|
|
27
24
|
private StringBuilder xml;
|
|
28
25
|
private int indent = 0;
|
|
29
|
-
|
|
26
|
+
|
|
30
27
|
/**
|
|
31
28
|
* 解码 AXML 数据为可读 XML 字符串
|
|
32
29
|
*/
|
|
33
|
-
public static String decode(byte[] data)
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
public static String decode(byte[] data) {
|
|
31
|
+
try {
|
|
32
|
+
AxmlParser parser = new AxmlParser();
|
|
33
|
+
return parser.parse(data);
|
|
34
|
+
} catch (Exception e) {
|
|
35
|
+
Log.e(TAG, "AXML parse error", e);
|
|
36
|
+
return "<!-- AXML Parse Error: " + e.getMessage() + " -->";
|
|
37
|
+
}
|
|
36
38
|
}
|
|
37
|
-
|
|
39
|
+
|
|
38
40
|
private String parse(byte[] data) throws Exception {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
xml = new StringBuilder();
|
|
42
|
-
|
|
41
|
+
this.data = data;
|
|
42
|
+
this.position = 0;
|
|
43
|
+
this.xml = new StringBuilder();
|
|
44
|
+
this.xml.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
|
|
45
|
+
|
|
43
46
|
// 读取文件头
|
|
44
|
-
int magic =
|
|
47
|
+
int magic = readInt();
|
|
45
48
|
if (magic != AXML_MAGIC) {
|
|
46
|
-
throw new Exception("Invalid AXML magic: " + Integer.toHexString(magic));
|
|
49
|
+
throw new Exception("Invalid AXML magic: 0x" + Integer.toHexString(magic));
|
|
47
50
|
}
|
|
48
|
-
|
|
49
|
-
int fileSize =
|
|
50
|
-
|
|
51
|
-
//
|
|
52
|
-
while (
|
|
53
|
-
int
|
|
54
|
-
int
|
|
55
|
-
int
|
|
56
|
-
|
|
51
|
+
|
|
52
|
+
int fileSize = readInt();
|
|
53
|
+
|
|
54
|
+
// 解析 chunks
|
|
55
|
+
while (position < data.length - 8) {
|
|
56
|
+
int chunkStart = position;
|
|
57
|
+
int chunkType = readShort();
|
|
58
|
+
int headerSize = readShort();
|
|
59
|
+
int chunkSize = readInt();
|
|
60
|
+
|
|
61
|
+
if (chunkSize <= 0 || chunkStart + chunkSize > data.length) {
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
|
|
57
65
|
switch (chunkType) {
|
|
58
|
-
case
|
|
59
|
-
parseStringPool(chunkSize);
|
|
60
|
-
break;
|
|
61
|
-
case CHUNK_RESOURCE_IDS:
|
|
62
|
-
// 跳过资源 ID
|
|
63
|
-
buffer.position(startPos + chunkSize);
|
|
66
|
+
case STRING_POOL_TYPE:
|
|
67
|
+
parseStringPool(chunkStart, chunkSize);
|
|
64
68
|
break;
|
|
65
|
-
case
|
|
66
|
-
|
|
69
|
+
case XML_START_NAMESPACE:
|
|
70
|
+
case XML_END_NAMESPACE:
|
|
71
|
+
// 跳过命名空间
|
|
67
72
|
break;
|
|
68
|
-
case
|
|
69
|
-
parseEndNamespace();
|
|
70
|
-
break;
|
|
71
|
-
case CHUNK_START_TAG:
|
|
73
|
+
case XML_START_TAG:
|
|
72
74
|
parseStartTag();
|
|
73
75
|
break;
|
|
74
|
-
case
|
|
76
|
+
case XML_END_TAG:
|
|
75
77
|
parseEndTag();
|
|
76
78
|
break;
|
|
77
|
-
case CHUNK_TEXT:
|
|
78
|
-
parseText();
|
|
79
|
-
break;
|
|
80
79
|
default:
|
|
81
80
|
// 跳过未知 chunk
|
|
82
|
-
buffer.position(startPos + chunkSize);
|
|
83
81
|
break;
|
|
84
82
|
}
|
|
83
|
+
|
|
84
|
+
// 移动到下一个 chunk
|
|
85
|
+
position = chunkStart + chunkSize;
|
|
85
86
|
}
|
|
86
|
-
|
|
87
|
+
|
|
87
88
|
return xml.toString();
|
|
88
89
|
}
|
|
89
|
-
|
|
90
|
-
private void parseStringPool(int chunkSize) {
|
|
91
|
-
int stringCount =
|
|
92
|
-
int styleCount =
|
|
93
|
-
int flags =
|
|
94
|
-
int stringsOffset =
|
|
95
|
-
int stylesOffset =
|
|
96
|
-
|
|
90
|
+
|
|
91
|
+
private void parseStringPool(int chunkStart, int chunkSize) {
|
|
92
|
+
int stringCount = readInt();
|
|
93
|
+
int styleCount = readInt();
|
|
94
|
+
int flags = readInt();
|
|
95
|
+
int stringsOffset = readInt();
|
|
96
|
+
int stylesOffset = readInt();
|
|
97
|
+
|
|
98
|
+
boolean isUtf8 = (flags & 0x100) != 0;
|
|
99
|
+
|
|
97
100
|
// 读取字符串偏移表
|
|
98
|
-
int[]
|
|
101
|
+
int[] offsets = new int[stringCount];
|
|
99
102
|
for (int i = 0; i < stringCount; i++) {
|
|
100
|
-
|
|
103
|
+
offsets[i] = readInt();
|
|
101
104
|
}
|
|
102
|
-
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
buffer.getInt();
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// 读取字符串
|
|
109
|
-
int stringsStart = buffer.position();
|
|
105
|
+
|
|
106
|
+
// 字符串数据开始位置
|
|
107
|
+
int stringsStart = chunkStart + stringsOffset;
|
|
110
108
|
stringPool = new String[stringCount];
|
|
111
|
-
|
|
112
|
-
boolean isUtf8 = (flags & 0x100) != 0;
|
|
113
|
-
|
|
109
|
+
|
|
114
110
|
for (int i = 0; i < stringCount; i++) {
|
|
115
|
-
|
|
116
|
-
|
|
111
|
+
int stringStart = stringsStart + offsets[i];
|
|
112
|
+
if (stringStart >= data.length) {
|
|
113
|
+
stringPool[i] = "";
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
stringPool[i] = readStringAt(stringStart, isUtf8);
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
-
|
|
120
|
-
private String
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
119
|
+
|
|
120
|
+
private String readStringAt(int pos, boolean isUtf8) {
|
|
121
|
+
try {
|
|
122
|
+
if (isUtf8) {
|
|
123
|
+
// UTF-8: 先读长度
|
|
124
|
+
int charLen = data[pos] & 0xFF;
|
|
125
|
+
int byteLen;
|
|
126
|
+
int dataStart;
|
|
127
|
+
|
|
128
|
+
if ((charLen & 0x80) != 0) {
|
|
129
|
+
charLen = ((charLen & 0x7F) << 8) | (data[pos + 1] & 0xFF);
|
|
130
|
+
byteLen = data[pos + 2] & 0xFF;
|
|
131
|
+
if ((byteLen & 0x80) != 0) {
|
|
132
|
+
byteLen = ((byteLen & 0x7F) << 8) | (data[pos + 3] & 0xFF);
|
|
133
|
+
dataStart = pos + 4;
|
|
134
|
+
} else {
|
|
135
|
+
dataStart = pos + 3;
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
byteLen = data[pos + 1] & 0xFF;
|
|
139
|
+
if ((byteLen & 0x80) != 0) {
|
|
140
|
+
byteLen = ((byteLen & 0x7F) << 8) | (data[pos + 2] & 0xFF);
|
|
141
|
+
dataStart = pos + 3;
|
|
142
|
+
} else {
|
|
143
|
+
dataStart = pos + 2;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (dataStart + byteLen > data.length) {
|
|
148
|
+
byteLen = data.length - dataStart;
|
|
149
|
+
}
|
|
150
|
+
if (byteLen <= 0) return "";
|
|
151
|
+
|
|
152
|
+
return new String(data, dataStart, byteLen, java.nio.charset.StandardCharsets.UTF_8);
|
|
153
|
+
} else {
|
|
154
|
+
// UTF-16
|
|
155
|
+
int charLen = (data[pos] & 0xFF) | ((data[pos + 1] & 0xFF) << 8);
|
|
156
|
+
if ((charLen & 0x8000) != 0) {
|
|
157
|
+
int high = (data[pos + 2] & 0xFF) | ((data[pos + 3] & 0xFF) << 8);
|
|
158
|
+
charLen = ((charLen & 0x7FFF) << 16) | high;
|
|
159
|
+
pos += 4;
|
|
160
|
+
} else {
|
|
161
|
+
pos += 2;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (pos + charLen * 2 > data.length) {
|
|
165
|
+
charLen = (data.length - pos) / 2;
|
|
166
|
+
}
|
|
167
|
+
if (charLen <= 0) return "";
|
|
168
|
+
|
|
169
|
+
char[] chars = new char[charLen];
|
|
170
|
+
for (int i = 0; i < charLen; i++) {
|
|
171
|
+
chars[i] = (char) ((data[pos + i * 2] & 0xFF) | ((data[pos + i * 2 + 1] & 0xFF) << 8));
|
|
172
|
+
}
|
|
173
|
+
return new String(chars);
|
|
143
174
|
}
|
|
144
|
-
|
|
175
|
+
} catch (Exception e) {
|
|
176
|
+
return "";
|
|
145
177
|
}
|
|
146
178
|
}
|
|
147
|
-
|
|
148
|
-
private void parseStartNamespace() {
|
|
149
|
-
int lineNumber = buffer.getInt();
|
|
150
|
-
int comment = buffer.getInt();
|
|
151
|
-
int prefix = buffer.getInt();
|
|
152
|
-
int uri = buffer.getInt();
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
private void parseEndNamespace() {
|
|
156
|
-
int lineNumber = buffer.getInt();
|
|
157
|
-
int comment = buffer.getInt();
|
|
158
|
-
int prefix = buffer.getInt();
|
|
159
|
-
int uri = buffer.getInt();
|
|
160
|
-
}
|
|
161
|
-
|
|
179
|
+
|
|
162
180
|
private void parseStartTag() {
|
|
163
|
-
int lineNumber =
|
|
164
|
-
int comment =
|
|
165
|
-
int
|
|
166
|
-
int name =
|
|
167
|
-
int
|
|
168
|
-
int
|
|
169
|
-
int
|
|
170
|
-
int
|
|
171
|
-
int
|
|
172
|
-
|
|
173
|
-
|
|
181
|
+
int lineNumber = readInt();
|
|
182
|
+
int comment = readInt();
|
|
183
|
+
int ns = readInt();
|
|
184
|
+
int name = readInt();
|
|
185
|
+
int attrStart = readShort();
|
|
186
|
+
int attrSize = readShort();
|
|
187
|
+
int attrCount = readShort();
|
|
188
|
+
int idIndex = readShort();
|
|
189
|
+
int classIndex = readShort();
|
|
190
|
+
int styleIndex = readShort();
|
|
191
|
+
|
|
192
|
+
// 缩进
|
|
174
193
|
for (int i = 0; i < indent; i++) {
|
|
175
|
-
xml.append("
|
|
194
|
+
xml.append(" ");
|
|
176
195
|
}
|
|
177
|
-
|
|
178
|
-
xml.append("<");
|
|
179
|
-
|
|
180
|
-
|
|
196
|
+
|
|
197
|
+
xml.append("<").append(getString(name));
|
|
198
|
+
|
|
181
199
|
// 解析属性
|
|
182
|
-
for (int i = 0; i <
|
|
183
|
-
int attrNs =
|
|
184
|
-
int attrName =
|
|
185
|
-
int attrRawValue =
|
|
186
|
-
int
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
200
|
+
for (int i = 0; i < attrCount; i++) {
|
|
201
|
+
int attrNs = readInt();
|
|
202
|
+
int attrName = readInt();
|
|
203
|
+
int attrRawValue = readInt();
|
|
204
|
+
int attrTypeAndSize = readInt();
|
|
205
|
+
int attrData = readInt();
|
|
206
|
+
|
|
207
|
+
int attrType = (attrTypeAndSize >> 24) & 0xFF;
|
|
208
|
+
|
|
190
209
|
xml.append("\n");
|
|
191
210
|
for (int j = 0; j <= indent; j++) {
|
|
192
|
-
xml.append("
|
|
211
|
+
xml.append(" ");
|
|
193
212
|
}
|
|
194
|
-
|
|
213
|
+
|
|
195
214
|
// 命名空间前缀
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
xml.append("android:");
|
|
200
|
-
}
|
|
215
|
+
String nsStr = getString(attrNs);
|
|
216
|
+
if (nsStr.contains("android")) {
|
|
217
|
+
xml.append("android:");
|
|
201
218
|
}
|
|
202
|
-
|
|
203
|
-
xml.append(getString(attrName));
|
|
204
|
-
xml.append(
|
|
205
|
-
xml.append(getAttributeValue(attrRawValue, attrType, attrData));
|
|
219
|
+
|
|
220
|
+
xml.append(getString(attrName)).append("=\"");
|
|
221
|
+
xml.append(escapeXml(getAttrValue(attrRawValue, attrType, attrData)));
|
|
206
222
|
xml.append("\"");
|
|
207
223
|
}
|
|
208
|
-
|
|
224
|
+
|
|
209
225
|
xml.append(">\n");
|
|
210
226
|
indent++;
|
|
211
227
|
}
|
|
212
|
-
|
|
228
|
+
|
|
213
229
|
private void parseEndTag() {
|
|
214
|
-
int lineNumber =
|
|
215
|
-
int comment =
|
|
216
|
-
int
|
|
217
|
-
int name =
|
|
218
|
-
|
|
230
|
+
int lineNumber = readInt();
|
|
231
|
+
int comment = readInt();
|
|
232
|
+
int ns = readInt();
|
|
233
|
+
int name = readInt();
|
|
234
|
+
|
|
219
235
|
indent--;
|
|
220
236
|
for (int i = 0; i < indent; i++) {
|
|
221
|
-
xml.append("
|
|
222
|
-
}
|
|
223
|
-
xml.append("</");
|
|
224
|
-
xml.append(getString(name));
|
|
225
|
-
xml.append(">\n");
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
private void parseText() {
|
|
229
|
-
int lineNumber = buffer.getInt();
|
|
230
|
-
int comment = buffer.getInt();
|
|
231
|
-
int text = buffer.getInt();
|
|
232
|
-
buffer.getInt(); // unknown
|
|
233
|
-
buffer.getInt(); // unknown
|
|
234
|
-
|
|
235
|
-
for (int i = 0; i < indent; i++) {
|
|
236
|
-
xml.append(" ");
|
|
237
|
+
xml.append(" ");
|
|
237
238
|
}
|
|
238
|
-
xml.append(getString(
|
|
239
|
-
xml.append("\n");
|
|
239
|
+
xml.append("</").append(getString(name)).append(">\n");
|
|
240
240
|
}
|
|
241
|
-
|
|
241
|
+
|
|
242
242
|
private String getString(int index) {
|
|
243
|
-
if (index >= 0 && index < stringPool.length) {
|
|
244
|
-
return
|
|
243
|
+
if (stringPool != null && index >= 0 && index < stringPool.length) {
|
|
244
|
+
return stringPool[index] != null ? stringPool[index] : "";
|
|
245
245
|
}
|
|
246
246
|
return "";
|
|
247
247
|
}
|
|
248
|
-
|
|
249
|
-
private String
|
|
250
|
-
//
|
|
251
|
-
if (rawValue >= 0 && rawValue < stringPool.length) {
|
|
252
|
-
return
|
|
248
|
+
|
|
249
|
+
private String getAttrValue(int rawValue, int type, int data) {
|
|
250
|
+
// 优先使用原始字符串
|
|
251
|
+
if (rawValue >= 0 && stringPool != null && rawValue < stringPool.length && stringPool[rawValue] != null) {
|
|
252
|
+
return stringPool[rawValue];
|
|
253
253
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
case
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
case 0x03: // 字符串
|
|
262
|
-
if (data >= 0 && data < stringPool.length) {
|
|
263
|
-
return escapeXml(stringPool[data]);
|
|
254
|
+
|
|
255
|
+
switch (type) {
|
|
256
|
+
case 0x01: return "@0x" + Integer.toHexString(data);
|
|
257
|
+
case 0x02: return "?0x" + Integer.toHexString(data);
|
|
258
|
+
case 0x03:
|
|
259
|
+
if (data >= 0 && stringPool != null && data < stringPool.length) {
|
|
260
|
+
return stringPool[data] != null ? stringPool[data] : "";
|
|
264
261
|
}
|
|
265
262
|
return "";
|
|
266
|
-
case 0x10:
|
|
267
|
-
|
|
268
|
-
case
|
|
269
|
-
|
|
270
|
-
case
|
|
271
|
-
|
|
272
|
-
case
|
|
273
|
-
|
|
274
|
-
case 0x1D: // 颜色 RGB8
|
|
275
|
-
return String.format("#%06X", data & 0xFFFFFF);
|
|
276
|
-
default:
|
|
277
|
-
return "0x" + Integer.toHexString(data);
|
|
263
|
+
case 0x10: return String.valueOf(data);
|
|
264
|
+
case 0x11: return "0x" + Integer.toHexString(data);
|
|
265
|
+
case 0x12: return data != 0 ? "true" : "false";
|
|
266
|
+
case 0x1C: return String.format("#%08X", data);
|
|
267
|
+
case 0x1D: return String.format("#%06X", data & 0xFFFFFF);
|
|
268
|
+
case 0x05: return String.format("%.1fdip", Float.intBitsToFloat(data));
|
|
269
|
+
case 0x06: return String.format("%.1fsp", Float.intBitsToFloat(data));
|
|
270
|
+
default: return "0x" + Integer.toHexString(data);
|
|
278
271
|
}
|
|
279
272
|
}
|
|
280
|
-
|
|
273
|
+
|
|
274
|
+
private int readInt() {
|
|
275
|
+
if (position + 4 > data.length) return 0;
|
|
276
|
+
int result = (data[position] & 0xFF) |
|
|
277
|
+
((data[position + 1] & 0xFF) << 8) |
|
|
278
|
+
((data[position + 2] & 0xFF) << 16) |
|
|
279
|
+
((data[position + 3] & 0xFF) << 24);
|
|
280
|
+
position += 4;
|
|
281
|
+
return result;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
private int readShort() {
|
|
285
|
+
if (position + 2 > data.length) return 0;
|
|
286
|
+
int result = (data[position] & 0xFF) | ((data[position + 1] & 0xFF) << 8);
|
|
287
|
+
position += 2;
|
|
288
|
+
return result;
|
|
289
|
+
}
|
|
290
|
+
|
|
281
291
|
private String escapeXml(String s) {
|
|
282
292
|
if (s == null) return "";
|
|
283
293
|
return s.replace("&", "&")
|
|
284
294
|
.replace("<", "<")
|
|
285
295
|
.replace(">", ">")
|
|
286
|
-
.replace("\"", """)
|
|
287
|
-
.replace("'", "'");
|
|
296
|
+
.replace("\"", """);
|
|
288
297
|
}
|
|
289
298
|
}
|
|
@@ -441,6 +441,96 @@ public class DexEditorPluginPlugin extends Plugin {
|
|
|
441
441
|
));
|
|
442
442
|
break;
|
|
443
443
|
|
|
444
|
+
// ==================== MCP 工作流操作 ====================
|
|
445
|
+
case "listDexFiles":
|
|
446
|
+
result.put("data", dexManager.listDexFilesInApk(
|
|
447
|
+
params.getString("apkPath")
|
|
448
|
+
));
|
|
449
|
+
break;
|
|
450
|
+
|
|
451
|
+
case "openDex":
|
|
452
|
+
result.put("data", dexManager.openMultipleDex(
|
|
453
|
+
params.getString("apkPath"),
|
|
454
|
+
params.getJSONArray("dexFiles")
|
|
455
|
+
));
|
|
456
|
+
break;
|
|
457
|
+
|
|
458
|
+
case "listClasses":
|
|
459
|
+
result.put("data", dexManager.getClassesFromMultiSession(
|
|
460
|
+
params.getString("sessionId"),
|
|
461
|
+
params.optString("packageFilter", ""),
|
|
462
|
+
params.optInt("offset", 0),
|
|
463
|
+
params.optInt("limit", 100)
|
|
464
|
+
));
|
|
465
|
+
break;
|
|
466
|
+
|
|
467
|
+
case "searchInDexSession":
|
|
468
|
+
result.put("data", dexManager.searchInMultiSession(
|
|
469
|
+
params.getString("sessionId"),
|
|
470
|
+
params.getString("query"),
|
|
471
|
+
params.getString("searchType"),
|
|
472
|
+
params.optBoolean("caseSensitive", false),
|
|
473
|
+
params.optInt("maxResults", 50)
|
|
474
|
+
));
|
|
475
|
+
break;
|
|
476
|
+
|
|
477
|
+
case "getClassSmaliFromSession":
|
|
478
|
+
result.put("data", dexManager.getClassSmaliFromSession(
|
|
479
|
+
params.getString("sessionId"),
|
|
480
|
+
params.getString("className")
|
|
481
|
+
));
|
|
482
|
+
break;
|
|
483
|
+
|
|
484
|
+
case "modifyClass":
|
|
485
|
+
dexManager.modifyClassInSession(
|
|
486
|
+
params.getString("sessionId"),
|
|
487
|
+
params.getString("className"),
|
|
488
|
+
params.getString("smaliContent")
|
|
489
|
+
);
|
|
490
|
+
break;
|
|
491
|
+
|
|
492
|
+
case "saveDexToApk":
|
|
493
|
+
result.put("data", dexManager.saveMultiDexSessionToApk(
|
|
494
|
+
params.getString("sessionId")
|
|
495
|
+
));
|
|
496
|
+
break;
|
|
497
|
+
|
|
498
|
+
case "closeMultiDexSession":
|
|
499
|
+
dexManager.closeMultiDexSession(params.getString("sessionId"));
|
|
500
|
+
break;
|
|
501
|
+
|
|
502
|
+
case "listSessions":
|
|
503
|
+
result.put("data", dexManager.listAllSessions());
|
|
504
|
+
break;
|
|
505
|
+
|
|
506
|
+
// ==================== XML/资源操作 ====================
|
|
507
|
+
case "getManifest":
|
|
508
|
+
result.put("data", dexManager.getManifestFromApk(
|
|
509
|
+
params.getString("apkPath")
|
|
510
|
+
));
|
|
511
|
+
break;
|
|
512
|
+
|
|
513
|
+
case "modifyManifest":
|
|
514
|
+
result.put("data", dexManager.modifyManifestInApk(
|
|
515
|
+
params.getString("apkPath"),
|
|
516
|
+
params.getString("newManifest")
|
|
517
|
+
));
|
|
518
|
+
break;
|
|
519
|
+
|
|
520
|
+
case "listResources":
|
|
521
|
+
result.put("data", dexManager.listResourcesInApk(
|
|
522
|
+
params.getString("apkPath"),
|
|
523
|
+
params.optString("filter", "")
|
|
524
|
+
));
|
|
525
|
+
break;
|
|
526
|
+
|
|
527
|
+
case "getResource":
|
|
528
|
+
result.put("data", dexManager.getResourceFromApk(
|
|
529
|
+
params.getString("apkPath"),
|
|
530
|
+
params.getString("resourcePath")
|
|
531
|
+
));
|
|
532
|
+
break;
|
|
533
|
+
|
|
444
534
|
default:
|
|
445
535
|
result.put("success", false);
|
|
446
536
|
result.put("error", "Unknown action: " + action);
|