react-native-debug-toolkit 3.3.2 → 3.3.4
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 +40 -1
- package/README.zh-CN.md +40 -1
- package/app.plugin.js +51 -0
- package/bin/debug-toolkit.js +18 -2
- package/dev-client.js +3 -0
- package/ios/DebugToolkitDevConnect.h +17 -0
- package/ios/DebugToolkitDevConnect.mm +260 -212
- package/lib/commonjs/features/devConnect/DevConnectTab.js +127 -126
- package/lib/commonjs/features/devConnect/DevConnectTab.js.map +1 -1
- package/lib/commonjs/features/devConnect/nativeDevConnect.js +0 -12
- package/lib/commonjs/features/devConnect/nativeDevConnect.js.map +1 -1
- package/lib/module/features/devConnect/DevConnectTab.js +129 -128
- package/lib/module/features/devConnect/DevConnectTab.js.map +1 -1
- package/lib/module/features/devConnect/nativeDevConnect.js +0 -11
- package/lib/module/features/devConnect/nativeDevConnect.js.map +1 -1
- package/lib/typescript/src/features/devConnect/DevConnectTab.d.ts.map +1 -1
- package/lib/typescript/src/features/devConnect/nativeDevConnect.d.ts +6 -4
- package/lib/typescript/src/features/devConnect/nativeDevConnect.d.ts.map +1 -1
- package/package.json +6 -2
- package/scripts/bundle/android.js +101 -0
- package/scripts/bundle/cli.js +57 -0
- package/scripts/bundle/doctor.js +38 -0
- package/scripts/bundle/ios.js +179 -0
- package/scripts/bundle/setup.js +39 -0
- package/scripts/debug-bundle.gradle +147 -0
- package/src/features/devConnect/DevConnectTab.tsx +92 -92
- package/src/features/devConnect/nativeDevConnect.ts +8 -16
|
@@ -37,7 +37,6 @@ import {
|
|
|
37
37
|
} from './devConnectPreferences';
|
|
38
38
|
import {
|
|
39
39
|
applyMetroBundle,
|
|
40
|
-
clearNativeDiagnostics,
|
|
41
40
|
getNativeDiagnostics,
|
|
42
41
|
resetMetroBundle,
|
|
43
42
|
type NativeDiagnostics,
|
|
@@ -80,7 +79,6 @@ export function DevConnectTab({ snapshot, feature }: DebugFeatureRenderProps<Dev
|
|
|
80
79
|
const [metroBusy, setMetroBusy] = useState(false);
|
|
81
80
|
const [diagData, setDiagData] = useState<NativeDiagnostics | null>(null);
|
|
82
81
|
const [diagOpen, setDiagOpen] = useState(false);
|
|
83
|
-
const [diagBusy, setDiagBusy] = useState(false);
|
|
84
82
|
|
|
85
83
|
const isSim = snapshot.isSimulator;
|
|
86
84
|
|
|
@@ -88,6 +86,23 @@ export function DevConnectTab({ snapshot, feature }: DebugFeatureRenderProps<Dev
|
|
|
88
86
|
(feature as unknown as DevConnectFeatureControls).updateSettings?.(patch);
|
|
89
87
|
}, [feature]);
|
|
90
88
|
|
|
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
|
+
|
|
91
106
|
useEffect(() => {
|
|
92
107
|
setComputerHost(snapshot.computerHost);
|
|
93
108
|
}, [snapshot.computerHost]);
|
|
@@ -381,24 +396,11 @@ export function DevConnectTab({ snapshot, feature }: DebugFeatureRenderProps<Dev
|
|
|
381
396
|
}
|
|
382
397
|
}, [snapshot.nativeMetroAvailable]);
|
|
383
398
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
const result = await getNativeDiagnostics();
|
|
388
|
-
setDiagData(result);
|
|
389
|
-
setDiagOpen(true);
|
|
390
|
-
} finally {
|
|
391
|
-
setDiagBusy(false);
|
|
392
|
-
}
|
|
393
|
-
}, []);
|
|
394
|
-
|
|
395
|
-
const clearDiag = useCallback(async () => {
|
|
396
|
-
await clearNativeDiagnostics();
|
|
397
|
-
setDiagData(null);
|
|
398
|
-
}, []);
|
|
399
|
-
|
|
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;
|
|
400
402
|
const canConnect = isSim || (Boolean(normalizeComputerHost(computerHost)) && Boolean(normalizePort(daemonPort)));
|
|
401
|
-
const canUseMetro = Boolean(metroTarget) && snapshot.nativeMetroAvailable && !metroBusy;
|
|
403
|
+
const canUseMetro = Boolean(metroTarget) && snapshot.nativeMetroAvailable && !metroBusy && !metroReleaseBlocked;
|
|
402
404
|
const busy = sending || syncState === 'checking';
|
|
403
405
|
const subnetPrefix = snapshot.subnetPrefix;
|
|
404
406
|
const ipPlaceholder = subnetPrefix ? `${subnetPrefix}...` : '192.168.1.10';
|
|
@@ -505,9 +507,20 @@ export function DevConnectTab({ snapshot, feature }: DebugFeatureRenderProps<Dev
|
|
|
505
507
|
{message ? <Text style={styles.message}>{message}</Text> : null}
|
|
506
508
|
|
|
507
509
|
<View style={styles.section}>
|
|
508
|
-
<
|
|
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>
|
|
509
521
|
<Text style={styles.sectionDesc}>
|
|
510
|
-
|
|
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.
|
|
511
524
|
</Text>
|
|
512
525
|
|
|
513
526
|
{!metroUrls ? (
|
|
@@ -551,70 +564,66 @@ export function DevConnectTab({ snapshot, feature }: DebugFeatureRenderProps<Dev
|
|
|
551
564
|
{!snapshot.nativeMetroAvailable ? (
|
|
552
565
|
<Text style={styles.hint}>Native DevConnect requires pod install / Gradle sync and app rebuild.</Text>
|
|
553
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}
|
|
554
574
|
</View>
|
|
555
575
|
|
|
556
|
-
{snapshot.nativeMetroAvailable ? (
|
|
576
|
+
{snapshot.nativeMetroAvailable && diagData ? (
|
|
557
577
|
<View style={styles.section}>
|
|
558
578
|
<TouchableOpacity
|
|
559
579
|
style={styles.diagHeader}
|
|
560
|
-
onPress={() => setDiagOpen((v) => !v)}
|
|
580
|
+
onPress={() => { setDiagOpen((v) => !v); refreshDiag(); }}
|
|
561
581
|
activeOpacity={0.7}
|
|
562
582
|
>
|
|
563
|
-
<Text style={styles.sectionTitle}>
|
|
583
|
+
<Text style={styles.sectionTitle}>iOS Bundle Status</Text>
|
|
564
584
|
<Text style={styles.diagChevron}>{diagOpen ? '▲' : '▼'}</Text>
|
|
565
585
|
</TouchableOpacity>
|
|
566
586
|
|
|
567
587
|
{diagOpen ? (
|
|
568
588
|
<View style={styles.diagCard}>
|
|
569
|
-
{
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
<View style={styles.diagLog}>
|
|
589
|
-
{diagData.log.map((entry, i) => (
|
|
590
|
-
<Text key={i} style={styles.diagLogEntry}>{entry}</Text>
|
|
591
|
-
))}
|
|
592
|
-
</View>
|
|
593
|
-
) : (
|
|
594
|
-
<Text style={styles.diagEmpty}>No log entries yet.</Text>
|
|
595
|
-
)}
|
|
596
|
-
</>
|
|
597
|
-
) : (
|
|
598
|
-
<Text style={styles.diagEmpty}>Tap Read to fetch diagnostics.</Text>
|
|
599
|
-
)}
|
|
600
|
-
|
|
601
|
-
<View style={styles.diagActions}>
|
|
602
|
-
<TouchableOpacity
|
|
603
|
-
style={[styles.diagBtn, diagBusy && styles.buttonDisabled]}
|
|
604
|
-
onPress={readDiag}
|
|
605
|
-
disabled={diagBusy}
|
|
606
|
-
activeOpacity={0.75}
|
|
607
|
-
>
|
|
608
|
-
<Text style={styles.diagBtnText}>{diagBusy ? 'Reading…' : 'Read'}</Text>
|
|
609
|
-
</TouchableOpacity>
|
|
610
|
-
<TouchableOpacity
|
|
611
|
-
style={[styles.diagBtn, styles.diagBtnSecondary]}
|
|
612
|
-
onPress={clearDiag}
|
|
613
|
-
activeOpacity={0.75}
|
|
614
|
-
>
|
|
615
|
-
<Text style={[styles.diagBtnText, styles.diagBtnSecondaryText]}>Clear</Text>
|
|
616
|
-
</TouchableOpacity>
|
|
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>
|
|
617
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}
|
|
618
627
|
</View>
|
|
619
628
|
) : null}
|
|
620
629
|
</View>
|
|
@@ -723,6 +732,12 @@ const styles = StyleSheet.create({
|
|
|
723
732
|
paddingVertical: 7,
|
|
724
733
|
},
|
|
725
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' },
|
|
726
741
|
diagHeader: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 6 },
|
|
727
742
|
diagChevron: { fontSize: 12, color: Colors.textSecondary },
|
|
728
743
|
diagCard: {
|
|
@@ -736,26 +751,11 @@ const styles = StyleSheet.create({
|
|
|
736
751
|
diagKey: { fontSize: 12, color: Colors.textSecondary, fontFamily: 'Courier' },
|
|
737
752
|
diagVal: { fontSize: 12, color: Colors.text, fontFamily: 'Courier', fontWeight: '600' },
|
|
738
753
|
diagGood: { color: '#34C759' },
|
|
739
|
-
diagBad: { color: '#FF3B30' },
|
|
740
754
|
diagWarn: { color: '#FF9500' },
|
|
741
|
-
|
|
742
|
-
marginTop:
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
gap: 4,
|
|
747
|
-
},
|
|
748
|
-
diagLogEntry: { fontSize: 11, fontFamily: 'Courier', color: Colors.textSecondary, lineHeight: 16 },
|
|
749
|
-
diagEmpty: { fontSize: 12, color: Colors.textLight, fontStyle: 'italic', paddingVertical: 4 },
|
|
750
|
-
diagActions: { flexDirection: 'row', gap: 8, marginTop: 10 },
|
|
751
|
-
diagBtn: {
|
|
752
|
-
flex: 1,
|
|
753
|
-
alignItems: 'center',
|
|
754
|
-
paddingVertical: 8,
|
|
755
|
-
borderRadius: 8,
|
|
756
|
-
backgroundColor: Colors.primary,
|
|
755
|
+
diagWarning: {
|
|
756
|
+
marginTop: 10,
|
|
757
|
+
fontSize: 11,
|
|
758
|
+
color: '#FF9500',
|
|
759
|
+
lineHeight: 16,
|
|
757
760
|
},
|
|
758
|
-
diagBtnSecondary: { backgroundColor: 'transparent', borderWidth: 1, borderColor: Colors.border },
|
|
759
|
-
diagBtnText: { fontSize: 13, fontWeight: '600', color: '#fff' },
|
|
760
|
-
diagBtnSecondaryText: { color: Colors.primary },
|
|
761
761
|
});
|
|
@@ -3,10 +3,15 @@ import { NativeModules } from 'react-native';
|
|
|
3
3
|
import { buildMetroTarget } from './devConnectUtils';
|
|
4
4
|
|
|
5
5
|
export interface NativeDiagnostics {
|
|
6
|
-
log: string[];
|
|
7
|
-
swizzleInstalled: boolean;
|
|
8
|
-
swizzleInvoked: boolean;
|
|
9
6
|
persistedMetroHost: string | null;
|
|
7
|
+
appDelegateClass: string;
|
|
8
|
+
// Metro host switching only works in Debug builds (RN strips the packager machinery in
|
|
9
|
+
// Release). False means the Remote JS Bundle controls should be disabled.
|
|
10
|
+
isDebugBuild: boolean;
|
|
11
|
+
hasEmbeddedBundle?: boolean;
|
|
12
|
+
embeddedFirstHookInstalled?: boolean;
|
|
13
|
+
packagerHookInstalled?: boolean;
|
|
14
|
+
bundleRootHookInstalled?: boolean;
|
|
10
15
|
}
|
|
11
16
|
|
|
12
17
|
interface DebugToolkitDevConnectNativeModule {
|
|
@@ -17,7 +22,6 @@ interface DebugToolkitDevConnectNativeModule {
|
|
|
17
22
|
isDebugBuild?: () => Promise<boolean>;
|
|
18
23
|
getPreference?: (key: string) => Promise<string | null>;
|
|
19
24
|
getDiagnostics?: () => Promise<NativeDiagnostics>;
|
|
20
|
-
clearDiagnostics?: () => Promise<void>;
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
type MetroBundleFailureReason =
|
|
@@ -174,15 +178,3 @@ export async function getNativeDiagnostics(): Promise<NativeDiagnostics | null>
|
|
|
174
178
|
return null;
|
|
175
179
|
}
|
|
176
180
|
}
|
|
177
|
-
|
|
178
|
-
export async function clearNativeDiagnostics(): Promise<void> {
|
|
179
|
-
const nativeModule = getNativeModule();
|
|
180
|
-
if (!nativeModule?.clearDiagnostics) {
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
try {
|
|
184
|
-
await nativeModule.clearDiagnostics();
|
|
185
|
-
} catch {
|
|
186
|
-
// best-effort
|
|
187
|
-
}
|
|
188
|
-
}
|