@annadata/capacitor-mqtt-quic 0.1.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.
Files changed (64) hide show
  1. package/README.md +399 -0
  2. package/android/NGTCP2_BUILD_INSTRUCTIONS.md +319 -0
  3. package/android/build-nghttp3.sh +182 -0
  4. package/android/build-ngtcp2.sh +289 -0
  5. package/android/build-openssl.sh +302 -0
  6. package/android/build.gradle +75 -0
  7. package/android/gradle.properties +3 -0
  8. package/android/proguard-rules.pro +2 -0
  9. package/android/settings.gradle +1 -0
  10. package/android/src/main/AndroidManifest.xml +1 -0
  11. package/android/src/main/assets/mqttquic_ca.pem +5 -0
  12. package/android/src/main/cpp/CMakeLists.txt +157 -0
  13. package/android/src/main/cpp/ngtcp2_jni.cpp +928 -0
  14. package/android/src/main/kotlin/ai/annadata/mqttquic/MqttQuicPlugin.kt +232 -0
  15. package/android/src/main/kotlin/ai/annadata/mqttquic/client/MQTTClient.kt +339 -0
  16. package/android/src/main/kotlin/ai/annadata/mqttquic/mqtt/MQTT5Properties.kt +250 -0
  17. package/android/src/main/kotlin/ai/annadata/mqttquic/mqtt/MQTT5Protocol.kt +281 -0
  18. package/android/src/main/kotlin/ai/annadata/mqttquic/mqtt/MQTT5ReasonCodes.kt +109 -0
  19. package/android/src/main/kotlin/ai/annadata/mqttquic/mqtt/MQTTProtocol.kt +249 -0
  20. package/android/src/main/kotlin/ai/annadata/mqttquic/mqtt/MQTTTypes.kt +47 -0
  21. package/android/src/main/kotlin/ai/annadata/mqttquic/quic/NGTCP2Client.kt +184 -0
  22. package/android/src/main/kotlin/ai/annadata/mqttquic/quic/QuicClientStub.kt +54 -0
  23. package/android/src/main/kotlin/ai/annadata/mqttquic/quic/QuicTypes.kt +21 -0
  24. package/android/src/main/kotlin/ai/annadata/mqttquic/transport/QUICStreamAdapter.kt +37 -0
  25. package/android/src/main/kotlin/ai/annadata/mqttquic/transport/StreamTransport.kt +91 -0
  26. package/android/src/test/kotlin/ai/annadata/mqttquic/mqtt/MQTTProtocolTest.kt +92 -0
  27. package/dist/esm/definitions.d.ts +66 -0
  28. package/dist/esm/definitions.d.ts.map +1 -0
  29. package/dist/esm/definitions.js +2 -0
  30. package/dist/esm/definitions.js.map +1 -0
  31. package/dist/esm/index.d.ts +5 -0
  32. package/dist/esm/index.d.ts.map +1 -0
  33. package/dist/esm/index.js +7 -0
  34. package/dist/esm/index.js.map +1 -0
  35. package/dist/esm/web.d.ts +28 -0
  36. package/dist/esm/web.d.ts.map +1 -0
  37. package/dist/esm/web.js +183 -0
  38. package/dist/esm/web.js.map +1 -0
  39. package/dist/plugin.cjs.js +217 -0
  40. package/dist/plugin.cjs.js.map +1 -0
  41. package/dist/plugin.js +215 -0
  42. package/dist/plugin.js.map +1 -0
  43. package/ios/MqttQuicPlugin.podspec +34 -0
  44. package/ios/NGTCP2_BUILD_INSTRUCTIONS.md +302 -0
  45. package/ios/Sources/MqttQuicPlugin/Client/MQTTClient.swift +343 -0
  46. package/ios/Sources/MqttQuicPlugin/MQTT/MQTT5Properties.swift +280 -0
  47. package/ios/Sources/MqttQuicPlugin/MQTT/MQTT5Protocol.swift +333 -0
  48. package/ios/Sources/MqttQuicPlugin/MQTT/MQTT5ReasonCodes.swift +113 -0
  49. package/ios/Sources/MqttQuicPlugin/MQTT/MQTTProtocol.swift +322 -0
  50. package/ios/Sources/MqttQuicPlugin/MQTT/MQTTTypes.swift +54 -0
  51. package/ios/Sources/MqttQuicPlugin/MqttQuicPlugin.swift +229 -0
  52. package/ios/Sources/MqttQuicPlugin/QUIC/NGTCP2Bridge.h +29 -0
  53. package/ios/Sources/MqttQuicPlugin/QUIC/NGTCP2Bridge.mm +865 -0
  54. package/ios/Sources/MqttQuicPlugin/QUIC/NGTCP2Client.swift +262 -0
  55. package/ios/Sources/MqttQuicPlugin/QUIC/QuicClientStub.swift +66 -0
  56. package/ios/Sources/MqttQuicPlugin/QUIC/QuicTypes.swift +23 -0
  57. package/ios/Sources/MqttQuicPlugin/Resources/mqttquic_ca.pem +5 -0
  58. package/ios/Sources/MqttQuicPlugin/Transport/QUICStreamAdapter.swift +50 -0
  59. package/ios/Sources/MqttQuicPlugin/Transport/StreamTransport.swift +105 -0
  60. package/ios/Tests/MQTTProtocolTests.swift +82 -0
  61. package/ios/build-nghttp3.sh +173 -0
  62. package/ios/build-ngtcp2.sh +278 -0
  63. package/ios/build-openssl.sh +405 -0
  64. package/package.json +63 -0
