create-droid 1.0.4 → 1.0.6
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.
- package/package.json +1 -1
- package/templates/base/scripts/adb.js +200 -24
package/package.json
CHANGED
|
@@ -1,47 +1,223 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const { spawn } = require('child_process');
|
|
3
|
+
const { spawn, execSync } = require('child_process');
|
|
4
|
+
const readline = require('readline');
|
|
4
5
|
const os = require('os');
|
|
5
6
|
|
|
6
|
-
//
|
|
7
|
+
// --- Configuration ---
|
|
7
8
|
const projectRoot = path.resolve(__dirname, '..');
|
|
8
9
|
const localPropertiesPath = path.join(projectRoot, 'local.properties');
|
|
9
10
|
let sdkPath = process.env.ANDROID_HOME;
|
|
10
11
|
|
|
12
|
+
// --- 1. Resolve ADB Path ---
|
|
11
13
|
if (fs.existsSync(localPropertiesPath)) {
|
|
12
14
|
const content = fs.readFileSync(localPropertiesPath, 'utf8');
|
|
13
15
|
const match = content.match(/^sdk\.dir=(.*)$/m);
|
|
14
16
|
if (match) {
|
|
15
|
-
sdkPath = match[1].trim().replace(/\\\\/g, '\\');
|
|
17
|
+
sdkPath = match[1].trim().replace(/\\\\/g, '\\');
|
|
16
18
|
}
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
if (!sdkPath) {
|
|
20
|
-
console.error('❌ Could not find SDK location. Set ANDROID_HOME or create local.properties.');
|
|
21
|
-
process.exit(1);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// 2. Resolve ADB binary
|
|
25
21
|
const isWin = os.platform() === 'win32';
|
|
26
22
|
const adbBinary = isWin ? 'adb.exe' : 'adb';
|
|
27
|
-
const
|
|
23
|
+
const localAdbPath = sdkPath ? path.join(sdkPath, 'platform-tools', adbBinary) : null;
|
|
24
|
+
const finalAdbPath = (localAdbPath && fs.existsSync(localAdbPath)) ? localAdbPath : 'adb';
|
|
25
|
+
|
|
26
|
+
// --- 2. Helper Functions ---
|
|
27
|
+
function runCommand(args, inherit = true) {
|
|
28
|
+
if (inherit) {
|
|
29
|
+
const child = spawn(finalAdbPath, args, { stdio: 'inherit' });
|
|
30
|
+
return new Promise((resolve) => {
|
|
31
|
+
child.on('close', (code) => resolve(code));
|
|
32
|
+
});
|
|
33
|
+
} else {
|
|
34
|
+
try {
|
|
35
|
+
return execSync(`"${finalAdbPath}" ${args.join(' ')}`, { encoding: 'utf8' }).trim();
|
|
36
|
+
} catch (e) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
28
41
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
42
|
+
async function getMdnsServices() {
|
|
43
|
+
const output = runCommand(['mdns', 'services'], false);
|
|
44
|
+
if (!output) return [];
|
|
45
|
+
|
|
46
|
+
// Output format usually:
|
|
47
|
+
// List of discovered mdns services
|
|
48
|
+
// <name> <type> <ip>:<port>
|
|
49
|
+
// myphone _adb-tls-connect._tcp. 192.168.1.5:38291
|
|
50
|
+
|
|
51
|
+
const lines = output.split('\n');
|
|
52
|
+
const services = [];
|
|
53
|
+
|
|
54
|
+
for (const line of lines) {
|
|
55
|
+
if (!line.includes('_adb-tls-connect') && !line.includes('_adb._tcp')) continue;
|
|
56
|
+
|
|
57
|
+
const parts = line.trim().split(/\s+/);
|
|
58
|
+
if (parts.length >= 3) {
|
|
59
|
+
const ipPort = parts[parts.length - 1]; // last part is ip:port
|
|
60
|
+
const name = parts[0];
|
|
61
|
+
services.push({ name, ipPort });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return services;
|
|
32
65
|
}
|
|
33
66
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
67
|
+
function clearScreen() {
|
|
68
|
+
process.stdout.write('\x1Bc');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// --- 3. Interactive Menu ---
|
|
72
|
+
async function showMenu() {
|
|
73
|
+
clearScreen();
|
|
74
|
+
console.log('\x1b[36m%s\x1b[0m', '🤖 Android Debug Bridge (ADB) Manager');
|
|
75
|
+
console.log('-----------------------------------');
|
|
76
|
+
console.log('1. 📱 List Connected Devices');
|
|
77
|
+
console.log('2. 📡 Connect to Device (Wi-Fi)');
|
|
78
|
+
console.log('3. 🔗 Pair Device (Android 11+)');
|
|
79
|
+
console.log('4. 🔄 Reverse Port 8081 (React Native/Metro)');
|
|
80
|
+
console.log('5. 📜 Stream Logcat');
|
|
81
|
+
console.log('6. 💀 Kill ADB Server');
|
|
82
|
+
console.log('0. 🚪 Exit');
|
|
83
|
+
console.log('-----------------------------------');
|
|
84
|
+
|
|
85
|
+
const rl = readline.createInterface({
|
|
86
|
+
input: process.stdin,
|
|
87
|
+
output: process.stdout
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
rl.question('Select option: ', async (answer) => {
|
|
91
|
+
rl.close();
|
|
92
|
+
switch (answer.trim()) {
|
|
93
|
+
case '1':
|
|
94
|
+
await runCommand(['devices', '-l']);
|
|
95
|
+
await pause();
|
|
96
|
+
showMenu();
|
|
97
|
+
break;
|
|
98
|
+
case '2':
|
|
99
|
+
await handleConnect();
|
|
100
|
+
break;
|
|
101
|
+
case '3':
|
|
102
|
+
await handlePair();
|
|
103
|
+
break;
|
|
104
|
+
case '4':
|
|
105
|
+
console.log('Reversing tcp:8081...');
|
|
106
|
+
await runCommand(['reverse', 'tcp:8081', 'tcp:8081']);
|
|
107
|
+
await pause();
|
|
108
|
+
showMenu();
|
|
109
|
+
break;
|
|
110
|
+
case '5':
|
|
111
|
+
console.log('Starting Logcat (Ctrl+C to stop)...');
|
|
112
|
+
await runCommand(['logcat']);
|
|
113
|
+
break;
|
|
114
|
+
case '6':
|
|
115
|
+
await runCommand(['kill-server']);
|
|
116
|
+
console.log('Server killed.');
|
|
117
|
+
await pause();
|
|
118
|
+
showMenu();
|
|
119
|
+
break;
|
|
120
|
+
case '0':
|
|
121
|
+
process.exit(0);
|
|
122
|
+
break;
|
|
123
|
+
default:
|
|
124
|
+
showMenu();
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
37
128
|
|
|
38
|
-
|
|
129
|
+
async function handleConnect() {
|
|
130
|
+
console.log('\nScanning for devices via mDNS...');
|
|
131
|
+
const services = await getMdnsServices();
|
|
132
|
+
|
|
133
|
+
if (services.length > 0) {
|
|
134
|
+
console.log('\nDiscovered Devices:');
|
|
135
|
+
services.forEach((s, i) => console.log(`${i + 1}. ${s.name} (${s.ipPort})`));
|
|
136
|
+
console.log(`${services.length + 1}. Enter manually`);
|
|
137
|
+
} else {
|
|
138
|
+
console.log('No mDNS devices found.');
|
|
139
|
+
}
|
|
39
140
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
141
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
142
|
+
rl.question('\nSelect device number or enter IP:Port: ', async (answer) => {
|
|
143
|
+
rl.close();
|
|
144
|
+
|
|
145
|
+
let target = answer.trim();
|
|
146
|
+
const idx = parseInt(target) - 1;
|
|
147
|
+
|
|
148
|
+
if (!isNaN(idx) && idx >= 0 && idx < services.length) {
|
|
149
|
+
target = services[idx].ipPort;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (target) {
|
|
153
|
+
console.log(`Connecting to ${target}...`);
|
|
154
|
+
await runCommand(['connect', target]);
|
|
155
|
+
}
|
|
156
|
+
await pause();
|
|
157
|
+
showMenu();
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function handlePair() {
|
|
162
|
+
console.log('\nScanning for devices via mDNS...');
|
|
163
|
+
const services = await getMdnsServices();
|
|
164
|
+
|
|
165
|
+
if (services.length > 0) {
|
|
166
|
+
console.log('\nDiscovered Devices:');
|
|
167
|
+
services.forEach((s, i) => console.log(`${i + 1}. ${s.name} (${s.ipPort})`));
|
|
168
|
+
console.log(`${services.length + 1}. Enter manually`);
|
|
169
|
+
} else {
|
|
170
|
+
console.log('No mDNS devices found.');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
174
|
+
rl.question('\nSelect device number or enter IP:Port: ', (answer) => {
|
|
175
|
+
let target = answer.trim();
|
|
176
|
+
const idx = parseInt(target) - 1;
|
|
177
|
+
|
|
178
|
+
if (!isNaN(idx) && idx >= 0 && idx < services.length) {
|
|
179
|
+
target = services[idx].ipPort;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (!target) {
|
|
183
|
+
rl.close();
|
|
184
|
+
showMenu();
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
rl.question(`Enter Pairing Code for ${target}: `, async (code) => {
|
|
189
|
+
rl.close();
|
|
190
|
+
if (code) {
|
|
191
|
+
console.log(`Pairing with ${target}...`);
|
|
192
|
+
await runCommand(['pair', target, code]);
|
|
193
|
+
}
|
|
194
|
+
await pause();
|
|
195
|
+
showMenu();
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
}
|
|
44
199
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
});
|
|
200
|
+
function pause() {
|
|
201
|
+
return new Promise((resolve) => {
|
|
202
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
203
|
+
rl.question('\nPress Enter to continue...', () => {
|
|
204
|
+
rl.close();
|
|
205
|
+
resolve();
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// --- 4. Main Execution ---
|
|
211
|
+
const args = process.argv.slice(2);
|
|
212
|
+
|
|
213
|
+
if (args.length > 0) {
|
|
214
|
+
// Pass-through mode (e.g., npm run adb connect ...)
|
|
215
|
+
const child = spawn(finalAdbPath, args, { stdio: 'inherit' });
|
|
216
|
+
child.on('close', (code) => process.exit(code));
|
|
217
|
+
} else {
|
|
218
|
+
// Interactive mode
|
|
219
|
+
if (!sdkPath && !process.env.ANDROID_HOME) {
|
|
220
|
+
console.warn('⚠️ ANDROID_HOME not set. Trying global ADB...');
|
|
221
|
+
}
|
|
222
|
+
showMenu();
|
|
223
|
+
}
|