react-native-debug-toolkit 3.3.4 → 3.3.8
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/README.md +48 -46
- package/README.zh-CN.md +48 -46
- package/android/src/main/java/com/reactnativedebugtoolkit/DebugToolkitDevConnectModule.java +0 -187
- package/bin/debug-toolkit.js +0 -16
- package/ios/DebugToolkitDevConnect.h +0 -12
- package/ios/DebugToolkitDevConnect.mm +0 -321
- package/lib/commonjs/core/initialize.js +8 -1
- package/lib/commonjs/core/initialize.js.map +1 -1
- package/lib/commonjs/features/devConnect/DevConnectTab.js +18 -470
- package/lib/commonjs/features/devConnect/DevConnectTab.js.map +1 -1
- package/lib/commonjs/features/devConnect/devConnectPreferences.js +0 -12
- package/lib/commonjs/features/devConnect/devConnectPreferences.js.map +1 -1
- package/lib/commonjs/features/devConnect/devConnectUtils.js +2 -57
- package/lib/commonjs/features/devConnect/devConnectUtils.js.map +1 -1
- package/lib/commonjs/features/devConnect/index.js +1 -23
- package/lib/commonjs/features/devConnect/index.js.map +1 -1
- package/lib/commonjs/features/devConnect/nativeDevConnect.js +1 -103
- package/lib/commonjs/features/devConnect/nativeDevConnect.js.map +1 -1
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/DebugView.js +2 -0
- package/lib/commonjs/ui/DebugView.js.map +1 -1
- package/lib/commonjs/ui/panel/FloatPanelView.js +22 -10
- package/lib/commonjs/ui/panel/FloatPanelView.js.map +1 -1
- package/lib/commonjs/ui/panel/tabPersistence.js +17 -0
- package/lib/commonjs/ui/panel/tabPersistence.js.map +1 -0
- package/lib/commonjs/utils/createDebugTab.js +21 -0
- package/lib/commonjs/utils/createDebugTab.js.map +1 -0
- package/lib/commonjs/utils/debugPreferences.js +0 -1
- package/lib/commonjs/utils/debugPreferences.js.map +1 -1
- package/lib/module/core/initialize.js +8 -1
- package/lib/module/core/initialize.js.map +1 -1
- package/lib/module/features/devConnect/DevConnectTab.js +21 -473
- package/lib/module/features/devConnect/DevConnectTab.js.map +1 -1
- package/lib/module/features/devConnect/devConnectPreferences.js +1 -12
- package/lib/module/features/devConnect/devConnectPreferences.js.map +1 -1
- package/lib/module/features/devConnect/devConnectUtils.js +1 -53
- package/lib/module/features/devConnect/devConnectUtils.js.map +1 -1
- package/lib/module/features/devConnect/index.js +5 -9
- package/lib/module/features/devConnect/index.js.map +1 -1
- package/lib/module/features/devConnect/nativeDevConnect.js +1 -100
- package/lib/module/features/devConnect/nativeDevConnect.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/DebugView.js +2 -0
- package/lib/module/ui/DebugView.js.map +1 -1
- package/lib/module/ui/panel/FloatPanelView.js +22 -10
- package/lib/module/ui/panel/FloatPanelView.js.map +1 -1
- package/lib/module/ui/panel/tabPersistence.js +13 -0
- package/lib/module/ui/panel/tabPersistence.js.map +1 -0
- package/lib/module/utils/createDebugTab.js +17 -0
- package/lib/module/utils/createDebugTab.js.map +1 -0
- package/lib/module/utils/debugPreferences.js +0 -1
- package/lib/module/utils/debugPreferences.js.map +1 -1
- package/lib/typescript/src/core/initialize.d.ts +2 -0
- package/lib/typescript/src/core/initialize.d.ts.map +1 -1
- package/lib/typescript/src/features/devConnect/DevConnectTab.d.ts.map +1 -1
- package/lib/typescript/src/features/devConnect/devConnectPreferences.d.ts +0 -2
- package/lib/typescript/src/features/devConnect/devConnectPreferences.d.ts.map +1 -1
- package/lib/typescript/src/features/devConnect/devConnectUtils.d.ts +0 -20
- package/lib/typescript/src/features/devConnect/devConnectUtils.d.ts.map +1 -1
- package/lib/typescript/src/features/devConnect/index.d.ts +2 -2
- package/lib/typescript/src/features/devConnect/index.d.ts.map +1 -1
- package/lib/typescript/src/features/devConnect/nativeDevConnect.d.ts +0 -25
- package/lib/typescript/src/features/devConnect/nativeDevConnect.d.ts.map +1 -1
- package/lib/typescript/src/features/devConnect/types.d.ts +1 -3
- package/lib/typescript/src/features/devConnect/types.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/ui/DebugView.d.ts +4 -2
- package/lib/typescript/src/ui/DebugView.d.ts.map +1 -1
- package/lib/typescript/src/ui/panel/FloatPanelView.d.ts.map +1 -1
- package/lib/typescript/src/ui/panel/tabPersistence.d.ts +3 -0
- package/lib/typescript/src/ui/panel/tabPersistence.d.ts.map +1 -0
- package/lib/typescript/src/utils/createDebugTab.d.ts +18 -0
- package/lib/typescript/src/utils/createDebugTab.d.ts.map +1 -0
- package/lib/typescript/src/utils/debugPreferences.d.ts +0 -1
- package/lib/typescript/src/utils/debugPreferences.d.ts.map +1 -1
- package/package.json +2 -6
- package/src/core/initialize.ts +17 -1
- package/src/features/devConnect/DevConnectTab.tsx +17 -381
- package/src/features/devConnect/devConnectPreferences.ts +0 -15
- package/src/features/devConnect/devConnectUtils.ts +1 -81
- package/src/features/devConnect/index.ts +2 -9
- package/src/features/devConnect/nativeDevConnect.ts +1 -136
- package/src/features/devConnect/types.ts +1 -3
- package/src/index.ts +2 -0
- package/src/ui/DebugView.tsx +5 -1
- package/src/ui/panel/FloatPanelView.tsx +22 -10
- package/src/ui/panel/tabPersistence.ts +22 -0
- package/src/utils/createDebugTab.ts +32 -0
- package/src/utils/debugPreferences.ts +0 -1
- package/app.plugin.js +0 -51
- package/dev-client.js +0 -3
- package/scripts/bundle/android.js +0 -101
- package/scripts/bundle/cli.js +0 -57
- package/scripts/bundle/doctor.js +0 -38
- package/scripts/bundle/ios.js +0 -179
- package/scripts/bundle/setup.js +0 -39
- package/scripts/debug-bundle.gradle +0 -147
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useEffect,
|
|
1
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
KeyboardAvoidingView,
|
|
4
4
|
Platform,
|
|
@@ -21,10 +21,7 @@ import {
|
|
|
21
21
|
} from '../../utils/DaemonClient';
|
|
22
22
|
import {
|
|
23
23
|
DEFAULT_DAEMON_PORT,
|
|
24
|
-
DEFAULT_METRO_PORT,
|
|
25
24
|
buildDaemonDeviceHost,
|
|
26
|
-
buildMetroTarget,
|
|
27
|
-
buildMetroUrls,
|
|
28
25
|
normalizeComputerHost,
|
|
29
26
|
normalizePort,
|
|
30
27
|
parseComputerTarget,
|
|
@@ -33,52 +30,25 @@ import {
|
|
|
33
30
|
saveComputerHost,
|
|
34
31
|
saveComputerTarget,
|
|
35
32
|
saveDaemonPort,
|
|
36
|
-
saveMetroPort,
|
|
37
33
|
} from './devConnectPreferences';
|
|
38
|
-
import {
|
|
39
|
-
applyMetroBundle,
|
|
40
|
-
getNativeDiagnostics,
|
|
41
|
-
resetMetroBundle,
|
|
42
|
-
type NativeDiagnostics,
|
|
43
|
-
} from './nativeDevConnect';
|
|
44
34
|
import type { DevConnectFeatureControls, DevConnectSettingsPatch, DevConnectState } from './types';
|
|
45
35
|
|
|
46
36
|
const CONNECTION_TIMEOUT_MS = 2000;
|
|
47
37
|
|
|
48
38
|
type SyncUiState = 'idle' | 'checking' | 'connected' | 'retrying' | 'failed' | 'running';
|
|
49
39
|
|
|
50
|
-
function
|
|
40
|
+
function getSimulatorHost(): string {
|
|
51
41
|
return Platform.OS === 'android' ? '10.0.2.2' : 'localhost';
|
|
52
42
|
}
|
|
53
43
|
|
|
54
|
-
function describeMetroFailure(result: { reason: string; error?: string }): string {
|
|
55
|
-
if (result.reason === 'native_unavailable') {
|
|
56
|
-
return 'Native DevConnect not installed. Rebuild app after installing native module.';
|
|
57
|
-
}
|
|
58
|
-
if (result.reason === 'metro_unreachable') {
|
|
59
|
-
return result.error ? `Metro not reachable: ${result.error}` : 'Metro not reachable. Start Metro on that port.';
|
|
60
|
-
}
|
|
61
|
-
if (result.reason === 'fetch_unavailable') {
|
|
62
|
-
return 'Cannot check Metro because fetch is unavailable.';
|
|
63
|
-
}
|
|
64
|
-
if (result.reason === 'invalid_target') {
|
|
65
|
-
return 'Enter a valid computer IP and Metro port.';
|
|
66
|
-
}
|
|
67
|
-
return result.error ? `Metro switch failed: ${result.error}` : 'Metro switch failed.';
|
|
68
|
-
}
|
|
69
|
-
|
|
70
44
|
export function DevConnectTab({ snapshot, feature }: DebugFeatureRenderProps<DevConnectState>) {
|
|
71
45
|
const inputRef = useRef<TextInput>(null);
|
|
72
46
|
const [computerHost, setComputerHost] = useState(snapshot.computerHost);
|
|
73
|
-
const [metroPort, setMetroPort] = useState(snapshot.metroPort);
|
|
74
47
|
const [daemonPort, setDaemonPort] = useState(snapshot.daemonPort);
|
|
75
48
|
const [streaming, setStreaming] = useState(snapshot.streaming);
|
|
76
49
|
const [syncState, setSyncState] = useState<SyncUiState>(snapshot.streaming ? 'running' : 'idle');
|
|
77
50
|
const [message, setMessage] = useState<string | null>(null);
|
|
78
51
|
const [sending, setSending] = useState(false);
|
|
79
|
-
const [metroBusy, setMetroBusy] = useState(false);
|
|
80
|
-
const [diagData, setDiagData] = useState<NativeDiagnostics | null>(null);
|
|
81
|
-
const [diagOpen, setDiagOpen] = useState(false);
|
|
82
52
|
|
|
83
53
|
const isSim = snapshot.isSimulator;
|
|
84
54
|
|
|
@@ -86,31 +56,10 @@ export function DevConnectTab({ snapshot, feature }: DebugFeatureRenderProps<Dev
|
|
|
86
56
|
(feature as unknown as DevConnectFeatureControls).updateSettings?.(patch);
|
|
87
57
|
}, [feature]);
|
|
88
58
|
|
|
89
|
-
useEffect(() => {
|
|
90
|
-
getNativeDiagnostics().then((result) => {
|
|
91
|
-
if (result) {
|
|
92
|
-
setDiagData(result);
|
|
93
|
-
console.info(
|
|
94
|
-
`[DevConnect] debugBuild=${result.isDebugBuild} appDelegate=${result.appDelegateClass} persistedHost=${result.persistedMetroHost ?? 'none'}`,
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
}).catch(() => {});
|
|
98
|
-
}, []);
|
|
99
|
-
|
|
100
|
-
const refreshDiag = useCallback(() => {
|
|
101
|
-
getNativeDiagnostics().then((result) => {
|
|
102
|
-
if (result) setDiagData(result);
|
|
103
|
-
}).catch(() => {});
|
|
104
|
-
}, []);
|
|
105
|
-
|
|
106
59
|
useEffect(() => {
|
|
107
60
|
setComputerHost(snapshot.computerHost);
|
|
108
61
|
}, [snapshot.computerHost]);
|
|
109
62
|
|
|
110
|
-
useEffect(() => {
|
|
111
|
-
setMetroPort(snapshot.metroPort);
|
|
112
|
-
}, [snapshot.metroPort]);
|
|
113
|
-
|
|
114
63
|
useEffect(() => {
|
|
115
64
|
setDaemonPort(snapshot.daemonPort);
|
|
116
65
|
}, [snapshot.daemonPort]);
|
|
@@ -120,27 +69,15 @@ export function DevConnectTab({ snapshot, feature }: DebugFeatureRenderProps<Dev
|
|
|
120
69
|
setSyncState(snapshot.streaming ? 'running' : 'idle');
|
|
121
70
|
}, [snapshot.streaming]);
|
|
122
71
|
|
|
123
|
-
const metroHost = isSim ? getSimulatorMetroHost() : computerHost;
|
|
124
|
-
const metroTarget = useMemo(
|
|
125
|
-
() => buildMetroTarget(metroHost, metroPort),
|
|
126
|
-
[metroHost, metroPort],
|
|
127
|
-
);
|
|
128
|
-
const metroUrls = useMemo(
|
|
129
|
-
() => buildMetroUrls(metroHost, metroPort),
|
|
130
|
-
[metroHost, metroPort],
|
|
131
|
-
);
|
|
132
|
-
|
|
133
72
|
const handleHostChange = useCallback((value: string) => {
|
|
134
73
|
setComputerHost(value);
|
|
135
74
|
const target = parseComputerTarget(value);
|
|
136
75
|
if (target) {
|
|
137
|
-
setMetroPort(target.metroPort);
|
|
138
76
|
saveComputerTarget(value)
|
|
139
77
|
.then((savedTarget) => {
|
|
140
78
|
if (savedTarget) {
|
|
141
79
|
updateFeatureSettings({
|
|
142
80
|
computerHost: savedTarget.computerHost,
|
|
143
|
-
metroPort: savedTarget.metroPort,
|
|
144
81
|
});
|
|
145
82
|
}
|
|
146
83
|
})
|
|
@@ -150,17 +87,6 @@ export function DevConnectTab({ snapshot, feature }: DebugFeatureRenderProps<Dev
|
|
|
150
87
|
setMessage(null);
|
|
151
88
|
}, [updateFeatureSettings]);
|
|
152
89
|
|
|
153
|
-
const handleMetroPortChange = useCallback((value: string) => {
|
|
154
|
-
setMetroPort(value);
|
|
155
|
-
const normalized = normalizePort(value);
|
|
156
|
-
if (normalized) {
|
|
157
|
-
saveMetroPort(normalized)
|
|
158
|
-
.then(() => updateFeatureSettings({ metroPort: normalized }))
|
|
159
|
-
.catch(() => {});
|
|
160
|
-
}
|
|
161
|
-
setMessage(null);
|
|
162
|
-
}, [updateFeatureSettings]);
|
|
163
|
-
|
|
164
90
|
const handleDaemonPortChange = useCallback((value: string) => {
|
|
165
91
|
setDaemonPort(value);
|
|
166
92
|
const normalized = normalizePort(value);
|
|
@@ -194,38 +120,10 @@ export function DevConnectTab({ snapshot, feature }: DebugFeatureRenderProps<Dev
|
|
|
194
120
|
setComputerHost(normalizedHost);
|
|
195
121
|
}
|
|
196
122
|
|
|
197
|
-
const normalizedMetroPort = normalizePort(metroPort);
|
|
198
|
-
if (normalizedMetroPort) {
|
|
199
|
-
patch.metroPort = normalizedMetroPort;
|
|
200
|
-
writes.push(saveMetroPort(normalizedMetroPort));
|
|
201
|
-
setMetroPort(normalizedMetroPort);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
await Promise.all(writes);
|
|
205
|
-
updateFeatureSettings(patch);
|
|
206
|
-
return true;
|
|
207
|
-
}, [computerHost, daemonPort, isSim, metroPort, updateFeatureSettings]);
|
|
208
|
-
|
|
209
|
-
const persistMetroSettings = useCallback(async (): Promise<boolean> => {
|
|
210
|
-
if (!metroTarget) {
|
|
211
|
-
setMessage('Enter a valid computer IP and Metro port.');
|
|
212
|
-
return false;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const patch: DevConnectSettingsPatch = { metroPort: metroTarget.port };
|
|
216
|
-
const writes: Array<Promise<unknown>> = [saveMetroPort(metroTarget.port)];
|
|
217
|
-
setMetroPort(metroTarget.port);
|
|
218
|
-
|
|
219
|
-
if (!isSim) {
|
|
220
|
-
patch.computerHost = metroTarget.host;
|
|
221
|
-
writes.push(saveComputerTarget(metroTarget.hostPort));
|
|
222
|
-
setComputerHost(metroTarget.host);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
123
|
await Promise.all(writes);
|
|
226
124
|
updateFeatureSettings(patch);
|
|
227
125
|
return true;
|
|
228
|
-
}, [
|
|
126
|
+
}, [computerHost, daemonPort, isSim, updateFeatureSettings]);
|
|
229
127
|
|
|
230
128
|
const validateSettings = useCallback((): boolean => {
|
|
231
129
|
if (!isSim && !normalizeComputerHost(computerHost)) {
|
|
@@ -350,57 +248,7 @@ export function DevConnectTab({ snapshot, feature }: DebugFeatureRenderProps<Dev
|
|
|
350
248
|
}
|
|
351
249
|
}, [configureDaemon, persistConnectionSettings, validateSettings]);
|
|
352
250
|
|
|
353
|
-
const applyRemoteBundle = useCallback(async () => {
|
|
354
|
-
if (!metroTarget) {
|
|
355
|
-
setMessage('Enter a valid computer IP and Metro port.');
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
if (!snapshot.nativeMetroAvailable) {
|
|
359
|
-
setMessage(describeMetroFailure({ reason: 'native_unavailable' }));
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
setMetroBusy(true);
|
|
364
|
-
setMessage('Checking Metro...');
|
|
365
|
-
try {
|
|
366
|
-
if (!(await persistMetroSettings())) {
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
const result = await applyMetroBundle(metroTarget.host, metroTarget.port);
|
|
370
|
-
if (result.ok) {
|
|
371
|
-
setMessage(`Using Metro at ${result.hostPort}. Reloading...`);
|
|
372
|
-
} else {
|
|
373
|
-
setMessage(describeMetroFailure(result));
|
|
374
|
-
}
|
|
375
|
-
} finally {
|
|
376
|
-
setMetroBusy(false);
|
|
377
|
-
}
|
|
378
|
-
}, [metroTarget, persistMetroSettings, snapshot.nativeMetroAvailable]);
|
|
379
|
-
|
|
380
|
-
const resetRemoteBundle = useCallback(async () => {
|
|
381
|
-
if (!snapshot.nativeMetroAvailable) {
|
|
382
|
-
setMessage(describeMetroFailure({ reason: 'native_unavailable' }));
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
setMetroBusy(true);
|
|
387
|
-
try {
|
|
388
|
-
const result = await resetMetroBundle();
|
|
389
|
-
if (result.ok) {
|
|
390
|
-
setMessage('Metro host reset. Reloading...');
|
|
391
|
-
} else {
|
|
392
|
-
setMessage(describeMetroFailure(result));
|
|
393
|
-
}
|
|
394
|
-
} finally {
|
|
395
|
-
setMetroBusy(false);
|
|
396
|
-
}
|
|
397
|
-
}, [snapshot.nativeMetroAvailable]);
|
|
398
|
-
|
|
399
|
-
// Metro host switching only works in Debug builds. diagData is iOS-populated; when we know
|
|
400
|
-
// it's a Release build, disable the controls (Android reports null → stays enabled).
|
|
401
|
-
const metroReleaseBlocked = diagData ? !diagData.isDebugBuild : false;
|
|
402
251
|
const canConnect = isSim || (Boolean(normalizeComputerHost(computerHost)) && Boolean(normalizePort(daemonPort)));
|
|
403
|
-
const canUseMetro = Boolean(metroTarget) && snapshot.nativeMetroAvailable && !metroBusy && !metroReleaseBlocked;
|
|
404
252
|
const busy = sending || syncState === 'checking';
|
|
405
253
|
const subnetPrefix = snapshot.subnetPrefix;
|
|
406
254
|
const ipPlaceholder = subnetPrefix ? `${subnetPrefix}...` : '192.168.1.10';
|
|
@@ -411,7 +259,7 @@ export function DevConnectTab({ snapshot, feature }: DebugFeatureRenderProps<Dev
|
|
|
411
259
|
|
|
412
260
|
{isSim ? (
|
|
413
261
|
<View style={styles.badge}>
|
|
414
|
-
<Text style={styles.badgeText}>Simulator/emulator - using {
|
|
262
|
+
<Text style={styles.badgeText}>Simulator/emulator - using {getSimulatorHost()}</Text>
|
|
415
263
|
</View>
|
|
416
264
|
) : (
|
|
417
265
|
<View style={styles.section}>
|
|
@@ -448,36 +296,19 @@ export function DevConnectTab({ snapshot, feature }: DebugFeatureRenderProps<Dev
|
|
|
448
296
|
)}
|
|
449
297
|
|
|
450
298
|
<View style={styles.section}>
|
|
451
|
-
<Text style={styles.label}>
|
|
452
|
-
<View style={styles.
|
|
453
|
-
<
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
returnKeyType="done"
|
|
465
|
-
/>
|
|
466
|
-
</View>
|
|
467
|
-
<View style={styles.portField}>
|
|
468
|
-
<Text style={styles.portLabel}>Logs</Text>
|
|
469
|
-
<TextInput
|
|
470
|
-
style={styles.portInput}
|
|
471
|
-
value={daemonPort}
|
|
472
|
-
onChangeText={handleDaemonPortChange}
|
|
473
|
-
placeholder={DEFAULT_DAEMON_PORT}
|
|
474
|
-
placeholderTextColor={Colors.textLight}
|
|
475
|
-
autoCapitalize="none"
|
|
476
|
-
autoCorrect={false}
|
|
477
|
-
keyboardType="number-pad"
|
|
478
|
-
returnKeyType="done"
|
|
479
|
-
/>
|
|
480
|
-
</View>
|
|
299
|
+
<Text style={styles.label}>Desktop Logs Port</Text>
|
|
300
|
+
<View style={styles.inputRow}>
|
|
301
|
+
<TextInput
|
|
302
|
+
style={styles.input}
|
|
303
|
+
value={daemonPort}
|
|
304
|
+
onChangeText={handleDaemonPortChange}
|
|
305
|
+
placeholder={DEFAULT_DAEMON_PORT}
|
|
306
|
+
placeholderTextColor={Colors.textLight}
|
|
307
|
+
autoCapitalize="none"
|
|
308
|
+
autoCorrect={false}
|
|
309
|
+
keyboardType="number-pad"
|
|
310
|
+
returnKeyType="done"
|
|
311
|
+
/>
|
|
481
312
|
</View>
|
|
482
313
|
</View>
|
|
483
314
|
|
|
@@ -505,129 +336,6 @@ export function DevConnectTab({ snapshot, feature }: DebugFeatureRenderProps<Dev
|
|
|
505
336
|
</View>
|
|
506
337
|
|
|
507
338
|
{message ? <Text style={styles.message}>{message}</Text> : null}
|
|
508
|
-
|
|
509
|
-
<View style={styles.section}>
|
|
510
|
-
<View style={styles.sectionTitleRow}>
|
|
511
|
-
<Text style={styles.sectionTitle}>Remote JS Bundle</Text>
|
|
512
|
-
{diagData ? (
|
|
513
|
-
<View style={styles.swizzleBadge}>
|
|
514
|
-
<View style={[styles.swizzleDot, diagData.isDebugBuild ? styles.dotGreen : styles.dotRed]} />
|
|
515
|
-
<Text style={styles.swizzleBadgeText}>
|
|
516
|
-
{diagData.isDebugBuild ? 'debug build' : 'release: disabled'}
|
|
517
|
-
</Text>
|
|
518
|
-
</View>
|
|
519
|
-
) : null}
|
|
520
|
-
</View>
|
|
521
|
-
<Text style={styles.sectionDesc}>
|
|
522
|
-
Starts from the embedded bundle. After you apply a computer IP, hot-reloads from that
|
|
523
|
-
Metro. Debug builds only — use Reset to go back to the embedded bundle.
|
|
524
|
-
</Text>
|
|
525
|
-
|
|
526
|
-
{!metroUrls ? (
|
|
527
|
-
<View style={styles.stepCard}>
|
|
528
|
-
<Text style={styles.stepHint}>Enter your computer IP and Metro port to get started.</Text>
|
|
529
|
-
</View>
|
|
530
|
-
) : (
|
|
531
|
-
<View style={styles.stepCard}>
|
|
532
|
-
<View style={styles.urlRow}>
|
|
533
|
-
<Text style={styles.urlLabel}>HTTP</Text>
|
|
534
|
-
<Text style={styles.urlText} numberOfLines={1}>{metroUrls.httpUrl}</Text>
|
|
535
|
-
</View>
|
|
536
|
-
<View style={styles.urlRow}>
|
|
537
|
-
<Text style={styles.urlLabel}>Expo</Text>
|
|
538
|
-
<Text style={styles.urlText} numberOfLines={1}>{metroUrls.expUrl}</Text>
|
|
539
|
-
</View>
|
|
540
|
-
</View>
|
|
541
|
-
)}
|
|
542
|
-
|
|
543
|
-
<View style={styles.actions}>
|
|
544
|
-
<TouchableOpacity
|
|
545
|
-
style={[styles.primaryButton, !canUseMetro && styles.buttonDisabled]}
|
|
546
|
-
onPress={applyRemoteBundle}
|
|
547
|
-
disabled={!canUseMetro}
|
|
548
|
-
activeOpacity={0.75}
|
|
549
|
-
>
|
|
550
|
-
<Text style={styles.primaryButtonText}>
|
|
551
|
-
{metroBusy ? 'Checking...' : 'Use Metro Bundle'}
|
|
552
|
-
</Text>
|
|
553
|
-
</TouchableOpacity>
|
|
554
|
-
<TouchableOpacity
|
|
555
|
-
style={[styles.secondaryButton, (!snapshot.nativeMetroAvailable || metroBusy) && styles.buttonDisabled]}
|
|
556
|
-
onPress={resetRemoteBundle}
|
|
557
|
-
disabled={!snapshot.nativeMetroAvailable || metroBusy}
|
|
558
|
-
activeOpacity={0.75}
|
|
559
|
-
>
|
|
560
|
-
<Text style={styles.secondaryButtonText}>Reset</Text>
|
|
561
|
-
</TouchableOpacity>
|
|
562
|
-
</View>
|
|
563
|
-
|
|
564
|
-
{!snapshot.nativeMetroAvailable ? (
|
|
565
|
-
<Text style={styles.hint}>Native DevConnect requires pod install / Gradle sync and app rebuild.</Text>
|
|
566
|
-
) : null}
|
|
567
|
-
|
|
568
|
-
{metroReleaseBlocked ? (
|
|
569
|
-
<Text style={styles.diagWarning}>
|
|
570
|
-
⚠ This is a Release build. Metro host switching is disabled — RN loads the embedded
|
|
571
|
-
bundle and strips the packager machinery in Release. Run a Debug build to switch hosts.
|
|
572
|
-
</Text>
|
|
573
|
-
) : null}
|
|
574
|
-
</View>
|
|
575
|
-
|
|
576
|
-
{snapshot.nativeMetroAvailable && diagData ? (
|
|
577
|
-
<View style={styles.section}>
|
|
578
|
-
<TouchableOpacity
|
|
579
|
-
style={styles.diagHeader}
|
|
580
|
-
onPress={() => { setDiagOpen((v) => !v); refreshDiag(); }}
|
|
581
|
-
activeOpacity={0.7}
|
|
582
|
-
>
|
|
583
|
-
<Text style={styles.sectionTitle}>iOS Bundle Status</Text>
|
|
584
|
-
<Text style={styles.diagChevron}>{diagOpen ? '▲' : '▼'}</Text>
|
|
585
|
-
</TouchableOpacity>
|
|
586
|
-
|
|
587
|
-
{diagOpen ? (
|
|
588
|
-
<View style={styles.diagCard}>
|
|
589
|
-
<View style={styles.diagRow}>
|
|
590
|
-
<Text style={styles.diagKey}>AppDelegate</Text>
|
|
591
|
-
<Text style={styles.diagVal}>{diagData.appDelegateClass}</Text>
|
|
592
|
-
</View>
|
|
593
|
-
<View style={styles.diagRow}>
|
|
594
|
-
<Text style={styles.diagKey}>packagerHost</Text>
|
|
595
|
-
<Text style={styles.diagVal}>{diagData.persistedMetroHost ?? '—'}</Text>
|
|
596
|
-
</View>
|
|
597
|
-
<View style={styles.diagRow}>
|
|
598
|
-
<Text style={styles.diagKey}>embedded</Text>
|
|
599
|
-
<Text style={[styles.diagVal, diagData.hasEmbeddedBundle ? styles.diagGood : styles.diagWarn]}>
|
|
600
|
-
{diagData.hasEmbeddedBundle ? 'main.jsbundle' : 'missing'}
|
|
601
|
-
</Text>
|
|
602
|
-
</View>
|
|
603
|
-
<View style={styles.diagRow}>
|
|
604
|
-
<Text style={styles.diagKey}>build</Text>
|
|
605
|
-
<Text style={[styles.diagVal, diagData.isDebugBuild ? styles.diagGood : styles.diagWarn]}>
|
|
606
|
-
{diagData.isDebugBuild ? 'Debug' : 'Release'}
|
|
607
|
-
</Text>
|
|
608
|
-
</View>
|
|
609
|
-
<View style={styles.diagRow}>
|
|
610
|
-
<Text style={styles.diagKey}>embedded-first</Text>
|
|
611
|
-
<Text style={[styles.diagVal, diagData.embeddedFirstHookInstalled ? styles.diagGood : styles.diagWarn]}>
|
|
612
|
-
{diagData.embeddedFirstHookInstalled ? 'active' : 'inactive'}
|
|
613
|
-
</Text>
|
|
614
|
-
</View>
|
|
615
|
-
{!diagData.embeddedFirstHookInstalled ? (
|
|
616
|
-
<Text style={styles.diagWarning}>
|
|
617
|
-
⚠ Embedded-first hook not active (bundleRoot=
|
|
618
|
-
{diagData.bundleRootHookInstalled ? 'Y' : 'N'}). Rebuild after pod install.
|
|
619
|
-
Without it, Debug may still try Metro on launch.
|
|
620
|
-
</Text>
|
|
621
|
-
) : diagData.hasEmbeddedBundle === false ? (
|
|
622
|
-
<Text style={styles.diagWarning}>
|
|
623
|
-
⚠ main.jsbundle is missing from the app package. Build with an embedded bundle
|
|
624
|
-
(e.g. export/bundle) or cold start cannot use offline JS.
|
|
625
|
-
</Text>
|
|
626
|
-
) : null}
|
|
627
|
-
</View>
|
|
628
|
-
) : null}
|
|
629
|
-
</View>
|
|
630
|
-
) : null}
|
|
631
339
|
</ScrollView>
|
|
632
340
|
</KeyboardAvoidingView>
|
|
633
341
|
);
|
|
@@ -647,8 +355,6 @@ const styles = StyleSheet.create({
|
|
|
647
355
|
},
|
|
648
356
|
badgeText: { fontSize: 13, fontWeight: '500', color: Colors.primary },
|
|
649
357
|
section: { marginBottom: 14 },
|
|
650
|
-
sectionTitle: { fontSize: 14, fontWeight: '600', color: Colors.text, marginBottom: 4 },
|
|
651
|
-
sectionDesc: { fontSize: 12, color: Colors.textSecondary, marginBottom: 10, lineHeight: 17 },
|
|
652
358
|
label: { fontSize: 13, fontWeight: '500', color: Colors.textSecondary, marginBottom: 6 },
|
|
653
359
|
inputRow: { flexDirection: 'row', alignItems: 'center' },
|
|
654
360
|
subnetHint: { marginTop: 6 },
|
|
@@ -665,20 +371,6 @@ const styles = StyleSheet.create({
|
|
|
665
371
|
color: Colors.text,
|
|
666
372
|
fontFamily: 'Courier',
|
|
667
373
|
},
|
|
668
|
-
portRow: { flexDirection: 'row', gap: 10 },
|
|
669
|
-
portField: { flex: 1 },
|
|
670
|
-
portLabel: { fontSize: 11, color: Colors.textSecondary, marginBottom: 4 },
|
|
671
|
-
portInput: {
|
|
672
|
-
backgroundColor: Colors.surface,
|
|
673
|
-
borderWidth: 1,
|
|
674
|
-
borderColor: Colors.border,
|
|
675
|
-
borderRadius: 8,
|
|
676
|
-
paddingHorizontal: 12,
|
|
677
|
-
paddingVertical: 9,
|
|
678
|
-
fontSize: 13,
|
|
679
|
-
color: Colors.text,
|
|
680
|
-
fontFamily: 'Courier',
|
|
681
|
-
},
|
|
682
374
|
actions: { flexDirection: 'row', gap: 10, marginTop: 4, marginBottom: 12 },
|
|
683
375
|
primaryButton: {
|
|
684
376
|
flex: 1,
|
|
@@ -702,60 +394,4 @@ const styles = StyleSheet.create({
|
|
|
702
394
|
secondaryButtonText: { color: Colors.primary, fontSize: 14, fontWeight: '600' },
|
|
703
395
|
buttonDisabled: { opacity: 0.5 },
|
|
704
396
|
message: { fontSize: 12, lineHeight: 17, color: Colors.textSecondary, marginBottom: 12 },
|
|
705
|
-
hint: { fontSize: 12, color: Colors.textLight, lineHeight: 17 },
|
|
706
|
-
stepCard: {
|
|
707
|
-
backgroundColor: Colors.surface,
|
|
708
|
-
borderWidth: 1,
|
|
709
|
-
borderColor: Colors.border,
|
|
710
|
-
borderRadius: 10,
|
|
711
|
-
padding: 12,
|
|
712
|
-
marginBottom: 8,
|
|
713
|
-
},
|
|
714
|
-
stepHint: { fontSize: 12, color: Colors.textSecondary, lineHeight: 17 },
|
|
715
|
-
urlLabel: {
|
|
716
|
-
minWidth: 40,
|
|
717
|
-
fontSize: 10,
|
|
718
|
-
fontWeight: '600',
|
|
719
|
-
color: Colors.primary,
|
|
720
|
-
backgroundColor: `${Colors.primary}15`,
|
|
721
|
-
paddingHorizontal: 6,
|
|
722
|
-
paddingVertical: 2,
|
|
723
|
-
borderRadius: 4,
|
|
724
|
-
marginRight: 8,
|
|
725
|
-
textAlign: 'center',
|
|
726
|
-
},
|
|
727
|
-
urlRow: {
|
|
728
|
-
flexDirection: 'row',
|
|
729
|
-
alignItems: 'center',
|
|
730
|
-
borderBottomWidth: StyleSheet.hairlineWidth,
|
|
731
|
-
borderBottomColor: Colors.border,
|
|
732
|
-
paddingVertical: 7,
|
|
733
|
-
},
|
|
734
|
-
urlText: { flex: 1, fontSize: 13, fontFamily: 'Courier', color: Colors.text },
|
|
735
|
-
sectionTitleRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 4 },
|
|
736
|
-
swizzleBadge: { flexDirection: 'row', alignItems: 'center', gap: 4, paddingHorizontal: 7, paddingVertical: 3, borderRadius: 10, backgroundColor: Colors.surface, borderWidth: 1, borderColor: Colors.border },
|
|
737
|
-
swizzleDot: { width: 6, height: 6, borderRadius: 3 },
|
|
738
|
-
dotGreen: { backgroundColor: '#34C759' },
|
|
739
|
-
dotRed: { backgroundColor: '#FF3B30' },
|
|
740
|
-
swizzleBadgeText: { fontSize: 11, color: Colors.textSecondary, fontFamily: 'Courier' },
|
|
741
|
-
diagHeader: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 6 },
|
|
742
|
-
diagChevron: { fontSize: 12, color: Colors.textSecondary },
|
|
743
|
-
diagCard: {
|
|
744
|
-
backgroundColor: Colors.surface,
|
|
745
|
-
borderWidth: 1,
|
|
746
|
-
borderColor: Colors.border,
|
|
747
|
-
borderRadius: 10,
|
|
748
|
-
padding: 10,
|
|
749
|
-
},
|
|
750
|
-
diagRow: { flexDirection: 'row', justifyContent: 'space-between', paddingVertical: 4 },
|
|
751
|
-
diagKey: { fontSize: 12, color: Colors.textSecondary, fontFamily: 'Courier' },
|
|
752
|
-
diagVal: { fontSize: 12, color: Colors.text, fontFamily: 'Courier', fontWeight: '600' },
|
|
753
|
-
diagGood: { color: '#34C759' },
|
|
754
|
-
diagWarn: { color: '#FF9500' },
|
|
755
|
-
diagWarning: {
|
|
756
|
-
marginTop: 10,
|
|
757
|
-
fontSize: 11,
|
|
758
|
-
color: '#FF9500',
|
|
759
|
-
lineHeight: 16,
|
|
760
|
-
},
|
|
761
397
|
});
|
|
@@ -2,7 +2,6 @@ import { daemonClient } from '../../utils/DaemonClient';
|
|
|
2
2
|
import { getPreference, KEYS, setPreference } from '../../utils/debugPreferences';
|
|
3
3
|
import {
|
|
4
4
|
DEFAULT_DAEMON_PORT,
|
|
5
|
-
DEFAULT_METRO_PORT,
|
|
6
5
|
buildDaemonDeviceHost,
|
|
7
6
|
normalizeComputerHost,
|
|
8
7
|
normalizePort,
|
|
@@ -13,17 +12,14 @@ import { isSimulator } from './platformDetect';
|
|
|
13
12
|
|
|
14
13
|
export interface DevConnectPreferences {
|
|
15
14
|
computerHost: string;
|
|
16
|
-
metroPort: string;
|
|
17
15
|
daemonPort: string;
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
export async function loadDevConnectPreferences(): Promise<DevConnectPreferences> {
|
|
21
19
|
const storedHost = await getPreference(KEYS.computerHost);
|
|
22
|
-
const storedMetroPort = await getPreference(KEYS.metroPort);
|
|
23
20
|
const storedDaemonPort = await getPreference(KEYS.daemonPort);
|
|
24
21
|
return {
|
|
25
22
|
computerHost: storedHost ? normalizeComputerHost(storedHost) ?? '' : '',
|
|
26
|
-
metroPort: storedMetroPort ? normalizePort(storedMetroPort) ?? DEFAULT_METRO_PORT : DEFAULT_METRO_PORT,
|
|
27
23
|
daemonPort: storedDaemonPort ? normalizePort(storedDaemonPort) ?? DEFAULT_DAEMON_PORT : DEFAULT_DAEMON_PORT,
|
|
28
24
|
};
|
|
29
25
|
}
|
|
@@ -35,7 +31,6 @@ export async function saveComputerTarget(value: string): Promise<ParsedComputerT
|
|
|
35
31
|
}
|
|
36
32
|
|
|
37
33
|
await setPreference(KEYS.computerHost, target.computerHost);
|
|
38
|
-
await setPreference(KEYS.metroPort, target.metroPort);
|
|
39
34
|
return target;
|
|
40
35
|
}
|
|
41
36
|
|
|
@@ -49,16 +44,6 @@ export async function saveComputerHost(value: string): Promise<string | null> {
|
|
|
49
44
|
return host;
|
|
50
45
|
}
|
|
51
46
|
|
|
52
|
-
export async function saveMetroPort(value: string): Promise<string | null> {
|
|
53
|
-
const normalized = normalizePort(value);
|
|
54
|
-
if (!normalized) {
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
await setPreference(KEYS.metroPort, normalized);
|
|
59
|
-
return normalized;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
47
|
export async function saveDaemonPort(value: string): Promise<string | null> {
|
|
63
48
|
const normalized = normalizePort(value);
|
|
64
49
|
if (!normalized) {
|
|
@@ -1,27 +1,7 @@
|
|
|
1
|
-
export const DEFAULT_METRO_PORT = '8081';
|
|
2
1
|
export const DEFAULT_DAEMON_PORT = '3799';
|
|
3
2
|
|
|
4
|
-
export interface MetroUrls {
|
|
5
|
-
expUrl: string;
|
|
6
|
-
httpUrl: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface MetroTarget {
|
|
10
|
-
host: string;
|
|
11
|
-
port: string;
|
|
12
|
-
hostPort: string;
|
|
13
|
-
statusUrl: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
3
|
export interface ParsedComputerTarget {
|
|
17
4
|
computerHost: string;
|
|
18
|
-
metroPort: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface ParsedMetroQrPayload {
|
|
22
|
-
computerHost: string;
|
|
23
|
-
metroPort: string;
|
|
24
|
-
source: string;
|
|
25
5
|
}
|
|
26
6
|
|
|
27
7
|
function isValidIpv4(host: string): boolean {
|
|
@@ -92,67 +72,7 @@ export function parseComputerTarget(raw: string): ParsedComputerTarget | null {
|
|
|
92
72
|
return null;
|
|
93
73
|
}
|
|
94
74
|
|
|
95
|
-
|
|
96
|
-
? normalizePort(parsed.port)
|
|
97
|
-
: DEFAULT_METRO_PORT;
|
|
98
|
-
if (!metroPort) {
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return {
|
|
103
|
-
computerHost: parsed.host,
|
|
104
|
-
metroPort,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function normalizeMetroHost(rawHost: string): string | null {
|
|
109
|
-
const parsed = parseHostAndPort(rawHost);
|
|
110
|
-
if (!parsed) {
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
if (parsed.host === 'localhost') {
|
|
114
|
-
return parsed.host;
|
|
115
|
-
}
|
|
116
|
-
return isValidIpv4(parsed.host) ? parsed.host : null;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export function buildMetroTarget(rawHost: string, rawPort = DEFAULT_METRO_PORT): MetroTarget | null {
|
|
120
|
-
const host = normalizeMetroHost(rawHost);
|
|
121
|
-
if (!host) {
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const port = normalizePort(rawPort);
|
|
126
|
-
if (!port) {
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
host,
|
|
132
|
-
port,
|
|
133
|
-
hostPort: `${host}:${port}`,
|
|
134
|
-
statusUrl: `http://${host}:${port}/status`,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export function buildMetroUrls(rawHost: string, rawPort = DEFAULT_METRO_PORT): MetroUrls | null {
|
|
139
|
-
const target = buildMetroTarget(rawHost, rawPort);
|
|
140
|
-
if (!target) {
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return {
|
|
145
|
-
expUrl: `exp://${target.hostPort}`,
|
|
146
|
-
httpUrl: `http://${target.hostPort}`,
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
export function parseMetroQrPayload(payload: string): ParsedMetroQrPayload | null {
|
|
151
|
-
const target = parseComputerTarget(payload);
|
|
152
|
-
if (!target) {
|
|
153
|
-
return null;
|
|
154
|
-
}
|
|
155
|
-
return { ...target, source: payload };
|
|
75
|
+
return { computerHost: parsed.host };
|
|
156
76
|
}
|
|
157
77
|
|
|
158
78
|
export function buildDaemonDeviceHost(computerHost: string, daemonPort: string): string {
|