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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-droid",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "The fastest way to start an Android project. No Studio required.",
5
5
  "author": "YELrhilassi",
6
6
  "license": "MIT",
@@ -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
- // 1. Find SDK Location from local.properties
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, '\\'); // Handle Windows escaping if present
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 adbPath = path.join(sdkPath, 'platform-tools', adbBinary);
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
- if (!fs.existsSync(adbPath)) {
30
- // Fallback to global adb if local not found
31
- console.warn(`⚠️ Local ADB not found at ${adbPath}. Trying global 'adb'...`);
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
- // 3. Run ADB with arguments
35
- const args = process.argv.slice(2);
36
- const finalAdbPath = fs.existsSync(adbPath) ? adbPath : 'adb';
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
- const child = spawn(finalAdbPath, args, { stdio: 'inherit' });
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
- child.on('error', (err) => {
41
- console.error(`❌ Failed to start ADB: ${err.message}`);
42
- process.exit(1);
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
- child.on('close', (code) => {
46
- process.exit(code);
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
+ }