react-native-ble-mesh 1.1.1 → 2.0.0
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 +288 -172
- package/docs/IOS-BACKGROUND-BLE.md +231 -0
- package/docs/OPTIMIZATION.md +70 -0
- package/docs/SPEC-v2.1.md +308 -0
- package/package.json +1 -1
- package/src/MeshNetwork.js +659 -465
- package/src/constants/index.js +1 -0
- package/src/crypto/AutoCrypto.js +79 -0
- package/src/crypto/CryptoProvider.js +99 -0
- package/src/crypto/index.js +15 -63
- package/src/crypto/providers/ExpoCryptoProvider.js +125 -0
- package/src/crypto/providers/QuickCryptoProvider.js +134 -0
- package/src/crypto/providers/TweetNaClProvider.js +124 -0
- package/src/crypto/providers/index.js +11 -0
- package/src/errors/MeshError.js +2 -1
- package/src/expo/withBLEMesh.js +102 -0
- package/src/hooks/useMesh.js +30 -9
- package/src/hooks/useMessages.js +2 -0
- package/src/index.js +23 -8
- package/src/mesh/dedup/DedupManager.js +36 -10
- package/src/mesh/fragment/Assembler.js +5 -0
- package/src/mesh/index.js +1 -1
- package/src/mesh/monitor/ConnectionQuality.js +408 -0
- package/src/mesh/monitor/NetworkMonitor.js +327 -316
- package/src/mesh/monitor/index.js +7 -3
- package/src/mesh/peer/PeerManager.js +6 -1
- package/src/mesh/router/MessageRouter.js +26 -15
- package/src/mesh/router/RouteTable.js +7 -1
- package/src/mesh/store/StoreAndForwardManager.js +295 -297
- package/src/mesh/store/index.js +1 -1
- package/src/service/BatteryOptimizer.js +282 -278
- package/src/service/EmergencyManager.js +224 -214
- package/src/service/HandshakeManager.js +167 -13
- package/src/service/MeshService.js +72 -6
- package/src/service/SessionManager.js +77 -2
- package/src/service/audio/AudioManager.js +8 -2
- package/src/service/file/FileAssembler.js +106 -0
- package/src/service/file/FileChunker.js +79 -0
- package/src/service/file/FileManager.js +307 -0
- package/src/service/file/FileMessage.js +122 -0
- package/src/service/file/index.js +15 -0
- package/src/service/text/broadcast/BroadcastManager.js +16 -0
- package/src/transport/BLETransport.js +131 -9
- package/src/transport/MockTransport.js +1 -1
- package/src/transport/MultiTransport.js +305 -0
- package/src/transport/WiFiDirectTransport.js +295 -0
- package/src/transport/adapters/NodeBLEAdapter.js +34 -0
- package/src/transport/adapters/RNBLEAdapter.js +56 -1
- package/src/transport/index.js +6 -0
- package/src/utils/compression.js +291 -291
- package/src/crypto/aead.js +0 -189
- package/src/crypto/chacha20.js +0 -181
- package/src/crypto/hkdf.js +0 -187
- package/src/crypto/hmac.js +0 -143
- package/src/crypto/keys/KeyManager.js +0 -271
- package/src/crypto/keys/KeyPair.js +0 -216
- package/src/crypto/keys/SecureStorage.js +0 -219
- package/src/crypto/keys/index.js +0 -32
- package/src/crypto/noise/handshake.js +0 -410
- package/src/crypto/noise/index.js +0 -27
- package/src/crypto/noise/session.js +0 -253
- package/src/crypto/noise/state.js +0 -268
- package/src/crypto/poly1305.js +0 -113
- package/src/crypto/sha256.js +0 -240
- package/src/crypto/x25519.js +0 -154
package/README.md
CHANGED
|
@@ -7,14 +7,15 @@
|
|
|
7
7
|
[](https://opensource.org/licenses/MIT)
|
|
8
8
|
[](https://www.typescriptlang.org/)
|
|
9
9
|
[](https://reactnative.dev/)
|
|
10
|
+
[]()
|
|
10
11
|
|
|
11
12
|
---
|
|
12
13
|
|
|
13
14
|
## What is this?
|
|
14
15
|
|
|
15
|
-
Imagine you're at a concert, camping trip, or during a power outage
|
|
16
|
+
Imagine you're at a concert, camping trip, or during a power outage — **no WiFi, no cell service**. How do you text your friends?
|
|
16
17
|
|
|
17
|
-
**This library lets phones talk to each other using Bluetooth!** Messages hop from phone to phone until they reach your friend
|
|
18
|
+
**This library lets phones talk to each other using Bluetooth!** Messages hop from phone to phone until they reach your friend — even if they're far away.
|
|
18
19
|
|
|
19
20
|
```
|
|
20
21
|
You Friend's Your
|
|
@@ -22,7 +23,7 @@ Imagine you're at a concert, camping trip, or during a power outage - **no WiFi,
|
|
|
22
23
|
Phone (300m away!)
|
|
23
24
|
```
|
|
24
25
|
|
|
25
|
-
**Think of it like a game of telephone, but for text messages!**
|
|
26
|
+
**Think of it like a game of telephone, but for text messages and photos!**
|
|
26
27
|
|
|
27
28
|
---
|
|
28
29
|
|
|
@@ -56,9 +57,13 @@ mesh.on('messageReceived', (msg) => {
|
|
|
56
57
|
|---------|--------------|
|
|
57
58
|
| No WiFi or cell service | Works with just Bluetooth! |
|
|
58
59
|
| Friend is too far away | Messages hop through other phones |
|
|
59
|
-
|
|
|
60
|
+
| Need to send photos? | Send files & images up to 10MB! |
|
|
61
|
+
| Worried about privacy? | Encrypted with battle-tested crypto |
|
|
60
62
|
| Phone battery dying? | Smart power saving built-in |
|
|
61
63
|
| Need to delete everything fast? | One-tap emergency wipe |
|
|
64
|
+
| Using Expo? | Works out of the box! |
|
|
65
|
+
| Need faster transfers? | Wi-Fi Direct for big files |
|
|
66
|
+
| How's my connection? | Real-time signal quality indicator |
|
|
62
67
|
|
|
63
68
|
---
|
|
64
69
|
|
|
@@ -67,8 +72,84 @@ mesh.on('messageReceived', (msg) => {
|
|
|
67
72
|
### 📡 Messages That Hop
|
|
68
73
|
Your message can jump through **up to 7 phones** to reach someone far away. If Alice can't reach Dave directly, the message goes: Alice → Bob → Carol → Dave!
|
|
69
74
|
|
|
75
|
+
### 📸 Send Photos & Files
|
|
76
|
+
Send pictures, documents, or any file up to 10MB. The library chops it into tiny pieces, sends them through the mesh, and puts them back together on the other side. You get a progress bar too!
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
// Send a photo to a friend
|
|
80
|
+
await mesh.sendFile('friend-id', {
|
|
81
|
+
data: photoBytes, // The file as bytes
|
|
82
|
+
name: 'vacation.jpg', // File name
|
|
83
|
+
mimeType: 'image/jpeg', // What kind of file
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Watch the progress
|
|
87
|
+
mesh.on('fileSendProgress', ({ name, percent }) => {
|
|
88
|
+
console.log(`Sending ${name}: ${percent}%`);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Receive files from others
|
|
92
|
+
mesh.on('fileReceived', ({ from, file }) => {
|
|
93
|
+
console.log(`Got ${file.name} from ${from}!`);
|
|
94
|
+
// file.data has the bytes, file.mimeType tells you the type
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 📶 Connection Quality
|
|
99
|
+
See how good your connection is to each person — like signal bars on your phone!
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
const quality = mesh.getConnectionQuality('friend-id');
|
|
103
|
+
// quality.level = 'excellent' | 'good' | 'fair' | 'poor'
|
|
104
|
+
// quality.rssi = -55 (signal strength)
|
|
105
|
+
// quality.latencyMs = 45 (how fast, in milliseconds)
|
|
106
|
+
|
|
107
|
+
// Get alerted when connection changes
|
|
108
|
+
mesh.on('connectionQualityChanged', ({ peerId, level }) => {
|
|
109
|
+
if (level === 'poor') {
|
|
110
|
+
console.log('Connection getting weak! Move closer.');
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 📡 Wi-Fi Direct for Big Files
|
|
116
|
+
Bluetooth is great for messages, but slow for big files. Wi-Fi Direct is **250x faster**! The library automatically picks the best one:
|
|
117
|
+
|
|
118
|
+
- **Small message?** → Sends via Bluetooth (reliable, low power)
|
|
119
|
+
- **Big photo?** → Sends via Wi-Fi Direct (super fast)
|
|
120
|
+
- **Wi-Fi Direct not available?** → Falls back to Bluetooth automatically
|
|
121
|
+
|
|
122
|
+
```javascript
|
|
123
|
+
import { MultiTransport } from 'react-native-ble-mesh';
|
|
124
|
+
|
|
125
|
+
// Use both Bluetooth AND Wi-Fi Direct together
|
|
126
|
+
const transport = new MultiTransport({
|
|
127
|
+
bleTransport: myBleTransport,
|
|
128
|
+
wifiTransport: myWifiTransport,
|
|
129
|
+
strategy: 'auto', // Let the library decide
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const mesh = new MeshNetwork({ nickname: 'Alex' });
|
|
133
|
+
await mesh.start(transport);
|
|
134
|
+
// That's it! The library handles everything.
|
|
135
|
+
```
|
|
136
|
+
|
|
70
137
|
### 🔒 Secret Messages
|
|
71
|
-
|
|
138
|
+
Pick the encryption that works best for your app. The library auto-detects the fastest option:
|
|
139
|
+
|
|
140
|
+
| Option | Speed | Works On |
|
|
141
|
+
|--------|-------|----------|
|
|
142
|
+
| `react-native-quick-crypto` | ⚡ Blazing fast | React Native |
|
|
143
|
+
| `expo-crypto` + `tweetnacl` | 🚀 Fast | Expo apps |
|
|
144
|
+
| `tweetnacl` | ✅ Good | Everywhere |
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
// The library picks the best one automatically!
|
|
148
|
+
const mesh = new MeshNetwork({
|
|
149
|
+
nickname: 'Alex',
|
|
150
|
+
crypto: 'auto', // Auto-detect fastest available
|
|
151
|
+
});
|
|
152
|
+
```
|
|
72
153
|
|
|
73
154
|
### 📬 Offline Delivery
|
|
74
155
|
Friend's phone turned off? No problem! Your message waits and delivers when they come back online.
|
|
@@ -78,6 +159,7 @@ Choose how much battery to use:
|
|
|
78
159
|
- **High Power** = Faster messages, more battery
|
|
79
160
|
- **Balanced** = Good speed, normal battery (default)
|
|
80
161
|
- **Low Power** = Slower messages, saves battery
|
|
162
|
+
- **Auto** = Let the phone decide based on battery level!
|
|
81
163
|
|
|
82
164
|
### 🚨 Panic Button
|
|
83
165
|
Triple-tap to instantly delete all messages and data. Everything gone in less than 0.2 seconds!
|
|
@@ -89,20 +171,46 @@ Create chat rooms like `#camping-trip` or `#concert-squad`. Only people who join
|
|
|
89
171
|
|
|
90
172
|
## Installation
|
|
91
173
|
|
|
92
|
-
###
|
|
174
|
+
### Option A: Expo Projects (Easiest!) 🎯
|
|
93
175
|
|
|
94
176
|
```bash
|
|
95
|
-
|
|
177
|
+
npx expo install react-native-ble-mesh react-native-ble-plx react-native-get-random-values
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Add the plugin to your `app.json`:
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
{
|
|
184
|
+
"expo": {
|
|
185
|
+
"plugins": [
|
|
186
|
+
["react-native-ble-mesh", {
|
|
187
|
+
"bluetoothAlwaysPermission": "Chat with nearby friends using Bluetooth"
|
|
188
|
+
}]
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
}
|
|
96
192
|
```
|
|
97
193
|
|
|
98
|
-
|
|
194
|
+
**That's it! The plugin handles all the permissions for you.** ✅
|
|
99
195
|
|
|
196
|
+
Then build your dev client:
|
|
100
197
|
```bash
|
|
101
|
-
|
|
198
|
+
npx expo prebuild
|
|
199
|
+
npx expo run:ios # or run:android
|
|
102
200
|
```
|
|
103
201
|
|
|
104
|
-
|
|
202
|
+
### Option B: Bare React Native
|
|
105
203
|
|
|
204
|
+
```bash
|
|
205
|
+
npm install react-native-ble-mesh react-native-ble-plx react-native-get-random-values
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**iOS Setup:**
|
|
209
|
+
```bash
|
|
210
|
+
cd ios && pod install && cd ..
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Add to `ios/YourApp/Info.plist`:
|
|
106
214
|
```xml
|
|
107
215
|
<key>NSBluetoothAlwaysUsageDescription</key>
|
|
108
216
|
<string>Chat with nearby friends using Bluetooth</string>
|
|
@@ -115,28 +223,31 @@ Add these lines to your `ios/YourApp/Info.plist`:
|
|
|
115
223
|
</array>
|
|
116
224
|
```
|
|
117
225
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
Add these lines to `android/app/src/main/AndroidManifest.xml`:
|
|
121
|
-
|
|
226
|
+
**Android Setup:** Add to `android/app/src/main/AndroidManifest.xml`:
|
|
122
227
|
```xml
|
|
123
|
-
<uses-permission android:name="android.permission.BLUETOOTH" />
|
|
124
|
-
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
|
125
228
|
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
|
126
229
|
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
|
127
230
|
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
|
128
231
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
|
129
232
|
```
|
|
130
233
|
|
|
131
|
-
### Step
|
|
234
|
+
### Final Step (Both Options)
|
|
235
|
+
|
|
236
|
+
Add this as the **very first line** in your app:
|
|
132
237
|
|
|
133
238
|
```javascript
|
|
134
|
-
// This MUST be the very first line in index.js or App.js
|
|
135
239
|
import 'react-native-get-random-values';
|
|
240
|
+
```
|
|
136
241
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
242
|
+
### Optional: Extra Speed & Features
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
# Want encryption? Pick one:
|
|
246
|
+
npm install tweetnacl # Works everywhere
|
|
247
|
+
npm install react-native-quick-crypto # Fastest (native)
|
|
248
|
+
|
|
249
|
+
# Want Wi-Fi Direct for big file transfers?
|
|
250
|
+
npm install react-native-wifi-p2p
|
|
140
251
|
```
|
|
141
252
|
|
|
142
253
|
---
|
|
@@ -148,7 +259,6 @@ import { AppRegistry } from 'react-native';
|
|
|
148
259
|
```javascript
|
|
149
260
|
import { MeshNetwork } from 'react-native-ble-mesh';
|
|
150
261
|
|
|
151
|
-
// Create and start
|
|
152
262
|
const mesh = new MeshNetwork({ nickname: 'YourName' });
|
|
153
263
|
await mesh.start();
|
|
154
264
|
|
|
@@ -156,93 +266,96 @@ await mesh.start();
|
|
|
156
266
|
await mesh.broadcast('Hi everyone!');
|
|
157
267
|
|
|
158
268
|
// Send private message to one person
|
|
159
|
-
await mesh.sendDirect('friend-id
|
|
269
|
+
await mesh.sendDirect('friend-id', 'Hey, just for you!');
|
|
160
270
|
|
|
161
271
|
// Receive messages
|
|
162
272
|
mesh.on('messageReceived', ({ from, text }) => {
|
|
163
273
|
console.log(`${from}: ${text}`);
|
|
164
274
|
});
|
|
165
275
|
|
|
166
|
-
// When done
|
|
167
276
|
await mesh.stop();
|
|
168
277
|
```
|
|
169
278
|
|
|
170
|
-
### Example 2:
|
|
279
|
+
### Example 2: Send a Photo
|
|
171
280
|
|
|
172
281
|
```javascript
|
|
173
|
-
//
|
|
174
|
-
await mesh.
|
|
282
|
+
// Send a photo
|
|
283
|
+
await mesh.sendFile('friend-id', {
|
|
284
|
+
data: imageBytes,
|
|
285
|
+
name: 'selfie.jpg',
|
|
286
|
+
mimeType: 'image/jpeg',
|
|
287
|
+
});
|
|
175
288
|
|
|
176
|
-
//
|
|
177
|
-
|
|
289
|
+
// Track sending progress
|
|
290
|
+
mesh.on('fileSendProgress', ({ percent }) => {
|
|
291
|
+
console.log(`${percent}% sent`);
|
|
292
|
+
});
|
|
178
293
|
|
|
179
|
-
//
|
|
294
|
+
// Receive photos
|
|
295
|
+
mesh.on('fileReceived', ({ from, file }) => {
|
|
296
|
+
console.log(`Got ${file.name} (${file.size} bytes) from ${from}`);
|
|
297
|
+
// file.data = the photo bytes
|
|
298
|
+
// file.mimeType = 'image/jpeg'
|
|
299
|
+
});
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Example 3: Group Channels
|
|
303
|
+
|
|
304
|
+
```javascript
|
|
305
|
+
await mesh.joinChannel('#road-trip');
|
|
306
|
+
await mesh.sendToChannel('#road-trip', 'Are we there yet?');
|
|
180
307
|
await mesh.leaveChannel('#road-trip');
|
|
181
308
|
```
|
|
182
309
|
|
|
183
|
-
### Example
|
|
310
|
+
### Example 4: Check Connection Quality
|
|
184
311
|
|
|
185
312
|
```javascript
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
313
|
+
// How's my connection to a friend?
|
|
314
|
+
const quality = mesh.getConnectionQuality('friend-id');
|
|
315
|
+
console.log(`Signal: ${quality.level}`); // excellent, good, fair, poor
|
|
316
|
+
console.log(`Speed: ${quality.latencyMs}ms`);
|
|
317
|
+
|
|
318
|
+
// Check everyone at once
|
|
319
|
+
const all = mesh.getAllConnectionQuality();
|
|
320
|
+
all.forEach(q => {
|
|
321
|
+
console.log(`${q.peerId}: ${q.level} (${q.transport})`);
|
|
189
322
|
});
|
|
323
|
+
```
|
|
190
324
|
|
|
191
|
-
|
|
325
|
+
### Example 5: Save Battery
|
|
326
|
+
|
|
327
|
+
```javascript
|
|
192
328
|
const mesh = new MeshNetwork({
|
|
193
329
|
nickname: 'Smart',
|
|
194
|
-
batteryMode: 'auto', // Adjusts
|
|
330
|
+
batteryMode: 'auto', // Adjusts based on your battery level!
|
|
195
331
|
});
|
|
196
332
|
```
|
|
197
333
|
|
|
198
|
-
### Example
|
|
334
|
+
### Example 6: Emergency Delete
|
|
199
335
|
|
|
200
336
|
```javascript
|
|
201
|
-
|
|
202
|
-
mesh.enablePanicMode({
|
|
203
|
-
trigger: 'triple_tap', // Triple tap to wipe
|
|
204
|
-
});
|
|
337
|
+
mesh.enablePanicMode({ trigger: 'triple_tap' });
|
|
205
338
|
|
|
206
|
-
// Or wipe everything
|
|
339
|
+
// Or wipe everything right now
|
|
207
340
|
await mesh.wipeAllData();
|
|
208
341
|
// All messages, keys, and data = GONE! 💨
|
|
209
342
|
```
|
|
210
343
|
|
|
211
|
-
### Example 5: Check Network Health
|
|
212
|
-
|
|
213
|
-
```javascript
|
|
214
|
-
const health = mesh.getNetworkHealth();
|
|
215
|
-
|
|
216
|
-
console.log(`Connected to ${health.activeNodes} people`);
|
|
217
|
-
console.log(`Network status: ${health.overallHealth}`); // 'good', 'fair', or 'poor'
|
|
218
|
-
```
|
|
219
|
-
|
|
220
344
|
---
|
|
221
345
|
|
|
222
346
|
## Using React Hooks
|
|
223
347
|
|
|
224
|
-
If you're using React, we have easy hooks!
|
|
225
|
-
|
|
226
348
|
```javascript
|
|
227
|
-
import React, { useEffect } from 'react';
|
|
228
|
-
import { View, Text, Button } from 'react-native';
|
|
229
349
|
import { useMesh, useMessages, usePeers } from 'react-native-ble-mesh/hooks';
|
|
230
350
|
import { BLETransport } from 'react-native-ble-mesh';
|
|
231
351
|
|
|
232
352
|
function ChatScreen() {
|
|
233
|
-
// Manage mesh lifecycle
|
|
234
353
|
const { mesh, state, initialize, destroy } = useMesh({ displayName: 'Alex' });
|
|
235
|
-
|
|
236
|
-
// Message handling (pass mesh instance)
|
|
237
354
|
const { messages, sendBroadcast } = useMessages(mesh);
|
|
238
|
-
|
|
239
|
-
// Peer tracking (pass mesh instance)
|
|
240
355
|
const { peers, connectedCount } = usePeers(mesh);
|
|
241
356
|
|
|
242
|
-
// Start mesh on mount
|
|
243
357
|
useEffect(() => {
|
|
244
|
-
|
|
245
|
-
initialize(transport);
|
|
358
|
+
initialize(new BLETransport());
|
|
246
359
|
return () => destroy();
|
|
247
360
|
}, []);
|
|
248
361
|
|
|
@@ -251,22 +364,18 @@ function ChatScreen() {
|
|
|
251
364
|
return (
|
|
252
365
|
<View>
|
|
253
366
|
<Text>Connected to {connectedCount} people</Text>
|
|
254
|
-
|
|
255
367
|
{messages.map(msg => (
|
|
256
368
|
<Text key={msg.id}>{msg.senderId}: {msg.content}</Text>
|
|
257
369
|
))}
|
|
258
|
-
|
|
259
370
|
<Button title="Say Hi!" onPress={() => sendBroadcast('Hello!')} />
|
|
260
371
|
</View>
|
|
261
372
|
);
|
|
262
373
|
}
|
|
263
374
|
```
|
|
264
375
|
|
|
265
|
-
> **Note:** The hooks (`useMesh`, `useMessages`, `usePeers`) work with the lower-level `MeshService`. For simpler usage, use the `MeshNetwork` class directly as shown in the Quick Start examples above.
|
|
266
|
-
|
|
267
376
|
---
|
|
268
377
|
|
|
269
|
-
##
|
|
378
|
+
## Everything You Can Do
|
|
270
379
|
|
|
271
380
|
### Starting & Stopping
|
|
272
381
|
|
|
@@ -274,40 +383,49 @@ function ChatScreen() {
|
|
|
274
383
|
|--------|--------------|
|
|
275
384
|
| `mesh.start()` | Turn on the mesh network |
|
|
276
385
|
| `mesh.stop()` | Turn it off (can restart later) |
|
|
277
|
-
| `mesh.destroy()` | Completely shut down
|
|
386
|
+
| `mesh.destroy()` | Completely shut down |
|
|
278
387
|
|
|
279
388
|
### Sending Messages
|
|
280
389
|
|
|
281
390
|
| Method | What It Does |
|
|
282
391
|
|--------|--------------|
|
|
283
392
|
| `mesh.broadcast('Hi!')` | Send to everyone nearby |
|
|
284
|
-
| `mesh.sendDirect(id, 'Hey')` |
|
|
285
|
-
| `mesh.sendToChannel('#fun', 'Yo')` | Send to a group
|
|
393
|
+
| `mesh.sendDirect(id, 'Hey')` | Private message to one person |
|
|
394
|
+
| `mesh.sendToChannel('#fun', 'Yo')` | Send to a group |
|
|
286
395
|
|
|
287
|
-
###
|
|
396
|
+
### Sending Files
|
|
288
397
|
|
|
289
398
|
| Method | What It Does |
|
|
290
399
|
|--------|--------------|
|
|
291
|
-
| `mesh.
|
|
292
|
-
| `mesh.
|
|
293
|
-
| `mesh.
|
|
400
|
+
| `mesh.sendFile(id, { data, name, mimeType })` | Send a file to someone |
|
|
401
|
+
| `mesh.getActiveTransfers()` | See files being sent/received |
|
|
402
|
+
| `mesh.cancelTransfer(id)` | Cancel a file transfer |
|
|
294
403
|
|
|
295
|
-
###
|
|
404
|
+
### Connection Quality
|
|
296
405
|
|
|
297
406
|
| Method | What It Does |
|
|
298
407
|
|--------|--------------|
|
|
299
|
-
| `mesh.
|
|
300
|
-
| `mesh.
|
|
301
|
-
| `mesh.unblockPeer(id)` | Unblock someone |
|
|
408
|
+
| `mesh.getConnectionQuality(id)` | Signal quality for one person |
|
|
409
|
+
| `mesh.getAllConnectionQuality()` | Signal quality for everyone |
|
|
302
410
|
|
|
303
|
-
###
|
|
411
|
+
### Channels (Group Chats)
|
|
304
412
|
|
|
305
413
|
| Method | What It Does |
|
|
306
414
|
|--------|--------------|
|
|
307
|
-
| `mesh.
|
|
308
|
-
| `mesh.
|
|
415
|
+
| `mesh.joinChannel('#name')` | Join a group |
|
|
416
|
+
| `mesh.leaveChannel('#name')` | Leave a group |
|
|
417
|
+
| `mesh.getChannels()` | See your groups |
|
|
418
|
+
|
|
419
|
+
### People
|
|
420
|
+
|
|
421
|
+
| Method | What It Does |
|
|
422
|
+
|--------|--------------|
|
|
423
|
+
| `mesh.getPeers()` | See everyone nearby |
|
|
424
|
+
| `mesh.getConnectedPeers()` | See who's connected |
|
|
425
|
+
| `mesh.blockPeer(id)` | Block someone |
|
|
426
|
+
| `mesh.unblockPeer(id)` | Unblock someone |
|
|
309
427
|
|
|
310
|
-
### Safety
|
|
428
|
+
### Safety
|
|
311
429
|
|
|
312
430
|
| Method | What It Does |
|
|
313
431
|
|--------|--------------|
|
|
@@ -318,61 +436,48 @@ function ChatScreen() {
|
|
|
318
436
|
|
|
319
437
|
| Method | What It Does |
|
|
320
438
|
|--------|--------------|
|
|
321
|
-
| `mesh.getStatus()` |
|
|
322
|
-
| `mesh.getNetworkHealth()` |
|
|
323
|
-
| `mesh.getBatteryMode()` |
|
|
439
|
+
| `mesh.getStatus()` | Current status |
|
|
440
|
+
| `mesh.getNetworkHealth()` | How good is the network? |
|
|
441
|
+
| `mesh.getBatteryMode()` | Current battery mode |
|
|
324
442
|
| `mesh.setBatteryMode('low')` | Change battery mode |
|
|
325
443
|
|
|
326
444
|
---
|
|
327
445
|
|
|
328
446
|
## Events (When Things Happen)
|
|
329
447
|
|
|
330
|
-
Listen for these events:
|
|
331
|
-
|
|
332
448
|
```javascript
|
|
333
|
-
//
|
|
334
|
-
mesh.on('
|
|
335
|
-
mesh.on('
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
mesh.on('
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
// Message was delivered successfully
|
|
347
|
-
mesh.on('messageDelivered', ({ messageId, peerId }) => { });
|
|
348
|
-
|
|
349
|
-
// Found a new person nearby
|
|
449
|
+
// Messages
|
|
450
|
+
mesh.on('messageReceived', ({ from, text, type }) => { });
|
|
451
|
+
mesh.on('directMessage', ({ from, text }) => { });
|
|
452
|
+
mesh.on('channelMessage', ({ channel, from, text }) => { });
|
|
453
|
+
mesh.on('messageDelivered', ({ messageId }) => { });
|
|
454
|
+
|
|
455
|
+
// Files
|
|
456
|
+
mesh.on('fileReceived', ({ from, file }) => { });
|
|
457
|
+
mesh.on('fileSendProgress', ({ name, percent }) => { });
|
|
458
|
+
mesh.on('fileReceiveProgress', ({ name, percent }) => { });
|
|
459
|
+
mesh.on('fileTransferFailed', ({ transferId, reason }) => { });
|
|
460
|
+
|
|
461
|
+
// People
|
|
350
462
|
mesh.on('peerDiscovered', (peer) => { });
|
|
351
|
-
|
|
352
|
-
// Connected to someone
|
|
353
463
|
mesh.on('peerConnected', (peer) => { });
|
|
354
|
-
|
|
355
|
-
// Someone left
|
|
356
464
|
mesh.on('peerDisconnected', (peer) => { });
|
|
357
465
|
|
|
358
|
-
//
|
|
359
|
-
mesh.on('
|
|
360
|
-
mesh.on('channelLeft', ({ channel }) => { });
|
|
466
|
+
// Connection Quality
|
|
467
|
+
mesh.on('connectionQualityChanged', ({ peerId, level, score }) => { });
|
|
361
468
|
|
|
362
|
-
// Network
|
|
363
|
-
mesh.on('
|
|
469
|
+
// Network
|
|
470
|
+
mesh.on('started', () => { });
|
|
471
|
+
mesh.on('stopped', () => { });
|
|
472
|
+
mesh.on('networkHealthChanged', (info) => { });
|
|
473
|
+
mesh.on('error', (error) => { });
|
|
364
474
|
|
|
365
|
-
//
|
|
475
|
+
// Offline delivery
|
|
366
476
|
mesh.on('messageCached', ({ peerId, text }) => { });
|
|
367
|
-
|
|
368
|
-
// Cached messages delivered when peer came online
|
|
369
477
|
mesh.on('cachedMessagesDelivered', ({ peerId, delivered }) => { });
|
|
370
478
|
|
|
371
|
-
//
|
|
479
|
+
// Safety
|
|
372
480
|
mesh.on('dataWiped', (result) => { });
|
|
373
|
-
|
|
374
|
-
// Something went wrong
|
|
375
|
-
mesh.on('error', (error) => { });
|
|
376
481
|
```
|
|
377
482
|
|
|
378
483
|
---
|
|
@@ -381,45 +486,60 @@ mesh.on('error', (error) => { });
|
|
|
381
486
|
|
|
382
487
|
**Very secure!** Here's what protects your messages:
|
|
383
488
|
|
|
384
|
-
| Feature | What It Means |
|
|
385
|
-
|
|
386
|
-
| **
|
|
387
|
-
| **
|
|
489
|
+
| Feature | What It Means (in Simple Words) |
|
|
490
|
+
|---------|-------------------------------|
|
|
491
|
+
| **Pluggable Encryption** | Choose the strongest lock for your messages |
|
|
492
|
+
| **Key Exchange** | Phones secretly agree on a password that nobody else knows |
|
|
388
493
|
| **Forward Secrecy** | Even if someone steals your keys later, old messages stay secret |
|
|
389
|
-
| **No Permanent IDs** | You
|
|
494
|
+
| **No Permanent IDs** | You can't be tracked — you're just "a phone" |
|
|
495
|
+
| **Panic Wipe** | One tap and everything disappears forever |
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
## iOS Background Mode
|
|
500
|
+
|
|
501
|
+
Want the mesh to keep working when the app is in the background? We've got you covered.
|
|
502
|
+
|
|
503
|
+
**Short version:** Add `bluetooth-central` and `bluetooth-peripheral` to your background modes (the Expo plugin does this automatically).
|
|
504
|
+
|
|
505
|
+
**Detailed version:** See our [iOS Background BLE Guide](docs/IOS-BACKGROUND-BLE.md) — covers all the limitations, workarounds, and known bugs.
|
|
390
506
|
|
|
391
507
|
---
|
|
392
508
|
|
|
393
509
|
## Frequently Asked Questions
|
|
394
510
|
|
|
395
|
-
|
|
396
|
-
|
|
511
|
+
**How far can messages travel?**
|
|
512
|
+
One hop: ~30 meters (100 feet). With 7 hops through other phones: 300+ meters!
|
|
397
513
|
|
|
398
|
-
|
|
514
|
+
**Does it work if Bluetooth is off?**
|
|
399
515
|
No, Bluetooth must be on. But you don't need WiFi or cell service!
|
|
400
516
|
|
|
401
|
-
|
|
402
|
-
|
|
517
|
+
**Can someone read my private messages?**
|
|
518
|
+
Nope! They're encrypted. Only you and your friend have the keys.
|
|
519
|
+
|
|
520
|
+
**How big of a file can I send?**
|
|
521
|
+
Up to 10MB by default (configurable). Big files automatically use Wi-Fi Direct if available.
|
|
403
522
|
|
|
404
|
-
|
|
405
|
-
|
|
523
|
+
**Does it work with Expo?**
|
|
524
|
+
Yes! Just add the plugin to `app.json` and build a dev client.
|
|
406
525
|
|
|
407
|
-
|
|
408
|
-
It uses some battery (Bluetooth is on), but
|
|
526
|
+
**Does it drain my battery?**
|
|
527
|
+
It uses some battery (Bluetooth is on), but use `batteryMode: 'auto'` and the library manages it for you.
|
|
409
528
|
|
|
410
|
-
|
|
411
|
-
On iOS, it works with some limitations. On Android, it works fully
|
|
529
|
+
**Does it work in the background?**
|
|
530
|
+
On iOS, it works with some limitations (scanning is slower). On Android, it works fully. See [iOS Background BLE Guide](docs/IOS-BACKGROUND-BLE.md).
|
|
412
531
|
|
|
413
532
|
---
|
|
414
533
|
|
|
415
534
|
## Use Cases
|
|
416
535
|
|
|
417
|
-
- **Concerts & Festivals**
|
|
418
|
-
- **Camping & Hiking**
|
|
419
|
-
- **Emergencies**
|
|
420
|
-
- **Protests & Events**
|
|
421
|
-
- **Gaming**
|
|
422
|
-
- **Schools**
|
|
536
|
+
- 🎵 **Concerts & Festivals** — Text friends when cell towers are overloaded
|
|
537
|
+
- ⛺ **Camping & Hiking** — Stay connected in the wilderness
|
|
538
|
+
- 🆘 **Emergencies** — Communicate during power outages or disasters
|
|
539
|
+
- ✊ **Protests & Events** — When networks are restricted
|
|
540
|
+
- 🎮 **Gaming** — Local multiplayer without internet
|
|
541
|
+
- 🏫 **Schools** — Classroom activities without WiFi
|
|
542
|
+
- 📸 **Photo Sharing** — Share pictures at events without data
|
|
423
543
|
|
|
424
544
|
---
|
|
425
545
|
|
|
@@ -428,36 +548,39 @@ On iOS, it works with some limitations. On Android, it works fully in the backgr
|
|
|
428
548
|
```
|
|
429
549
|
react-native-ble-mesh/
|
|
430
550
|
├── src/
|
|
431
|
-
│ ├── index.js
|
|
432
|
-
│ ├── MeshNetwork.js
|
|
433
|
-
│ ├── crypto/
|
|
434
|
-
│ ├── mesh/
|
|
435
|
-
│ ├── transport/
|
|
436
|
-
│
|
|
437
|
-
├──
|
|
438
|
-
└──
|
|
551
|
+
│ ├── index.js # Main entry point
|
|
552
|
+
│ ├── MeshNetwork.js # High-level API (start here!)
|
|
553
|
+
│ ├── crypto/ # Pluggable encryption providers
|
|
554
|
+
│ ├── mesh/ # Routing, dedup, connection quality
|
|
555
|
+
│ ├── transport/ # BLE + Wi-Fi Direct + MultiTransport
|
|
556
|
+
│ ├── service/ # Messaging, files, audio, battery, panic
|
|
557
|
+
│ ├── expo/ # Expo config plugin
|
|
558
|
+
│ └── hooks/ # React hooks
|
|
559
|
+
├── docs/ # Guides & specs
|
|
560
|
+
├── app.plugin.js # Expo plugin entry
|
|
561
|
+
└── __tests__/ # 432 tests, 0 failures ✅
|
|
439
562
|
```
|
|
440
563
|
|
|
441
564
|
---
|
|
442
565
|
|
|
443
566
|
## More Documentation
|
|
444
567
|
|
|
445
|
-
- [Full API Reference](docs/API.md)
|
|
446
|
-
- [React Native Guide](docs/REACT_NATIVE.md)
|
|
447
|
-
- [
|
|
448
|
-
- [
|
|
449
|
-
- [
|
|
568
|
+
- [Full API Reference](docs/API.md) — Every method explained
|
|
569
|
+
- [React Native Guide](docs/REACT_NATIVE.md) — Platform-specific setup
|
|
570
|
+
- [iOS Background BLE](docs/IOS-BACKGROUND-BLE.md) — Background mode guide
|
|
571
|
+
- [Security Details](docs/SECURITY.md) — How encryption works
|
|
572
|
+
- [Protocol Spec](docs/PROTOCOL.md) — Technical wire format
|
|
573
|
+
- [Optimization Notes](docs/OPTIMIZATION.md) — Performance details
|
|
574
|
+
- [v2.1 Feature Spec](docs/SPEC-v2.1.md) — Architecture decisions
|
|
575
|
+
- [AI/Agent Instructions](docs/prompt-instructions.md) — For AI assistants
|
|
450
576
|
|
|
451
577
|
---
|
|
452
578
|
|
|
453
579
|
## Testing
|
|
454
580
|
|
|
455
581
|
```bash
|
|
456
|
-
# Run all tests
|
|
457
|
-
npm test
|
|
458
|
-
|
|
459
|
-
# Run with coverage report
|
|
460
|
-
npm run test:coverage
|
|
582
|
+
npm test # Run all 432 tests
|
|
583
|
+
npm run test:coverage # With coverage report
|
|
461
584
|
```
|
|
462
585
|
|
|
463
586
|
---
|
|
@@ -476,24 +599,17 @@ We love contributions! Here's how:
|
|
|
476
599
|
|
|
477
600
|
## Credits
|
|
478
601
|
|
|
479
|
-
Inspired by [BitChat](https://github.com/nicegram/nicegram-bitchat)
|
|
602
|
+
Inspired by [BitChat](https://github.com/nicegram/nicegram-bitchat) — the original decentralized mesh chat.
|
|
480
603
|
|
|
481
604
|
Built with:
|
|
482
|
-
- [react-native-ble-plx](https://github.com/Polidea/react-native-ble-plx)
|
|
483
|
-
- [
|
|
605
|
+
- [react-native-ble-plx](https://github.com/Polidea/react-native-ble-plx) — Bluetooth Low Energy
|
|
606
|
+
- [tweetnacl](https://tweetnacl.js.org/) — Encryption
|
|
484
607
|
|
|
485
608
|
---
|
|
486
609
|
|
|
487
610
|
## License
|
|
488
611
|
|
|
489
|
-
MIT License
|
|
490
|
-
|
|
491
|
-
---
|
|
492
|
-
|
|
493
|
-
## Get Help
|
|
494
|
-
|
|
495
|
-
- **Issues**: [GitHub Issues](https://github.com/suhailtajshaik/react-native-ble-mesh/issues)
|
|
496
|
-
- **Questions**: Open a Discussion on GitHub
|
|
612
|
+
MIT License — do whatever you want with it! See [LICENSE](LICENSE) for details.
|
|
497
613
|
|
|
498
614
|
---
|
|
499
615
|
|