@vaishnavkm/flutterbridge 0.1.1 → 0.1.2
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/index.js +76 -2
- package/package.json +8 -8
package/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const qrcode = require('qrcode-terminal');
|
|
4
4
|
const chalk = require('chalk');
|
|
5
|
+
const WebSocket = require('ws');
|
|
5
6
|
const { spawn } = require('child_process');
|
|
6
7
|
const readline = require('readline');
|
|
7
8
|
const fs = require('fs');
|
|
@@ -9,7 +10,7 @@ const path = require('path');
|
|
|
9
10
|
const os = require('os');
|
|
10
11
|
const net = require('net');
|
|
11
12
|
|
|
12
|
-
const VM_URL_TIMEOUT_MS =
|
|
13
|
+
const VM_URL_TIMEOUT_MS = 300000; // 5 minutes (initial gradle builds take time)
|
|
13
14
|
const SERVICE_URI_KEYS = [
|
|
14
15
|
'vmServiceUri',
|
|
15
16
|
'observatoryUri',
|
|
@@ -200,6 +201,61 @@ function closeAllProxies() {
|
|
|
200
201
|
|
|
201
202
|
process.on('exit', closeAllProxies);
|
|
202
203
|
|
|
204
|
+
function startScreenshotServer(deviceId) {
|
|
205
|
+
return new Promise((resolve, reject) => {
|
|
206
|
+
try {
|
|
207
|
+
const wss = new WebSocket.Server({ port: 0, host: '0.0.0.0' });
|
|
208
|
+
let intervalId = null;
|
|
209
|
+
let connections = 0;
|
|
210
|
+
|
|
211
|
+
wss.on('listening', () => {
|
|
212
|
+
const port = wss.address().port;
|
|
213
|
+
resolve(port);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
wss.on('error', (err) => {
|
|
217
|
+
reject(err);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
wss.on('connection', (ws) => {
|
|
221
|
+
connections++;
|
|
222
|
+
|
|
223
|
+
if (connections === 1) {
|
|
224
|
+
intervalId = setInterval(() => {
|
|
225
|
+
const adbArgs = deviceId ? ['-s', deviceId, 'exec-out', 'screencap', '-p'] : ['exec-out', 'screencap', '-p'];
|
|
226
|
+
const child = spawn('adb', adbArgs);
|
|
227
|
+
const chunks = [];
|
|
228
|
+
|
|
229
|
+
child.stdout.on('data', chunk => chunks.push(chunk));
|
|
230
|
+
child.on('close', code => {
|
|
231
|
+
if (code === 0 && wss.clients.size > 0) {
|
|
232
|
+
const buffer = Buffer.concat(chunks);
|
|
233
|
+
wss.clients.forEach(client => {
|
|
234
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
235
|
+
client.send(buffer);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}, 500); // 2 fps polling
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
ws.on('close', () => {
|
|
244
|
+
connections--;
|
|
245
|
+
if (connections === 0 && intervalId) {
|
|
246
|
+
clearInterval(intervalId);
|
|
247
|
+
intervalId = null;
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
registerProxy(wss);
|
|
253
|
+
} catch(err) {
|
|
254
|
+
reject(err);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
203
259
|
function startTcpProxy(targetHost, targetPort) {
|
|
204
260
|
return new Promise((resolve, reject) => {
|
|
205
261
|
const server = net.createServer((client) => {
|
|
@@ -457,6 +513,14 @@ async function main() {
|
|
|
457
513
|
return;
|
|
458
514
|
}
|
|
459
515
|
|
|
516
|
+
let previewPort = null;
|
|
517
|
+
try {
|
|
518
|
+
previewPort = await startScreenshotServer(deviceId);
|
|
519
|
+
if (!quiet) console.log(chalk.gray(`Started Live Preview server on port ${previewPort}`));
|
|
520
|
+
} catch (e) {
|
|
521
|
+
if (!quiet) console.warn(chalk.yellow(`Warning: Failed to start Live Preview server: ${e.message}`));
|
|
522
|
+
}
|
|
523
|
+
|
|
460
524
|
if (!quiet) {
|
|
461
525
|
console.log(chalk.gray('Starting Flutter...\n'));
|
|
462
526
|
}
|
|
@@ -509,7 +573,17 @@ async function main() {
|
|
|
509
573
|
if (vmServiceUrl) {
|
|
510
574
|
return;
|
|
511
575
|
}
|
|
512
|
-
|
|
576
|
+
|
|
577
|
+
let finalUrl = result.url;
|
|
578
|
+
if (previewPort) {
|
|
579
|
+
try {
|
|
580
|
+
const u = new URL(finalUrl);
|
|
581
|
+
u.searchParams.set('previewPort', previewPort);
|
|
582
|
+
finalUrl = u.toString();
|
|
583
|
+
} catch(e) {}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
vmServiceUrl = finalUrl;
|
|
513
587
|
clearTimeout(vmTimeout);
|
|
514
588
|
|
|
515
589
|
if (jsonOutput) {
|
package/package.json
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaishnavkm/flutterbridge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Bridge your Flutter code to your phone instantly. Wireless development with QR code pairing.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"
|
|
7
|
+
"bridge": "index.js"
|
|
8
8
|
},
|
|
9
9
|
"publishConfig": {
|
|
10
10
|
"access": "public"
|
|
11
11
|
},
|
|
12
|
-
"scripts": {
|
|
13
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
14
|
-
},
|
|
15
12
|
"keywords": [
|
|
16
13
|
"flutter",
|
|
17
14
|
"mobile",
|
|
@@ -37,9 +34,12 @@
|
|
|
37
34
|
"engines": {
|
|
38
35
|
"node": ">=18.0.0"
|
|
39
36
|
},
|
|
40
|
-
"packageManager": "pnpm@10.33.0",
|
|
41
37
|
"dependencies": {
|
|
42
38
|
"chalk": "^4.1.2",
|
|
43
|
-
"qrcode-terminal": "^0.12.0"
|
|
39
|
+
"qrcode-terminal": "^0.12.0",
|
|
40
|
+
"ws": "^8.21.0"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
44
44
|
}
|
|
45
|
-
}
|
|
45
|
+
}
|