0
# Device Management
1
2
Device connection handling for React Native apps that connect to the proxy. Each device represents a single React Native application connection and can have multiple inspectable pages (JavaScript contexts). The Device class manages debugger sessions, message forwarding, and handles Chrome DevTools Protocol communication.
3
4
## Capabilities
5
6
### Device Class
7
8
Represents single device connection to Inspector Proxy. Each device can have multiple inspectable pages and handles debugger session management.
9
10
```javascript { .api }
11
/**
12
* Device class represents single device connection to Inspector Proxy
13
* @param id - Device ID
14
* @param name - Device name
15
* @param app - Package name of the app
16
* @param socket - WebSocket connection to device
17
* @param projectRoot - Root of the project used for relative to absolute source path conversion
18
*/
19
class Device {
20
constructor(
21
id: string,
22
name: string,
23
app: string,
24
socket: WS,
25
projectRoot: string
26
);
27
28
/**
29
* Returns device name
30
* @returns Device name string
31
*/
32
getName(): string;
33
34
/**
35
* Returns app package name
36
* @returns App package name string
37
*/
38
getApp(): string;
39
40
/**
41
* Returns list of inspectable pages from this device
42
* @returns Array of Page objects
43
*/
44
getPagesList(): Array<Page>;
45
46
/**
47
* Handles new debugger connection to this device
48
* @param socket - WebSocket connection from debugger
49
* @param pageId - ID of the page to debug
50
*/
51
handleDebuggerConnection(socket: WS, pageId: string): void;
52
53
/**
54
* Handles cleaning up a duplicate device connection
55
* @param newDevice - New device instance attempting to connect
56
*/
57
handleDuplicateDeviceConnection(newDevice: Device): void;
58
}
59
```
60
61
**Usage Examples:**
62
63
```javascript
64
const Device = require("metro-inspector-proxy/src/Device");
65
const WebSocket = require("ws");
66
67
// Device instances are typically created automatically by InspectorProxy
68
// when React Native apps connect to /inspector/device WebSocket endpoint
69
70
// Example of how devices are created internally:
71
const deviceSocket = new WebSocket("ws://localhost:8081/inspector/device?device=myphone&name=iPhone&app=MyApp");
72
const device = new Device(
73
"myphone", // device ID
74
"iPhone", // device name
75
"MyApp", // app name
76
deviceSocket, // WebSocket connection
77
"/path/to/project" // project root
78
);
79
80
// Get device information
81
console.log(device.getName()); // "iPhone"
82
console.log(device.getApp()); // "MyApp"
83
84
// Get available pages for debugging
85
const pages = device.getPagesList();
86
console.log(pages); // Array of Page objects
87
```
88
89
### Page Information
90
91
Page objects represent individual JavaScript contexts that can be debugged.
92
93
```javascript { .api }
94
interface Page {
95
id: string; // Unique page identifier
96
title: string; // Page title (usually "React Native")
97
vm: string; // JavaScript engine name (e.g., "Hermes", "JSC")
98
app: string; // App name
99
}
100
```
101
102
### Debugger Connection Handling
103
104
When a debugger (Chrome DevTools) connects to debug a specific page:
105
106
```javascript
107
// Debugger connects to WebSocket endpoint with device and page IDs
108
const debuggerSocket = new WebSocket("ws://localhost:8081/inspector/debug?device=myphone&page=1");
109
110
// Device handles the debugger connection internally
111
device.handleDebuggerConnection(debuggerSocket, "1");
112
```
113
114
The Device class:
115
1. Disconnects any existing debugger for this device
116
2. Sets up message forwarding between debugger and device
117
3. Sends connect event to the React Native app
118
4. Handles Chrome DevTools Protocol message transformation
119
120
### Message Processing
121
122
The Device class handles bidirectional message forwarding and transformation:
123
124
#### Messages from Device to Debugger
125
- **getPages responses**: Updates local page list
126
- **wrappedEvent messages**: Chrome DevTools Protocol messages forwarded to debugger
127
- **disconnect events**: Handles page reloads and app disconnections
128
129
#### Messages from Debugger to Device
130
- **Chrome DevTools Protocol messages**: Forwarded as wrappedEvent to device
131
- **Special handling for**:
132
- `Debugger.setBreakpointByUrl`: URL transformation for Android emulator addresses
133
- `Debugger.getScriptSource`: Local file serving and HTTP source map fetching
134
135
### React Native Reloadable Page
136
137
The Device class provides special handling for React Native app reloads:
138
139
```javascript { .api }
140
// Special page ID for reloadable React Native debugging
141
const REACT_NATIVE_RELOADABLE_PAGE_ID = "-1";
142
143
// When available, this creates a special page entry:
144
{
145
id: "-1",
146
title: "React Native Experimental (Improved Chrome Reloads)",
147
vm: "don't use",
148
app: "MyApp"
149
}
150
```
151
152
This allows debuggers to maintain connections across React Native app reloads.
153
154
### Duplicate Connection Handling
155
156
When the same device attempts to reconnect (common during app reloads):
157
158
```javascript
159
// If same device and app reconnect
160
if (oldDevice.getApp() === newDevice.getApp() &&
161
oldDevice.getName() === newDevice.getName()) {
162
// Reuse existing debugger connection with new device socket
163
olddevice.handleDuplicateDeviceConnection(newDevice);
164
} else {
165
// Different app/device - close old connections
166
oldDevice.close();
167
}
168
```
169
170
### Source Path Resolution
171
172
The Device class handles source path resolution for debugging:
173
174
#### Android Emulator Address Translation
175
```javascript
176
// Translates Android emulator addresses to localhost for Chrome DevTools
177
const EMULATOR_LOCALHOST_ADDRESSES = ["10.0.2.2", "10.0.3.2"];
178
179
// Example: "http://10.0.2.2:8081/bundle.js" becomes "http://localhost:8081/bundle.js"
180
```
181
182
#### File URL Handling
183
```javascript
184
// Adds file:// prefix to alphanumeric script IDs for Chrome DevTools compatibility
185
const FILE_PREFIX = "file://";
186
187
// Example: "12abc34" becomes "file://12abc34"
188
```
189
190
#### Source Map Processing
191
- Fetches HTTP-based source maps and converts to data URLs
192
- Handles local file reading for source content
193
- Maintains script ID to source path mapping for `Debugger.getScriptSource` requests
194
195
### Error Handling
196
197
The Device class provides error handling and debugging support:
198
199
```javascript { .api }
200
/**
201
* Sends error message to connected debugger console
202
* @param message - Error message to display in debugger console
203
*/
204
_sendErrorToDebugger(message: string): void;
205
206
/**
207
* Sends message to connected device
208
* @param message - Message to send to device
209
*/
210
_sendMessageToDevice(message: MessageToDevice): void;
211
212
/**
213
* Processes message from device, handling special cases like getPages and wrappedEvent
214
* @param message - Message received from device
215
*/
216
_handleMessageFromDevice(message: MessageFromDevice): void;
217
218
/**
219
* Processes messages from device with source path transformation
220
* @param payload - Message payload with method and params
221
* @param debuggerInfo - Information about current debugger connection
222
*/
223
_processMessageFromDevice(
224
payload: { method: string, params: { sourceMapURL: string, url: string } },
225
debuggerInfo: DebuggerInfo
226
): Promise<void>;
227
228
/**
229
* Intercepts and processes messages from debugger before forwarding to device
230
* @param req - Debugger request
231
* @param debuggerInfo - Information about current debugger connection
232
* @param socket - WebSocket connection to debugger
233
* @returns Whether message was handled locally (true) or should be forwarded (false)
234
*/
235
_interceptMessageFromDebugger(
236
req: DebuggerRequest,
237
debuggerInfo: DebuggerInfo,
238
socket: WS
239
): boolean;
240
```
241
242
Errors are sent to the debugger as `Runtime.consoleAPICalled` events with type 'error', appearing in the Chrome DevTools console.