webview.io 1.0.0 → 1.0.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/README.md +208 -37
- package/dist/index.d.ts +15 -2
- package/dist/index.js +198 -23
- package/package.json +2 -2
- package/src/index.ts +487 -157
package/README.md
CHANGED
|
@@ -5,13 +5,15 @@ Easy and friendly API to connect and interact between React Native applications
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **Bidirectional Communication**: Seamless messaging between React Native and WebView
|
|
8
|
-
- **
|
|
8
|
+
- **Robust Connection Handshake**: Three-way handshake with token validation for reliable connections
|
|
9
|
+
- **Enhanced Security**: Origin validation, message sanitization, token-based authentication, and payload size limits
|
|
9
10
|
- **Auto-Reconnection**: Automatic reconnection with exponential backoff strategy
|
|
11
|
+
- **Connection Timeout & Retries**: Configurable timeout with periodic connection attempts
|
|
10
12
|
- **Heartbeat Monitoring**: Connection health monitoring with configurable intervals
|
|
11
13
|
- **Message Queuing**: Queue messages when disconnected and replay on reconnection
|
|
12
14
|
- **Rate Limiting**: Configurable message rate limiting to prevent spam
|
|
13
15
|
- **Promise Support**: Modern async/await APIs with timeout handling
|
|
14
|
-
- **Connection Statistics**: Real-time connection and performance metrics
|
|
16
|
+
- **Connection Statistics**: Real-time connection and performance metrics including readiness state
|
|
15
17
|
- **Comprehensive Error Handling**: Detailed error types and handling mechanisms
|
|
16
18
|
|
|
17
19
|
## Installation
|
|
@@ -67,6 +69,11 @@ function MapComponent() {
|
|
|
67
69
|
wioRef.current.emit('hello', { message: 'Hello from React Native!' })
|
|
68
70
|
})
|
|
69
71
|
|
|
72
|
+
// Handle connection timeout
|
|
73
|
+
wioRef.current.on('connect_timeout', ({ attempts }) => {
|
|
74
|
+
console.log(`Connection failed after ${attempts} attempts`)
|
|
75
|
+
})
|
|
76
|
+
|
|
70
77
|
// Listen for messages
|
|
71
78
|
wioRef.current.on('response', (data) => {
|
|
72
79
|
console.log('Received:', data)
|
|
@@ -128,6 +135,8 @@ const wio = new WIO({
|
|
|
128
135
|
debug: false, // Enable debug logging
|
|
129
136
|
heartbeatInterval: 30000, // Heartbeat interval in ms (30s)
|
|
130
137
|
connectionTimeout: 10000, // Connection timeout in ms (10s)
|
|
138
|
+
connectionPingInterval: 2000, // Ping interval during connection (2s)
|
|
139
|
+
maxConnectionAttempts: 5, // Max connection attempts before timeout
|
|
131
140
|
maxMessageSize: 1024 * 1024, // Max message size in bytes (1MB)
|
|
132
141
|
maxMessagesPerSecond: 100, // Rate limit (100 messages/second)
|
|
133
142
|
autoReconnect: true, // Enable automatic reconnection
|
|
@@ -135,6 +144,48 @@ const wio = new WIO({
|
|
|
135
144
|
})
|
|
136
145
|
```
|
|
137
146
|
|
|
147
|
+
## Connection Architecture
|
|
148
|
+
|
|
149
|
+
### Three-Way Handshake
|
|
150
|
+
|
|
151
|
+
webview.io uses a robust three-way handshake protocol with token validation to ensure reliable connections:
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
1. WEBVIEW → ping (with token) → EMBEDDED
|
|
155
|
+
- WEBVIEW initiates connection with unique token
|
|
156
|
+
- Sends periodic pings until acknowledged
|
|
157
|
+
|
|
158
|
+
2. WEBVIEW ← pong (with token) ← EMBEDDED
|
|
159
|
+
- EMBEDDED responds with same token
|
|
160
|
+
- EMBEDDED announces readiness periodically
|
|
161
|
+
|
|
162
|
+
3. WEBVIEW → __connection_ack (with token) → EMBEDDED
|
|
163
|
+
- WEBVIEW confirms receipt of pong
|
|
164
|
+
- Both sides now confirmed connected
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
This prevents:
|
|
168
|
+
- Race conditions during initialization
|
|
169
|
+
- Accepting connections from wrong peers
|
|
170
|
+
- Silent connection failures
|
|
171
|
+
- Message loss during handshake
|
|
172
|
+
|
|
173
|
+
### Connection Flow Details
|
|
174
|
+
|
|
175
|
+
**WEBVIEW Side:**
|
|
176
|
+
- Sends initial `ping` with unique connection token
|
|
177
|
+
- Retries every 2 seconds (configurable via `connectionPingInterval`)
|
|
178
|
+
- Times out after 10 seconds (configurable via `connectionTimeout`)
|
|
179
|
+
- Maximum 5 attempts (configurable via `maxConnectionAttempts`)
|
|
180
|
+
- Fires `connect_timeout` event if all attempts fail
|
|
181
|
+
|
|
182
|
+
**EMBEDDED Side:**
|
|
183
|
+
- Automatically announces `__embedded_ready` when loaded
|
|
184
|
+
- Retries announcement every 2 seconds until connected
|
|
185
|
+
- Handles race condition if loaded before React Native
|
|
186
|
+
- Responds to `ping` with `pong` containing same token
|
|
187
|
+
- Confirms connection upon receiving `__connection_ack`
|
|
188
|
+
|
|
138
189
|
## Async/Await Support
|
|
139
190
|
|
|
140
191
|
### Send Messages with Acknowledgments
|
|
@@ -177,6 +228,21 @@ console.log('User data received:', userData)
|
|
|
177
228
|
|
|
178
229
|
## Enhanced Connection Management
|
|
179
230
|
|
|
231
|
+
### Connection Timeout Handling
|
|
232
|
+
|
|
233
|
+
```javascript
|
|
234
|
+
// Handle connection timeout (new event)
|
|
235
|
+
wio.on('connect_timeout', ({ attempts }) => {
|
|
236
|
+
console.log(`Failed to connect after ${attempts} attempts`)
|
|
237
|
+
// Optionally retry manually or show error to user
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
// With auto-reconnect enabled, timeout triggers reconnection
|
|
241
|
+
wio.on('reconnecting', ({ attempt, delay }) => {
|
|
242
|
+
console.log(`Reconnection attempt ${attempt}, waiting ${delay}ms`)
|
|
243
|
+
})
|
|
244
|
+
```
|
|
245
|
+
|
|
180
246
|
### Auto-Reconnection
|
|
181
247
|
|
|
182
248
|
```javascript
|
|
@@ -201,11 +267,13 @@ const stats = wio.getStats()
|
|
|
201
267
|
console.log(stats)
|
|
202
268
|
// {
|
|
203
269
|
// connected: true,
|
|
270
|
+
// embeddedReady: true, // NEW: EMBEDDED peer readiness state
|
|
204
271
|
// peerType: 'WEBVIEW',
|
|
205
272
|
// origin: 'https://example.com',
|
|
206
273
|
// lastHeartbeat: 1609459200000,
|
|
207
274
|
// queuedMessages: 0,
|
|
208
275
|
// reconnectAttempts: 0,
|
|
276
|
+
// connectionAttempts: 0, // NEW: Current connection attempts
|
|
209
277
|
// activeListeners: 5,
|
|
210
278
|
// messageRate: 2
|
|
211
279
|
// }
|
|
@@ -213,18 +281,24 @@ console.log(stats)
|
|
|
213
281
|
|
|
214
282
|
## Security Features
|
|
215
283
|
|
|
284
|
+
### Token-Based Authentication
|
|
285
|
+
|
|
286
|
+
Each connection uses a unique token for validation:
|
|
287
|
+
|
|
288
|
+
```javascript
|
|
289
|
+
// Automatically generated and validated during handshake
|
|
290
|
+
// Prevents accepting messages from previous connections
|
|
291
|
+
// Tokens are only used for connection-related events
|
|
292
|
+
```
|
|
293
|
+
|
|
216
294
|
### Origin Validation
|
|
217
295
|
|
|
218
296
|
```javascript
|
|
219
|
-
// Strict origin checking (
|
|
220
|
-
|
|
297
|
+
// Strict origin checking (React Native side)
|
|
298
|
+
wio.initiate(webViewRef, 'https://trusted-domain.com')
|
|
221
299
|
|
|
222
|
-
//
|
|
223
|
-
|
|
224
|
-
if (error.type === 'INVALID_ORIGIN') {
|
|
225
|
-
console.log(`Rejected message from ${error.received}`)
|
|
226
|
-
}
|
|
227
|
-
})
|
|
300
|
+
// Messages from other origins are automatically rejected
|
|
301
|
+
// No additional configuration needed
|
|
228
302
|
```
|
|
229
303
|
|
|
230
304
|
### Message Sanitization
|
|
@@ -257,17 +331,8 @@ wio.on('error', (error) => {
|
|
|
257
331
|
```javascript
|
|
258
332
|
wio.on('error', (error) => {
|
|
259
333
|
switch (error.type) {
|
|
260
|
-
case 'INVALID_ORIGIN':
|
|
261
|
-
console.error(`Invalid origin: expected ${error.expected}, got ${error.received}`)
|
|
262
|
-
break
|
|
263
|
-
case 'ORIGIN_MISMATCH':
|
|
264
|
-
console.error(`Origin mismatch: expected ${error.expected}, got ${error.received}`)
|
|
265
|
-
break
|
|
266
|
-
case 'RATE_LIMIT_EXCEEDED':
|
|
267
|
-
console.warn(`Rate limit exceeded: ${error.current}/${error.limit} messages/second`)
|
|
268
|
-
break
|
|
269
334
|
case 'MESSAGE_HANDLING_ERROR':
|
|
270
|
-
console.error(`Error handling
|
|
335
|
+
console.error(`Error handling message: ${error.error}`)
|
|
271
336
|
break
|
|
272
337
|
case 'EMIT_ERROR':
|
|
273
338
|
console.error(`Error sending event ${error.event}: ${error.error}`)
|
|
@@ -275,6 +340,9 @@ wio.on('error', (error) => {
|
|
|
275
340
|
case 'LISTENER_ERROR':
|
|
276
341
|
console.error(`Error in listener for ${error.event}: ${error.error}`)
|
|
277
342
|
break
|
|
343
|
+
case 'RATE_LIMIT_EXCEEDED':
|
|
344
|
+
console.warn(`Rate limit exceeded: ${error.current}/${error.limit} messages/second`)
|
|
345
|
+
break
|
|
278
346
|
case 'NO_CONNECTION':
|
|
279
347
|
console.error(`Attempted to send ${error.event} without connection`)
|
|
280
348
|
break
|
|
@@ -308,15 +376,15 @@ console.log(`${stats.queuedMessages} messages queued`)
|
|
|
308
376
|
- **`onceAsync(event)`** - Wait for single event (Promise)
|
|
309
377
|
|
|
310
378
|
#### Utility Methods
|
|
311
|
-
- **`getStats()`** - Get connection statistics
|
|
379
|
+
- **`getStats()`** - Get connection statistics including readiness states
|
|
312
380
|
- **`clearQueue()`** - Clear queued messages
|
|
313
381
|
- **`getInjectedJavaScript()`** - Get JavaScript to inject into WebView
|
|
314
382
|
|
|
315
383
|
#### Connection Methods
|
|
316
|
-
- **`initiate(webViewRef, origin)`** - Establish connection (WEBVIEW peer only)
|
|
317
|
-
- **`listen(hostOrigin?)`** - Listen for connection (EMBEDDED peer only)
|
|
384
|
+
- **`initiate(webViewRef, origin)`** - Establish connection with retry logic (WEBVIEW peer only)
|
|
385
|
+
- **`listen(hostOrigin?)`** - Listen for connection with readiness announcement (EMBEDDED peer only)
|
|
318
386
|
- **`handleMessage(event)`** - Handle incoming message from WebView
|
|
319
|
-
- **`disconnect(callback?)`** - Disconnect and cleanup
|
|
387
|
+
- **`disconnect(callback?)`** - Disconnect and cleanup all resources
|
|
320
388
|
- **`isConnected()`** - Check connection status
|
|
321
389
|
|
|
322
390
|
#### Messaging Methods
|
|
@@ -329,11 +397,18 @@ console.log(`${stats.queuedMessages} messages queued`)
|
|
|
329
397
|
### Events
|
|
330
398
|
|
|
331
399
|
#### Connection Events
|
|
332
|
-
- **`connect`** - Connection established
|
|
400
|
+
- **`connect`** - Connection established (after 3-way handshake)
|
|
333
401
|
- **`disconnect`** - Connection lost with reason
|
|
402
|
+
- **`connect_timeout`** - Initial connection failed after all attempts (NEW)
|
|
334
403
|
- **`reconnecting`** - Reconnection attempt started
|
|
335
404
|
- **`reconnection_failed`** - All reconnection attempts failed
|
|
336
405
|
|
|
406
|
+
#### Internal Events (handled automatically)
|
|
407
|
+
- **`__embedded_ready`** - EMBEDDED peer announces readiness
|
|
408
|
+
- **`__connection_ack`** - Final acknowledgment in 3-way handshake
|
|
409
|
+
- **`__heartbeat`** - Connection health check
|
|
410
|
+
- **`__heartbeat_response`** - Heartbeat response
|
|
411
|
+
|
|
337
412
|
#### Error Events
|
|
338
413
|
- **`error`** - Various error conditions with detailed error objects
|
|
339
414
|
|
|
@@ -341,7 +416,7 @@ console.log(`${stats.queuedMessages} messages queued`)
|
|
|
341
416
|
|
|
342
417
|
```javascript
|
|
343
418
|
import React, { useRef, useEffect, useState } from 'react'
|
|
344
|
-
import { View, TouchableOpacity, Text, StyleSheet } from 'react-native'
|
|
419
|
+
import { View, TouchableOpacity, Text, StyleSheet, ActivityIndicator } from 'react-native'
|
|
345
420
|
import { WebView } from 'react-native-webview'
|
|
346
421
|
import WIO from 'webview.io'
|
|
347
422
|
|
|
@@ -349,24 +424,41 @@ function App() {
|
|
|
349
424
|
const webViewRef = useRef(null)
|
|
350
425
|
const wioRef = useRef(null)
|
|
351
426
|
const [isConnected, setIsConnected] = useState(false)
|
|
427
|
+
const [isConnecting, setIsConnecting] = useState(false)
|
|
428
|
+
const [connectionAttempts, setConnectionAttempts] = useState(0)
|
|
352
429
|
|
|
353
430
|
useEffect(() => {
|
|
354
431
|
wioRef.current = new WIO({
|
|
355
432
|
type: 'WEBVIEW',
|
|
356
|
-
debug: true
|
|
433
|
+
debug: true,
|
|
434
|
+
connectionTimeout: 10000,
|
|
435
|
+
connectionPingInterval: 2000,
|
|
436
|
+
maxConnectionAttempts: 5
|
|
357
437
|
})
|
|
358
438
|
|
|
359
439
|
wioRef.current.initiate(webViewRef, 'https://your-app.com')
|
|
440
|
+
setIsConnecting(true)
|
|
360
441
|
|
|
361
442
|
wioRef.current
|
|
362
443
|
.on('connect', () => {
|
|
363
444
|
console.log('Connected!')
|
|
364
445
|
setIsConnected(true)
|
|
446
|
+
setIsConnecting(false)
|
|
447
|
+
setConnectionAttempts(0)
|
|
365
448
|
})
|
|
366
|
-
.on('disconnect', () => {
|
|
367
|
-
console.log('Disconnected
|
|
449
|
+
.on('disconnect', ({ reason }) => {
|
|
450
|
+
console.log('Disconnected:', reason)
|
|
368
451
|
setIsConnected(false)
|
|
369
452
|
})
|
|
453
|
+
.on('connect_timeout', ({ attempts }) => {
|
|
454
|
+
console.log(`Connection timeout after ${attempts} attempts`)
|
|
455
|
+
setIsConnecting(false)
|
|
456
|
+
setConnectionAttempts(attempts)
|
|
457
|
+
})
|
|
458
|
+
.on('reconnecting', ({ attempt, delay }) => {
|
|
459
|
+
console.log(`Reconnecting (${attempt})...`)
|
|
460
|
+
setIsConnecting(true)
|
|
461
|
+
})
|
|
370
462
|
.on('location:picked', (location) => {
|
|
371
463
|
console.log('User picked location:', location)
|
|
372
464
|
})
|
|
@@ -378,13 +470,19 @@ function App() {
|
|
|
378
470
|
|
|
379
471
|
const getLocation = async () => {
|
|
380
472
|
try {
|
|
381
|
-
const location = await wioRef.current.emitAsync('get:location')
|
|
473
|
+
const location = await wioRef.current.emitAsync('get:location', null, 5000)
|
|
382
474
|
console.log('Got location:', location)
|
|
383
475
|
} catch (error) {
|
|
384
476
|
console.error('Failed to get location:', error)
|
|
385
477
|
}
|
|
386
478
|
}
|
|
387
479
|
|
|
480
|
+
const retry = () => {
|
|
481
|
+
setConnectionAttempts(0)
|
|
482
|
+
setIsConnecting(true)
|
|
483
|
+
wioRef.current.initiate(webViewRef, 'https://your-app.com')
|
|
484
|
+
}
|
|
485
|
+
|
|
388
486
|
return (
|
|
389
487
|
<View style={styles.container}>
|
|
390
488
|
<WebView
|
|
@@ -396,10 +494,29 @@ function App() {
|
|
|
396
494
|
/>
|
|
397
495
|
|
|
398
496
|
<View style={styles.controls}>
|
|
399
|
-
<
|
|
400
|
-
|
|
401
|
-
<Text>
|
|
402
|
-
|
|
497
|
+
<View style={styles.status}>
|
|
498
|
+
{isConnecting && <ActivityIndicator />}
|
|
499
|
+
<Text>
|
|
500
|
+
Status: {isConnected ? 'Connected' : isConnecting ? 'Connecting...' : 'Disconnected'}
|
|
501
|
+
</Text>
|
|
502
|
+
{connectionAttempts > 0 && (
|
|
503
|
+
<Text style={styles.error}>
|
|
504
|
+
Failed after {connectionAttempts} attempts
|
|
505
|
+
</Text>
|
|
506
|
+
)}
|
|
507
|
+
</View>
|
|
508
|
+
|
|
509
|
+
{isConnected && (
|
|
510
|
+
<TouchableOpacity style={styles.button} onPress={getLocation}>
|
|
511
|
+
<Text>Get Location</Text>
|
|
512
|
+
</TouchableOpacity>
|
|
513
|
+
)}
|
|
514
|
+
|
|
515
|
+
{!isConnected && !isConnecting && (
|
|
516
|
+
<TouchableOpacity style={styles.button} onPress={retry}>
|
|
517
|
+
<Text>Retry Connection</Text>
|
|
518
|
+
</TouchableOpacity>
|
|
519
|
+
)}
|
|
403
520
|
</View>
|
|
404
521
|
</View>
|
|
405
522
|
)
|
|
@@ -407,7 +524,10 @@ function App() {
|
|
|
407
524
|
|
|
408
525
|
const styles = StyleSheet.create({
|
|
409
526
|
container: { flex: 1 },
|
|
410
|
-
controls: { padding: 16 }
|
|
527
|
+
controls: { padding: 16 },
|
|
528
|
+
status: { flexDirection: 'row', alignItems: 'center', gap: 8, marginBottom: 12 },
|
|
529
|
+
error: { color: 'red', marginTop: 4 },
|
|
530
|
+
button: { padding: 12, backgroundColor: '#007AFF', borderRadius: 8, alignItems: 'center' }
|
|
411
531
|
})
|
|
412
532
|
```
|
|
413
533
|
|
|
@@ -422,6 +542,9 @@ const options: Options = {
|
|
|
422
542
|
type: 'WEBVIEW',
|
|
423
543
|
debug: true,
|
|
424
544
|
heartbeatInterval: 30000,
|
|
545
|
+
connectionTimeout: 10000,
|
|
546
|
+
connectionPingInterval: 2000,
|
|
547
|
+
maxConnectionAttempts: 5,
|
|
425
548
|
maxMessageSize: 512 * 1024
|
|
426
549
|
}
|
|
427
550
|
|
|
@@ -449,8 +572,6 @@ const response = await wio.emitAsync<{ query: string }, ApiResponse>(
|
|
|
449
572
|
|
|
450
573
|
| Error Type | Description |
|
|
451
574
|
|------------|-------------|
|
|
452
|
-
| `INVALID_ORIGIN` | Message from unexpected origin |
|
|
453
|
-
| `ORIGIN_MISMATCH` | Origin changed during session |
|
|
454
575
|
| `MESSAGE_HANDLING_ERROR` | Error processing incoming message |
|
|
455
576
|
| `EMIT_ERROR` | Error sending message |
|
|
456
577
|
| `LISTENER_ERROR` | Error in event listener |
|
|
@@ -469,8 +590,55 @@ const response = await wio.emitAsync<{ query: string }, ApiResponse>(
|
|
|
469
590
|
- **Rate Limiting**: Respect the `maxMessagesPerSecond` limit (default 100/sec)
|
|
470
591
|
- **Queue Size**: Monitor queued messages to avoid memory issues
|
|
471
592
|
- **Heartbeat**: Adjust `heartbeatInterval` based on your reliability needs
|
|
593
|
+
- **Connection Timeout**: Configure `connectionTimeout` and `maxConnectionAttempts` based on network conditions
|
|
472
594
|
- **Battery Impact**: Consider disabling heartbeat or increasing interval for battery-sensitive applications
|
|
473
595
|
|
|
596
|
+
## Troubleshooting
|
|
597
|
+
|
|
598
|
+
### Connection Never Establishes
|
|
599
|
+
|
|
600
|
+
**Symptoms:** `connect_timeout` event fires, connection never succeeds
|
|
601
|
+
|
|
602
|
+
**Solutions:**
|
|
603
|
+
1. Check that `injectedJavaScript` is properly set on WebView
|
|
604
|
+
2. Verify `javaScriptEnabled={true}` is set
|
|
605
|
+
3. Check browser console for JavaScript errors in WebView
|
|
606
|
+
4. Ensure origin matches exactly (including protocol)
|
|
607
|
+
5. Increase `connectionTimeout` for slow networks
|
|
608
|
+
6. Check that WebView content loads successfully
|
|
609
|
+
|
|
610
|
+
### Messages Not Received
|
|
611
|
+
|
|
612
|
+
**Symptoms:** `emit()` called but listener never fires
|
|
613
|
+
|
|
614
|
+
**Solutions:**
|
|
615
|
+
1. Verify connection is established (`isConnected()` returns true)
|
|
616
|
+
2. Check that listener is registered before message is sent
|
|
617
|
+
3. Look for errors in `error` event listener
|
|
618
|
+
4. Check if rate limiting is being exceeded
|
|
619
|
+
5. Verify message size is under `maxMessageSize`
|
|
620
|
+
|
|
621
|
+
### Frequent Disconnections
|
|
622
|
+
|
|
623
|
+
**Symptoms:** Constant `disconnect`/`reconnect` cycle
|
|
624
|
+
|
|
625
|
+
**Solutions:**
|
|
626
|
+
1. Increase `heartbeatInterval` to reduce network overhead
|
|
627
|
+
2. Check network stability
|
|
628
|
+
3. Look for memory issues or crashes in WebView
|
|
629
|
+
4. Verify no conflicting JavaScript in WebView
|
|
630
|
+
5. Check React Native debugger for errors
|
|
631
|
+
|
|
632
|
+
### Race Conditions on Load
|
|
633
|
+
|
|
634
|
+
**Symptoms:** Sometimes connects, sometimes doesn't
|
|
635
|
+
|
|
636
|
+
**Solutions:**
|
|
637
|
+
- Already handled! The three-way handshake with readiness announcements prevents this
|
|
638
|
+
- EMBEDDED announces readiness periodically until connected
|
|
639
|
+
- WEBVIEW retries connection attempts automatically
|
|
640
|
+
- No action needed from your side
|
|
641
|
+
|
|
474
642
|
## Differences from iframe.io
|
|
475
643
|
|
|
476
644
|
`webview.io` is adapted specifically for React Native and differs from `iframe.io` in the following ways:
|
|
@@ -480,6 +648,9 @@ const response = await wio.emitAsync<{ query: string }, ApiResponse>(
|
|
|
480
648
|
- **Message Handling**: Requires explicit `handleMessage()` call in `onMessage` prop
|
|
481
649
|
- **Injected Script**: Uses `getInjectedJavaScript()` to setup bridge in WebView
|
|
482
650
|
- **No DOM Dependencies**: Works in React Native environment without DOM APIs
|
|
651
|
+
- **Enhanced Handshake**: Three-way handshake with token validation for mobile reliability
|
|
652
|
+
- **Connection Retry**: Built-in retry logic for spotty mobile connections
|
|
653
|
+
- **Readiness Protocol**: Handles race conditions common in mobile WebView loading
|
|
483
654
|
|
|
484
655
|
## License
|
|
485
656
|
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export type Options = {
|
|
|
12
12
|
maxMessagesPerSecond?: number;
|
|
13
13
|
autoReconnect?: boolean;
|
|
14
14
|
messageQueueSize?: number;
|
|
15
|
+
connectionPingInterval?: number;
|
|
16
|
+
maxConnectionAttempts?: number;
|
|
15
17
|
};
|
|
16
18
|
export interface RegisteredEvents {
|
|
17
19
|
[index: string]: Listener[];
|
|
@@ -22,6 +24,7 @@ export type Peer = {
|
|
|
22
24
|
origin?: string;
|
|
23
25
|
connected?: boolean;
|
|
24
26
|
lastHeartbeat?: number;
|
|
27
|
+
embeddedReady?: boolean;
|
|
25
28
|
};
|
|
26
29
|
export type MessageData = {
|
|
27
30
|
_event: string;
|
|
@@ -29,6 +32,7 @@ export type MessageData = {
|
|
|
29
32
|
cid: string | undefined;
|
|
30
33
|
timestamp?: number;
|
|
31
34
|
size?: number;
|
|
35
|
+
token?: string;
|
|
32
36
|
};
|
|
33
37
|
export type Message = {
|
|
34
38
|
data: MessageData;
|
|
@@ -45,10 +49,15 @@ export default class WIO {
|
|
|
45
49
|
options: Options;
|
|
46
50
|
private heartbeatTimer?;
|
|
47
51
|
private reconnectTimer?;
|
|
52
|
+
private connectionAttemptTimer?;
|
|
53
|
+
private connectionPingInterval?;
|
|
54
|
+
private embeddedReadyCheckInterval?;
|
|
48
55
|
private messageQueue;
|
|
49
56
|
private messageRateTracker;
|
|
50
57
|
private reconnectAttempts;
|
|
51
58
|
private maxReconnectAttempts;
|
|
59
|
+
private connectionToken?;
|
|
60
|
+
private connectionAttempts;
|
|
52
61
|
constructor(options?: Options);
|
|
53
62
|
debug(...args: any[]): void;
|
|
54
63
|
isConnected(): boolean;
|
|
@@ -56,6 +65,10 @@ export default class WIO {
|
|
|
56
65
|
private stopHeartbeat;
|
|
57
66
|
private handleConnectionLoss;
|
|
58
67
|
private attemptReconnection;
|
|
68
|
+
private startConnectionAttempt;
|
|
69
|
+
private stopConnectionAttempt;
|
|
70
|
+
private announceEmbeddedReady;
|
|
71
|
+
private stopEmbeddedReadyAnnouncement;
|
|
59
72
|
private checkRateLimit;
|
|
60
73
|
private queueMessage;
|
|
61
74
|
private processMessageQueue;
|
|
@@ -65,12 +78,10 @@ export default class WIO {
|
|
|
65
78
|
initiate(webViewRef: RefObject<WebView>, origin: string): this;
|
|
66
79
|
/**
|
|
67
80
|
* Listening to connection from the WebView host
|
|
68
|
-
* Note: In React Native context, this is handled by injected JavaScript
|
|
69
81
|
*/
|
|
70
82
|
listen(hostOrigin?: string): this;
|
|
71
83
|
/**
|
|
72
84
|
* Handle incoming message from WebView
|
|
73
|
-
* Called by React Native component via onMessage prop
|
|
74
85
|
*/
|
|
75
86
|
handleMessage(event: {
|
|
76
87
|
nativeEvent: {
|
|
@@ -90,11 +101,13 @@ export default class WIO {
|
|
|
90
101
|
disconnect(fn?: () => void): this;
|
|
91
102
|
getStats(): {
|
|
92
103
|
connected: boolean;
|
|
104
|
+
embeddedReady: boolean | undefined;
|
|
93
105
|
peerType: PeerType;
|
|
94
106
|
origin: string | undefined;
|
|
95
107
|
lastHeartbeat: number | undefined;
|
|
96
108
|
queuedMessages: number;
|
|
97
109
|
reconnectAttempts: number;
|
|
110
|
+
connectionAttempts: number;
|
|
98
111
|
activeListeners: number;
|
|
99
112
|
messageRate: number;
|
|
100
113
|
};
|