@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.
Files changed (2) hide show
  1. package/index.js +76 -2
  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 = 60000;
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
- vmServiceUrl = result.url;
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.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
- "flutterbridge": "index.js"
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
+ }