package/README.md ADDED
@@ -0,0 +1,399 @@
1
+ # @annadata/capacitor-mqtt-quic
2
+
3
+ MQTT-over-QUIC Capacitor plugin for iOS and Android. Uses ngtcp2 for QUIC on native; MQTT over WebSocket (WSS) fallback on web.
4
+
5
+ **Features:**
6
+ - ✅ **MQTT 5.0** support with full properties and reason codes
7
+ - ✅ **MQTT 3.1.1** support (backward compatible)
8
+ - ✅ Automatic protocol negotiation (tries 5.0, falls back to 3.1.1)
9
+ - ✅ QUIC transport (ngtcp2) - currently using stubs (see ngtcp2 build section)
10
+ - ✅ Transport abstraction (StreamReader/StreamWriter)
11
+ - ✅ Full MQTT client API (connect, publish, subscribe, unsubscribe, disconnect)
12
+
13
+ ## Structure
14
+
15
+ - **Phase 1**: MQTT protocol layer (Swift/Kotlin) - **Complete** ✅
16
+ - MQTT 3.1.1 protocol implementation
17
+ - MQTT 5.0 protocol implementation with properties and reason codes
18
+ - Transport abstraction (StreamReader/StreamWriter)
19
+ - **Phase 2**: QUIC transport (ngtcp2) + stream adapters - **In Progress** ⏳
20
+ - Currently uses stub implementations for testing
21
+ - See [NGTCP2_INTEGRATION_PLAN.md](./NGTCP2_INTEGRATION_PLAN.md) for build instructions
22
+ - **Phase 3**: MQTT client API + Capacitor plugin bridge - **Complete** ✅
23
+ - **Phase 4**: Platform integration in annadata-production - **Complete** ✅
24
+
25
+ ## Plugin API
26
+
27
+ ### Basic Usage (MQTT 3.1.1)
28
+
29
+ ```ts
30
+ import { MqttQuic } from '@annadata/capacitor-mqtt-quic';
31
+
32
+ // Connect
33
+ await MqttQuic.connect({
34
+ host: 'mqtt.example.com',
35
+ port: 1884,
36
+ clientId: 'my-client-id',
37
+ username: 'user',
38
+ password: 'pass',
39
+ cleanSession: true,
40
+ keepalive: 60
41
+ });
42
+
43
+ // Publish
44
+ await MqttQuic.publish({
45
+ topic: 'sensors/temperature',
46
+ payload: '25.5',
47
+ qos: 1,
48
+ retain: false
49
+ });
50
+
51
+ // Subscribe
52
+ await MqttQuic.subscribe({
53
+ topic: 'sensors/+',
54
+ qos: 1
55
+ });
56
+
57
+ // Unsubscribe
58
+ await MqttQuic.unsubscribe({ topic: 'sensors/+' });
59
+
60
+ // Disconnect
61
+ await MqttQuic.disconnect();
62
+ ```
63
+
64
+ ### TLS Certificate Verification (QUIC)
65
+
66
+ QUIC requires TLS 1.3 and certificate verification is **enabled by default**.
67
+ You can bundle a CA PEM and it will be loaded automatically:
68
+
69
+ - iOS: `ios/Sources/MqttQuicPlugin/Resources/mqttquic_ca.pem`
70
+ - Android: `android/src/main/assets/mqttquic_ca.pem`
71
+
72
+ You can also override per call:
73
+
74
+ ```ts
75
+ await MqttQuic.connect({
76
+ host: 'mqtt.example.com',
77
+ port: 1884,
78
+ clientId: 'my-client-id',
79
+ caFile: '/path/to/ca-bundle.pem',
80
+ // or caPath: '/path/to/ca-directory'
81
+ });
82
+ ```
83
+
84
+ #### How to generate certificates
85
+
86
+ **Option A: Public CA (Let’s Encrypt)**
87
+ You do not bundle `mqttquic_ca.pem` (the OS already trusts public CAs).
88
+
89
+ ```bash
90
+ sudo apt-get update
91
+ sudo apt-get install -y certbot
92
+ sudo certbot certonly --standalone -d mqtt.example.com
93
+ ```
94
+
95
+ Use on server:
96
+ - Cert: `/etc/letsencrypt/live/mqtt.example.com/fullchain.pem`
97
+ - Key: `/etc/letsencrypt/live/mqtt.example.com/privkey.pem`
98
+
99
+ **Option B: Private CA (dev/internal)**
100
+ Generate your own CA, sign the server cert, and bundle the CA PEM.
101
+
102
+ ```bash
103
+ mkdir -p certs && cd certs
104
+
105
+ # 1) Create CA (one-time)
106
+ openssl genrsa -out ca.key 4096
107
+ openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.pem \
108
+ -subj "/C=US/ST=CA/L=SF/O=Annadata/OU=MQTT/CN=Annadata-Root-CA"
109
+
110
+ # 2) Create server key + CSR
111
+ openssl genrsa -out server.key 2048
112
+ openssl req -new -key server.key -out server.csr \
113
+ -subj "/C=US/ST=CA/L=SF/O=Annadata/OU=MQTT/CN=mqtt.example.com"
114
+
115
+ # 3) Add SANs (edit DNS/IP)
116
+ cat > server_ext.cnf <<EOF
117
+ subjectAltName = DNS:mqtt.example.com,IP:YOUR.SERVER.IP
118
+ extendedKeyUsage = serverAuth
119
+ EOF
120
+
121
+ # 4) Sign server cert
122
+ openssl x509 -req -in server.csr -CA ca.pem -CAkey ca.key -CAcreateserial \
123
+ -out server.pem -days 365 -sha256 -extfile server_ext.cnf
124
+ ```
125
+
126
+ Bundle the CA cert (never ship `ca.key`):
127
+ - iOS: `ios/Sources/MqttQuicPlugin/Resources/mqttquic_ca.pem` (use `ca.pem`)
128
+ - Android: `android/src/main/assets/mqttquic_ca.pem` (use `ca.pem`)
129
+
130
+ ### Test Harness (QUIC Smoke Test)
131
+
132
+ This runs: connect → subscribe → publish → disconnect.
133
+
134
+ ```ts
135
+ await MqttQuic.testHarness({
136
+ host: 'mqtt.example.com',
137
+ port: 1884,
138
+ clientId: 'mqttquic_test_client',
139
+ topic: 'test/topic',
140
+ payload: 'Hello QUIC!',
141
+ // optional CA override
142
+ caFile: '/path/to/ca-bundle.pem'
143
+ });
144
+ ```
145
+
146
+ ### MQTT 5.0 Features
147
+
148
+ #### Protocol Version Selection
149
+
150
+ ```ts
151
+ // Use MQTT 5.0 explicitly
152
+ await MqttQuic.connect({
153
+ host: 'mqtt.example.com',
154
+ port: 1884,
155
+ clientId: 'my-client-id',
156
+ protocolVersion: '5.0', // '3.1.1' | '5.0' | 'auto' (default)
157
+ sessionExpiryInterval: 3600, // Session persists 1 hour after disconnect
158
+ keepalive: 60
159
+ });
160
+
161
+ // Auto-negotiation (default): tries 5.0, falls back to 3.1.1
162
+ await MqttQuic.connect({
163
+ protocolVersion: 'auto', // or omit
164
+ // ...
165
+ });
166
+ ```
167
+
168
+ #### Session Management
169
+
170
+ ```ts
171
+ // Session expiry: control how long sessions persist after disconnect
172
+ await MqttQuic.connect({
173
+ // ...
174
+ protocolVersion: '5.0',
175
+ sessionExpiryInterval: 3600, // 1 hour in seconds
176
+ // 0 = session expires immediately on disconnect
177
+ // undefined/null = session expires on disconnect (default)
178
+ });
179
+ ```
180
+
181
+ #### Message Expiry
182
+
183
+ ```ts
184
+ // Messages auto-expire if not delivered within time limit
185
+ await MqttQuic.publish({
186
+ topic: 'events/urgent',
187
+ payload: 'Important message',
188
+ messageExpiryInterval: 300, // Expires in 5 minutes
189
+ contentType: 'application/json'
190
+ });
191
+ ```
192
+
193
+ #### Subscription Identifiers
194
+
195
+ ```ts
196
+ // Identify which subscription triggered a message
197
+ await MqttQuic.subscribe({
198
+ topic: 'sensors/+',
199
+ qos: 1,
200
+ subscriptionIdentifier: 1 // Unique ID for this subscription
201
+ });
202
+
203
+ // When message arrives, you'll know which subscription matched
204
+ ```
205
+
206
+ #### User Properties (Custom Metadata)
207
+
208
+ ```ts
209
+ // Add custom metadata to messages
210
+ await MqttQuic.publish({
211
+ topic: 'events',
212
+ payload: JSON.stringify({ value: 42 }),
213
+ userProperties: [
214
+ { name: 'source', value: 'mobile-app' },
215
+ { name: 'version', value: '1.2.3' },
216
+ { name: 'device-id', value: 'device-123' }
217
+ ],
218
+ contentType: 'application/json'
219
+ });
220
+ ```
221
+
222
+ #### Response Topic & Correlation Data
223
+
224
+ ```ts
225
+ // Request-response pattern
226
+ await MqttQuic.publish({
227
+ topic: 'request/data',
228
+ payload: 'request-id-123',
229
+ responseTopic: 'response/data', // Where to send response
230
+ correlationData: 'correlation-id-456' // Match request/response
231
+ });
232
+ ```
233
+
234
+ ## MQTT 5.0 Features Summary
235
+
236
+ | Feature | Description | Use Case |
237
+ |---------|-------------|----------|
238
+ | **Session Expiry** | Control session persistence | Resume sessions after reconnect |
239
+ | **Message Expiry** | Auto-expire undelivered messages | Time-sensitive data |
240
+ | **Subscription Identifiers** | Identify subscription source | Multi-subscription handling |
241
+ | **User Properties** | Custom key-value metadata | Tracing, versioning, routing |
242
+ | **Content Type** | Message format indicator | JSON, XML, binary, etc. |
243
+ | **Response Topic** | Request-response pattern | RPC over MQTT |
244
+ | **Reason Codes** | Detailed error information | Better debugging |
245
+ | **Topic Aliases** | Reduce bandwidth | High-frequency publishing |
246
+
247
+ See [MQTT5_IMPLEMENTATION_COMPLETE.md](./MQTT5_IMPLEMENTATION_COMPLETE.md) for full details.
248
+
249
+ ## TypeScript Interface
250
+
251
+ ```ts
252
+ interface MqttQuicConnectOptions {
253
+ host: string;
254
+ port: number;
255
+ clientId: string;
256
+ username?: string;
257
+ password?: string;
258
+ cleanSession?: boolean;
259
+ keepalive?: number;
260
+ caFile?: string;
261
+ caPath?: string;
262
+ // MQTT 5.0 options
263
+ protocolVersion?: '3.1.1' | '5.0' | 'auto';
264
+ sessionExpiryInterval?: number;
265
+ receiveMaximum?: number;
266
+ maximumPacketSize?: number;
267
+ topicAliasMaximum?: number;
268
+ }
269
+
270
+ interface MqttQuicPublishOptions {
271
+ topic: string;
272
+ payload: string | Uint8Array;
273
+ qos?: 0 | 1 | 2;
274
+ retain?: boolean;
275
+ // MQTT 5.0 properties
276
+ messageExpiryInterval?: number;
277
+ contentType?: string;
278
+ responseTopic?: string;
279
+ correlationData?: string | Uint8Array;
280
+ userProperties?: Array<{ name: string; value: string }>;
281
+ }
282
+
283
+ interface MqttQuicSubscribeOptions {
284
+ topic: string;
285
+ qos?: 0 | 1 | 2;
286
+ // MQTT 5.0
287
+ subscriptionIdentifier?: number;
288
+ }
289
+
290
+ interface MqttQuicTestHarnessOptions {
291
+ host: string;
292
+ port?: number;
293
+ clientId?: string;
294
+ topic?: string;
295
+ payload?: string;
296
+ caFile?: string;
297
+ caPath?: string;
298
+ }
299
+ ```
300
+
301
+ ## ngtcp2 Build (Phase 2) ⏳
302
+
303
+ **Current Status:** Real QUIC transport implemented using ngtcp2 + quictls (OpenSSL fork).
304
+
305
+ ### Quick Build (Recommended)
306
+
307
+ Use the unified build script to build all native dependencies:
308
+
309
+ ```bash
310
+ # Build for both iOS and Android
311
+ ./build-native.sh
312
+
313
+ # Build only iOS
314
+ ./build-native.sh --ios-only
315
+
316
+ # Build only Android
317
+ ./build-native.sh --android-only
318
+
319
+ # Build for specific Android ABI
320
+ ./build-native.sh --android-only --abi arm64-v8a
321
+ ```
322
+
323
+ This script builds OpenSSL (quictls) → nghttp3 → ngtcp2 in the correct order for both platforms.
324
+
325
+ ### Manual Build
326
+
327
+ For detailed manual build instructions, see:
328
+ - **iOS**: [ios/NGTCP2_BUILD_INSTRUCTIONS.md](./ios/NGTCP2_BUILD_INSTRUCTIONS.md)
329
+ - **Android**: [android/NGTCP2_BUILD_INSTRUCTIONS.md](./android/NGTCP2_BUILD_INSTRUCTIONS.md)
330
+ - **Full Plan**: [NGTCP2_INTEGRATION_PLAN.md](./NGTCP2_INTEGRATION_PLAN.md)
331
+
332
+ **Prerequisites:**
333
+ - iOS: macOS with Xcode 14+
334
+ - Android: Android Studio with NDK r25+ (auto-detected from `$ANDROID_HOME`)
335
+
336
+ ## Development
337
+
338
+ ### Build Plugin
339
+
340
+ ```bash
341
+ cd production/capacitor-mqtt-quic
342
+ npm install
343
+ npm run build
344
+ ```
345
+
346
+ ### Add to Capacitor App
347
+
348
+ ```bash
349
+ cd production/annadata-production
350
+ npm i @annadata/capacitor-mqtt-quic
351
+ npx cap sync
352
+ ```
353
+
354
+ ### Usage in App
355
+
356
+ ```ts
357
+ import { MqttQuic } from '@annadata/capacitor-mqtt-quic';
358
+ import { MqttQuicService } from './services/MqttQuicService';
359
+
360
+ // Via service (recommended)
361
+ const mqttService = new MqttQuicService();
362
+ await mqttService.connect();
363
+
364
+ // Or directly
365
+ await MqttQuic.connect({
366
+ host: 'mqtt.annadata.cloud',
367
+ port: 1884,
368
+ clientId: 'device-123',
369
+ protocolVersion: '5.0'
370
+ });
371
+ ```
372
+
373
+ ## Documentation
374
+
375
+ - [Implementation Summary](./IMPLEMENTATION_SUMMARY.md) - Complete project overview
376
+ - [MQTT 5.0 Implementation](./MQTT5_IMPLEMENTATION_COMPLETE.md) - MQTT 5.0 features and usage
377
+ - [ngtcp2 Integration Plan](./NGTCP2_INTEGRATION_PLAN.md) - Build instructions for real QUIC
378
+ - [MQTT Version Analysis](./MQTT_VERSION_ANALYSIS.md) - Why MQTT 5.0?
379
+
380
+ ## Web/PWA Support
381
+
382
+ On **web** (including PWA), the plugin uses **MQTT over WebSocket (WSS)** via `mqtt.js`. No QUIC; same API.
383
+
384
+ - **Connect:** `ws://host:port` or `wss://host:port` (wss when port is 8884 or 443)
385
+ - **Build:** Ensure `mqtt` is installed (`npm install` in the plugin directory)
386
+ - Use `MqttQuic.connect` / `publish` / `subscribe` / `unsubscribe` / `disconnect` as on native
387
+
388
+ ## Compatibility
389
+
390
+ - **MQTT Protocol:** 3.1.1 and 5.0 (auto-negotiation)
391
+ - **iOS:** 15.0+ (for Network framework)
392
+ - **Android:** API 21+ (Android 5.0+)
393
+ - **Web/PWA:** mqtt.js over WSS
394
+ - **Capacitor:** 7.0+
395
+ - **QUIC:** ngtcp2 1.21.0+ (when integrated)
396
+
397
+ ## License
398
+
399
+ MIT
@@ -0,0 +1,319 @@
1
+ # Building ngtcp2 for Android
2
+
3
+ This document provides instructions for building ngtcp2 and OpenSSL for Android to enable real QUIC transport in the MQTT client.
4
+
5
+ ## Prerequisites
6
+
7
+ - **Android NDK r25+**
8
+ - **CMake 3.20+**
9
+ - **Android SDK 21+** (API level 21 = Android 5.0)
10
+ - **Git** (for cloning repositories)
11
+
12
+ **NDK path tip:** the build scripts auto-detect NDK installs in
13
+ `~/Library/Android/sdk/ndk` (macOS) or `~/Android/Sdk/ndk` (Linux). You can
14
+ omit `--ndk-path` if your NDK is installed in one of those locations.
15
+
16
+ **Source layout:** set `PROJECT_DIR` to the `capacitor-mqtt-quic` repo root.
17
+ Build scripts then expect dependencies under:
18
+ - `$PROJECT_DIR/ref-code/ngtcp2`
19
+ - `$PROJECT_DIR/ref-code/nghttp3`
20
+ - `$PROJECT_DIR/ref-code/openssl`
21
+
22
+ ```bash
23
+ export PROJECT_DIR="/Users/annadata/Project_A/annadata-production/ref-code/capacitor-mqtt-quic"
24
+ ```
25
+
26
+ Override with `NGTCP2_SOURCE_DIR`, `NGHTTP3_SOURCE_DIR`, `OPENSSL_SOURCE_DIR`
27
+ if you store sources elsewhere.
28
+
29
+ ## Quick Start
30
+
31
+ ### Option 1: Use Pre-built Libraries (Recommended for Development)
32
+
33
+ If you have access to pre-built ngtcp2, nghttp3, and OpenSSL libraries:
34
+
35
+ 1. Place `libngtcp2_client.so` in `android/src/main/jniLibs/<abi>/`
36
+ 2. Place `libnghttp3.a` in `android/libs/<abi>/`
37
+ 3. Place OpenSSL libraries (`libssl.a`, `libcrypto.a`) in `android/libs/<abi>/`
38
+ 4. Update `build.gradle` and `CMakeLists.txt` to link against these libraries
39
+
40
+ ### Option 2: Build from Source
41
+
42
+ #### Step 1: Build OpenSSL for Android (QUIC TLS)
43
+
44
+ ```bash
45
+ cd android
46
+ ./build-openssl.sh \
47
+ --ndk-path ~/Library/Android/sdk/ndk/<ndk-version> \
48
+ --abi arm64-v8a \
49
+ --platform android-21 \
50
+ --quictls
51
+ ```
52
+
53
+ This will:
54
+ - Clone quictls (OpenSSL fork with QUIC API) if not present
55
+ - Build static libraries for Android
56
+ - Install to `android/install/openssl-android/<abi>/`
57
+
58
+ **Note:** For different ABIs, repeat the build:
59
+ ```bash
60
+ # arm64-v8a (64-bit ARM)
61
+ ./build-openssl.sh --ndk-path ~/Android/Sdk/ndk/25.2.9519653 --platform android-21 --abi arm64-v8a --quictls
62
+ # ./build-openssl.sh --ndk-path "/Users/annadata/Library/Android/sdk/ndk/29.0.13113456" --abi arm64-v8a --platform android-21 --quictls
63
+
64
+ # armeabi-v7a (32-bit ARM)
65
+ ./build-openssl.sh --ndk-path ~/Android/Sdk/ndk/25.2.9519653 --platform android-21 --abi armeabi-v7a --quictls
66
+ # ./build-openssl.sh --ndk-path "/Users/annadata/Library/Android/sdk/ndk/29.0.13113456" --abi armeabi-v7a --platform android-21 --quictls
67
+
68
+ # x86_64 (64-bit x86)
69
+ ./build-openssl.sh --ndk-path ~/Android/Sdk/ndk/25.2.9519653 --platform android-21 --abi x86_64 --quictls
70
+ # ./build-openssl.sh --ndk-path "/Users/annadata/Library/Android/sdk/ndk/29.0.13113456" --abi x86_64 --platform android-21 --quictls
71
+ ```
72
+
73
+ #### Step 2: Build nghttp3 for Android
74
+
75
+ ```bash
76
+ cd android
77
+ ./build-nghttp3.sh \
78
+ --ndk-path ~/Library/Android/sdk/ndk/<ndk-version> \
79
+ --abi arm64-v8a \
80
+ --platform android-21
81
+ ```
82
+
83
+ This will:
84
+ - Build nghttp3 static library
85
+ - Install to `android/install/nghttp3-android/<abi>/`
86
+
87
+ - ./build-nghttp3.sh --abi arm64-v8a --platform android-21
88
+
89
+ #### Step 3: Build ngtcp2 for Android
90
+
91
+ ```bash
92
+ cd android
93
+ ./build-ngtcp2.sh \
94
+ --ndk-path ~/Library/Android/sdk/ndk/<ndk-version> \
95
+ --abi arm64-v8a \
96
+ --platform android-21 \
97
+ --openssl-path ./install/openssl-android/arm64-v8a \
98
+ --quictls
99
+ ```
100
+
101
+ This will:
102
+ - Build ngtcp2 static library
103
+ - Link against OpenSSL
104
+ - Install to `android/install/ngtcp2-android/<abi>/`
105
+ ./build-ngtcp2.sh --abi arm64-v8a --platform android-21 --openssl-path ./install/openssl-android --quictls
106
+
107
+ #### Step 4: Build JNI Library
108
+
109
+ The JNI wrapper (`ngtcp2_jni.cpp`) is built as part of the Android project using CMake.
110
+
111
+ Update `android/build.gradle`:
112
+
113
+ ```gradle
114
+ android {
115
+ // ...
116
+ externalNativeBuild {
117
+ cmake {
118
+ path "src/main/cpp/CMakeLists.txt"
119
+ version "3.22.1"
120
+ }
121
+ }
122
+
123
+ ndk {
124
+ abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64'
125
+ }
126
+ }
127
+ ```
128
+
129
+ ## Integration into Android Project
130
+
131
+ ### Update build.gradle
132
+
133
+ Add CMake configuration:
134
+
135
+ ```gradle
136
+ android {
137
+ compileSdkVersion 34
138
+
139
+ defaultConfig {
140
+ // ...
141
+ externalNativeBuild {
142
+ cmake {
143
+ arguments "-DANDROID_STL=c++_shared"
144
+ cppFlags "-std=c++17"
145
+ }
146
+ }
147
+ ndk {
148
+ abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64'
149
+ }
150
+ }
151
+
152
+ externalNativeBuild {
153
+ cmake {
154
+ path "src/main/cpp/CMakeLists.txt"
155
+ version "3.22.1"
156
+ }
157
+ }
158
+ }
159
+ ```
160
+
161
+ ### Update CMakeLists.txt
162
+
163
+ Ensure `CMakeLists.txt` points to correct ngtcp2 and OpenSSL paths:
164
+
165
+ ```cmake
166
+ # Set paths
167
+ set(NGTCP2_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../ngtcp2")
168
+ set(NGHTTP3_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../nghttp3")
169
+ set(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../install/openssl-android")
170
+ ```
171
+
172
+ ## TLS Certificate Verification (QUIC)
173
+
174
+ QUIC requires TLS 1.3 and certificate verification is **enabled by default**.
175
+ You can bundle a CA PEM and it will be loaded automatically:
176
+
177
+ - `android/src/main/assets/mqttquic_ca.pem`
178
+
179
+ You can also override per call:
180
+
181
+ ```ts
182
+ await MqttQuic.connect({
183
+ host: 'mqtt.example.com',
184
+ port: 1884,
185
+ clientId: 'my-client-id',
186
+ caFile: '/path/to/ca-bundle.pem',
187
+ // or caPath: '/path/to/ca-directory'
188
+ });
189
+ ```
190
+
191
+ ### How to generate certificates
192
+
193
+ **Option A: Public CA (Let’s Encrypt)**
194
+ You do not bundle `mqttquic_ca.pem` (the OS already trusts public CAs).
195
+
196
+ ```bash
197
+ sudo apt-get update
198
+ sudo apt-get install -y certbot
199
+ sudo certbot certonly --standalone -d mqtt.example.com
200
+ ```
201
+
202
+ Use on server:
203
+ - Cert: `/etc/letsencrypt/live/mqtt.example.com/fullchain.pem`
204
+ - Key: `/etc/letsencrypt/live/mqtt.example.com/privkey.pem`
205
+
206
+ **Option B: Private CA (dev/internal)**
207
+ Generate your own CA, sign the server cert, and bundle the CA PEM.
208
+
209
+ ```bash
210
+ mkdir -p certs && cd certs
211
+
212
+ # 1) Create CA (one-time)
213
+ openssl genrsa -out ca.key 4096
214
+ openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.pem \
215
+ -subj "/C=US/ST=CA/L=SF/O=Annadata/OU=MQTT/CN=Annadata-Root-CA"
216
+
217
+ # 2) Create server key + CSR
218
+ openssl genrsa -out server.key 2048
219
+ openssl req -new -key server.key -out server.csr \
220
+ -subj "/C=US/ST=CA/L=SF/O=Annadata/OU=MQTT/CN=mqtt.example.com"
221
+
222
+ # 3) Add SANs (edit DNS/IP)
223
+ cat > server_ext.cnf <<EOF
224
+ subjectAltName = DNS:mqtt.example.com,IP:YOUR.SERVER.IP
225
+ extendedKeyUsage = serverAuth
226
+ EOF
227
+
228
+ # 4) Sign server cert
229
+ openssl x509 -req -in server.csr -CA ca.pem -CAkey ca.key -CAcreateserial \
230
+ -out server.pem -days 365 -sha256 -extfile server_ext.cnf
231
+ ```
232
+
233
+ Bundle the CA cert (never ship `ca.key`):
234
+ - Android: `android/src/main/assets/mqttquic_ca.pem` (use `ca.pem`)
235
+
236
+ ## Test Harness (QUIC Smoke Test)
237
+
238
+ This runs: connect → subscribe → publish → disconnect.
239
+
240
+ ```ts
241
+ await MqttQuic.testHarness({
242
+ host: 'mqtt.example.com',
243
+ port: 1884,
244
+ clientId: 'mqttquic_test_client',
245
+ topic: 'test/topic',
246
+ payload: 'Hello QUIC!',
247
+ // optional CA override
248
+ caFile: '/path/to/ca-bundle.pem'
249
+ });
250
+ ```
251
+
252
+ ## Using Pre-built Libraries
253
+
254
+ ### OpenSSL
255
+
256
+ Download from:
257
+ - https://github.com/leenjewel/openssl_for_ios_and_android
258
+
259
+ ### ngtcp2
260
+
261
+ Currently, there are no widely available pre-built ngtcp2 libraries for Android. You'll need to build from source.
262
+
263
+ ### nghttp3
264
+
265
+ Currently, there are no widely available pre-built nghttp3 libraries for Android. You'll need to build from source. Make sure you clone with submodules:
266
+
267
+ ```bash
268
+ git clone --recurse-submodules https://github.com/ngtcp2/nghttp3.git
269
+ ```
270
+
271
+ ## Troubleshooting
272
+
273
+ ### NDK Not Found
274
+
275
+ ```bash
276
+ # Install via Android Studio SDK Manager
277
+ # Or download from: https://developer.android.com/ndk/downloads
278
+ ```
279
+
280
+ ### CMake Not Found
281
+
282
+ ```bash
283
+ # Install via Android Studio SDK Manager
284
+ # Or download from: https://cmake.org/download/
285
+ ```
286
+
287
+ ### OpenSSL Build Fails
288
+
289
+ - Ensure you're using OpenSSL 3.0+ (required for TLS 1.3)
290
+ - Check that NDK path is correct
291
+ - Verify ABI is supported (arm64-v8a, armeabi-v7a, x86_64, x86)
292
+
293
+ ### ngtcp2 Build Fails
294
+
295
+ - Verify OpenSSL is built and path is correct
296
+ - Check CMake version: `cmake --version` (must be 3.20+)
297
+ - Ensure Android platform matches (android-21+)
298
+
299
+ ### Link Errors
300
+
301
+ - Verify all libraries are built for the same ABI
302
+ - Check that CMakeLists.txt paths are correct
303
+ - Ensure OpenSSL and ngtcp2 are linked in the correct order
304
+
305
+ ### JNI Errors
306
+
307
+ - Verify native method names match exactly (package + class + method)
308
+ - Check that `System.loadLibrary("ngtcp2_client")` is called
309
+ - Ensure library is in correct ABI folder: `src/main/jniLibs/<abi>/`
310
+
311
+ ## Next Steps
312
+
313
+ After building ngtcp2/nghttp3:
314
+
315
+ 1. Update `ngtcp2_jni.cpp` to implement the TODO sections
316
+ 2. Replace `QuicClientStub` with `NGTCP2Client` in `MQTTClient.kt`
317
+ 3. Test connection to MQTT server over QUIC
318
+
319
+ See `NGTCP2_INTEGRATION_PLAN.md` for detailed implementation guide.