@dashx/react-native 1.1.4 → 1.2.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/.DS_Store +0 -0
- package/.claude/settings.local.json +18 -1
- package/.cursor/plans/deep_linking_implementation_plan_303c2ca9.plan.md +216 -0
- package/.gitignore +2 -2
- package/DashXReactNative.podspec +5 -26
- package/README.md +10 -478
- package/__tests__/fallback.test.js +72 -0
- package/__tests__/index.test.js +147 -4
- package/android/build.gradle +27 -1
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/dashx/rn/sdk/DashXReactNativeModuleImpl.kt +384 -0
- package/android/src/newarch/java/com/dashx/rn/sdk/DashXReactNativeModule.kt +85 -0
- package/android/src/newarch/java/com/dashx/rn/sdk/DashXReactNativePackage.kt +33 -0
- package/android/src/oldarch/java/com/dashx/rn/sdk/DashXReactNativeModule.kt +106 -0
- package/android/src/oldarch/java/com/dashx/rn/sdk/DashXReactNativePackage.kt +33 -0
- package/index.d.ts +32 -1
- package/index.js +31 -8
- package/ios/DashXNotificationHandler.swift +222 -0
- package/ios/DashXReactNative-Bridging-Header.h +0 -2
- package/ios/DashXReactNative.mm +32 -9
- package/ios/DashXReactNative.swift +60 -18
- package/package.json +11 -2
- package/src/NativeDashXReactNative.ts +42 -0
- package/android/src/main/java/com/dashx/rn/sdk/DashXReactNativeModule.kt +0 -231
- package/android/src/main/java/com/dashx/rn/sdk/DashXReactNativePackage.kt +0 -18
- package/ios/DashXRCTAppDelegate.h +0 -3
- package/ios/DashXRCTAppDelegate.swift +0 -266
- package/ios/DashXReactNative.h +0 -1
package/README.md
CHANGED
|
@@ -20,22 +20,17 @@
|
|
|
20
20
|
|
|
21
21
|
[](https://www.npmjs.com/package/@dashx/react-native)
|
|
22
22
|
[](https://github.com/dashxhq/dashx-react-native/blob/main/LICENSE)
|
|
23
|
-
[](#
|
|
23
|
+
[](#install)
|
|
24
24
|
|
|
25
25
|
_DashX SDK for React Native_
|
|
26
26
|
|
|
27
|
-
##
|
|
27
|
+
## Install
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|----------|----------------|
|
|
31
|
-
| iOS | 13.0+ |
|
|
32
|
-
| Android | SDK 26 (Android 8.0)+ |
|
|
33
|
-
| React Native | 0.71+ |
|
|
34
|
-
| Node.js | 16.0+ |
|
|
29
|
+
Requires **React Native 0.74+**, **iOS 13.0+**, **Android SDK 26+**, and **Node.js 16+**.
|
|
35
30
|
|
|
36
|
-
|
|
31
|
+
Supports both the **Old Architecture** (bridge) and **New Architecture** (TurboModule) from a single install.
|
|
37
32
|
|
|
38
|
-
|
|
33
|
+
> **Note:** This SDK uses native modules and is **not compatible with Expo Go**. Use a [development build](https://docs.expo.dev/develop/development-builds/introduction/) if you are using Expo.
|
|
39
34
|
|
|
40
35
|
```sh
|
|
41
36
|
npm install @dashx/react-native
|
|
@@ -47,480 +42,17 @@ or
|
|
|
47
42
|
yarn add @dashx/react-native
|
|
48
43
|
```
|
|
49
44
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
DashX requires Google Services for Firebase Cloud Messaging:
|
|
53
|
-
|
|
54
|
-
1. Add the `google-services` plugin in your `/android/build.gradle`:
|
|
55
|
-
|
|
56
|
-
```gradle
|
|
57
|
-
buildscript {
|
|
58
|
-
dependencies {
|
|
59
|
-
// ... other dependencies
|
|
60
|
-
classpath 'com.google.gms:google-services:4.4.2'
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
2. Apply the plugin in your `/android/app/build.gradle`:
|
|
66
|
-
|
|
67
|
-
```gradle
|
|
68
|
-
apply plugin: 'com.google.gms.google-services'
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
3. Add your Android app on [Firebase Console](https://console.firebase.google.com/): **Project Overview > Add App > Android**
|
|
72
|
-
|
|
73
|
-
4. Download `google-services.json` and place it at `/android/app/google-services.json`
|
|
74
|
-
|
|
75
|
-
### Setup for iOS
|
|
76
|
-
|
|
77
|
-
#### Step 1: Add pods to your Podfile
|
|
78
|
-
|
|
79
|
-
The DashX iOS SDK is not published to CocoaPods trunk. Add it directly from GitHub along with the Firebase pods required for FCM push notifications.
|
|
80
|
-
|
|
81
|
-
Add `use_modular_headers!` at the top of your `ios/Podfile`, then add the pods inside the target block:
|
|
82
|
-
|
|
83
|
-
```ruby
|
|
84
|
-
use_modular_headers!
|
|
85
|
-
|
|
86
|
-
target 'YourApp' do
|
|
87
|
-
# ... other pods
|
|
88
|
-
|
|
89
|
-
pod 'DashX', :git => 'https://github.com/dashxhq/dashx-ios.git', :tag => '1.1.4'
|
|
90
|
-
pod 'FirebaseCore'
|
|
91
|
-
pod 'FirebaseMessaging'
|
|
92
|
-
|
|
93
|
-
use_react_native!(...)
|
|
94
|
-
end
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
Then run:
|
|
98
|
-
|
|
99
|
-
```sh
|
|
100
|
-
cd ios && pod install
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
#### Step 2: Add GoogleService-Info.plist
|
|
104
|
-
|
|
105
|
-
1. Add your iOS app on [Firebase Console](https://console.firebase.google.com/): **Project Overview > Add App > iOS**
|
|
106
|
-
2. Download `GoogleService-Info.plist` and add it to your Xcode project (right-click project root > **Add Files to "YourApp"**, ensure **Copy items if needed** is checked)
|
|
107
|
-
|
|
108
|
-
#### Step 3: Enable Push Notifications capability
|
|
109
|
-
|
|
110
|
-
In Xcode, select your app target > **Signing & Capabilities** > **+ Capability** > add **Push Notifications**.
|
|
111
|
-
|
|
112
|
-
#### Step 4: Configure your AppDelegate
|
|
113
|
-
|
|
114
|
-
The SDK ships `DashXRCTAppDelegate` which handles permission requests, notification display, and universal link forwarding. Subclass it in your `AppDelegate.swift` and configure Firebase directly:
|
|
115
|
-
|
|
116
|
-
```swift
|
|
117
|
-
import DashXReactNative
|
|
118
|
-
import ReactAppDependencyProvider
|
|
119
|
-
import FirebaseCore
|
|
120
|
-
import FirebaseMessaging
|
|
121
|
-
import DashX
|
|
122
|
-
import UserNotifications
|
|
123
|
-
|
|
124
|
-
@main
|
|
125
|
-
class AppDelegate: DashXRCTAppDelegate {
|
|
126
|
-
override var moduleName: String { "YourAppName" }
|
|
127
|
-
|
|
128
|
-
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
|
129
|
-
self.dependencyProvider = RCTAppDependencyProvider()
|
|
130
|
-
FirebaseApp.configure()
|
|
131
|
-
Messaging.messaging().delegate = self
|
|
132
|
-
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Forward the APNS token to Firebase so it can exchange it for an FCM token
|
|
136
|
-
override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
|
|
137
|
-
Messaging.messaging().setAPNSToken(deviceToken, type: .unknown)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
override func bundleURL() -> URL? {
|
|
141
|
-
#if DEBUG
|
|
142
|
-
RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
|
|
143
|
-
#else
|
|
144
|
-
Bundle.main.url(forResource: "main", withExtension: "jsbundle")
|
|
145
|
-
#endif
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Receive the FCM token and pass it to DashX
|
|
150
|
-
extension AppDelegate: MessagingDelegate {
|
|
151
|
-
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
|
|
152
|
-
guard let token = fcmToken else { return }
|
|
153
|
-
DashX.setFCMToken(to: token)
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
`DashXRCTAppDelegate` handles the rest automatically:
|
|
159
|
-
- Requests notification permission on launch
|
|
160
|
-
- Displays notifications (banner + sound by default, even while app is in the foreground)
|
|
161
|
-
- Tracks delivery, clicks, and dismissals
|
|
162
|
-
- Forwards universal links to the JS `onLinkReceived` listener
|
|
45
|
+
## Documentation
|
|
163
46
|
|
|
164
|
-
|
|
47
|
+
For detailed documentation, visit [React Native SDK documentation](https://docs.dashx.com/sdks/client-side/react-native-sdk).
|
|
165
48
|
|
|
166
|
-
|
|
167
|
-
/// Control foreground notification presentation (default: [.banner, .sound])
|
|
168
|
-
override func notificationDeliveredInForeground(message: [AnyHashable: Any]) -> UNNotificationPresentationOptions {
|
|
169
|
-
return [.banner, .sound, .badge]
|
|
170
|
-
}
|
|
49
|
+
## Deep linking and push navigation
|
|
171
50
|
|
|
172
|
-
|
|
173
|
-
override func notificationClicked(message: [AnyHashable: Any], actionIdentifier: String) {
|
|
174
|
-
// custom tap handling
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Called when a universal/deep link arrives
|
|
178
|
-
override func handleLink(url: URL) {
|
|
179
|
-
// custom link handling
|
|
180
|
-
}
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
#### Step 5: Subscribe in JavaScript
|
|
184
|
-
|
|
185
|
-
Call `DashX.subscribe()` at app startup so the SDK registers the device as soon as the FCM token is available:
|
|
186
|
-
|
|
187
|
-
```js
|
|
188
|
-
import { useEffect } from 'react';
|
|
189
|
-
import DashX from '@dashx/react-native';
|
|
190
|
-
|
|
191
|
-
DashX.configure({ publicKey: 'your-public-key' });
|
|
192
|
-
|
|
193
|
-
export default function App() {
|
|
194
|
-
useEffect(() => {
|
|
195
|
-
DashX.subscribe();
|
|
196
|
-
}, []);
|
|
197
|
-
|
|
198
|
-
// ...
|
|
199
|
-
}
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
> **Without Firebase:** If you are not using FCM, omit the Firebase pods and the Firebase-related `AppDelegate` code. The SDK will still handle APNS permission requests and notification display via `DashXRCTAppDelegate`.
|
|
203
|
-
|
|
204
|
-
## Usage
|
|
205
|
-
|
|
206
|
-
```js
|
|
207
|
-
import DashX from '@dashx/react-native';
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Configure
|
|
211
|
-
|
|
212
|
-
Initialize the SDK once at app startup. Call `configure` at the top level of your entry file (e.g. `App.js`) so it runs before any component mounts:
|
|
213
|
-
|
|
214
|
-
```js
|
|
215
|
-
// App.js — call at module level, before the component
|
|
216
|
-
import DashX from '@dashx/react-native';
|
|
217
|
-
|
|
218
|
-
DashX.configure({
|
|
219
|
-
publicKey: 'your-public-key',
|
|
220
|
-
// baseURI: 'https://api.dashx.com', // optional, custom API endpoint
|
|
221
|
-
// targetEnvironment: 'production', // optional
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
export default function App() {
|
|
225
|
-
// ...
|
|
226
|
-
}
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
Calling from `useEffect` in your root component also works, but module-level init is preferred so the SDK is ready as early as possible.
|
|
230
|
-
|
|
231
|
-
| Option | Type | Required | Description |
|
|
232
|
-
|--------|------|----------|-------------|
|
|
233
|
-
| `publicKey` | `string` | Yes | Your DashX public key |
|
|
234
|
-
| `baseURI` | `string` | No | Custom API base URI |
|
|
235
|
-
| `targetEnvironment` | `string` | No | Target environment name |
|
|
236
|
-
|
|
237
|
-
### Identify a user
|
|
238
|
-
|
|
239
|
-
```js
|
|
240
|
-
DashX.identify({
|
|
241
|
-
firstName: 'John',
|
|
242
|
-
lastName: 'Doe',
|
|
243
|
-
email: 'john@example.com',
|
|
244
|
-
});
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
### Set identity with token
|
|
248
|
-
|
|
249
|
-
```js
|
|
250
|
-
DashX.setIdentity('user-uid', 'user-token');
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### Reset
|
|
254
|
-
|
|
255
|
-
Clear the current identity:
|
|
256
|
-
|
|
257
|
-
```js
|
|
258
|
-
DashX.reset();
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
### Track events
|
|
262
|
-
|
|
263
|
-
```js
|
|
264
|
-
DashX.track('Item Purchased', {
|
|
265
|
-
itemId: 'sku-123',
|
|
266
|
-
price: 9.99,
|
|
267
|
-
});
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
### Track screen views
|
|
271
|
-
|
|
272
|
-
```js
|
|
273
|
-
DashX.screen('HomeScreen', {
|
|
274
|
-
referrer: 'DeepLink',
|
|
275
|
-
});
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
### Fetch a record
|
|
279
|
-
|
|
280
|
-
Fetch a single record by URN (e.g. `"article/uuid"`). The URN must use the full UUID form of the record ID.
|
|
281
|
-
|
|
282
|
-
```js
|
|
283
|
-
const record = await DashX.fetchRecord('article/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', {
|
|
284
|
-
preview: false,
|
|
285
|
-
language: 'en',
|
|
286
|
-
// fields, include, exclude as arrays of objects if needed
|
|
287
|
-
});
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
| Option | Type | Description |
|
|
291
|
-
|--------|------|-------------|
|
|
292
|
-
| `preview` | `boolean` | Include draft/preview content |
|
|
293
|
-
| `language` | `string` | Content language |
|
|
294
|
-
| `fields` | `object[]` | Fields to return |
|
|
295
|
-
| `include` | `object[]` | Related data to include |
|
|
296
|
-
| `exclude` | `object[]` | Fields to exclude |
|
|
297
|
-
|
|
298
|
-
### Search records
|
|
299
|
-
|
|
300
|
-
```js
|
|
301
|
-
const records = await DashX.searchRecords('article', {
|
|
302
|
-
filter: { status: 'published' },
|
|
303
|
-
order: [{ field: 'createdAt', direction: 'desc' }],
|
|
304
|
-
limit: 10,
|
|
305
|
-
page: 1,
|
|
306
|
-
preview: false,
|
|
307
|
-
language: 'en',
|
|
308
|
-
});
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
| Option | Type | Description |
|
|
312
|
-
|--------|------|-------------|
|
|
313
|
-
| `filter` | `object` | Filter criteria |
|
|
314
|
-
| `order` | `object[]` | Sort order (e.g. `[{ field, direction }]`) |
|
|
315
|
-
| `limit` | `number` | Max records to return |
|
|
316
|
-
| `page` | `number` | Page number for pagination |
|
|
317
|
-
| `preview` | `boolean` | Preview/draft content |
|
|
318
|
-
| `language` | `string` | Content language |
|
|
319
|
-
| `fields` | `object[]` | Fields to return |
|
|
320
|
-
| `include` | `object[]` | Related data to include |
|
|
321
|
-
| `exclude` | `object[]` | Fields to exclude |
|
|
322
|
-
|
|
323
|
-
### Push notifications
|
|
324
|
-
|
|
325
|
-
Subscribe the current device to push notifications:
|
|
326
|
-
|
|
327
|
-
```js
|
|
328
|
-
DashX.subscribe();
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
Unsubscribe:
|
|
332
|
-
|
|
333
|
-
```js
|
|
334
|
-
DashX.unsubscribe();
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
### Request notification permission (iOS)
|
|
338
|
-
|
|
339
|
-
Prompt the user for push notification permission. Returns a `NotificationPermissionStatus` integer matching `UNAuthorizationStatus`:
|
|
340
|
-
|
|
341
|
-
| Value | Meaning |
|
|
342
|
-
|-------|---------|
|
|
343
|
-
| `0` | Not determined |
|
|
344
|
-
| `1` | Denied |
|
|
345
|
-
| `2` | Authorized |
|
|
346
|
-
| `3` | Provisional |
|
|
347
|
-
| `4` | Ephemeral |
|
|
348
|
-
|
|
349
|
-
```js
|
|
350
|
-
const status = await DashX.requestNotificationPermission();
|
|
351
|
-
if (status === 2) {
|
|
352
|
-
DashX.subscribe();
|
|
353
|
-
}
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
To check the current status without prompting the user:
|
|
357
|
-
|
|
358
|
-
```js
|
|
359
|
-
const status = await DashX.getNotificationPermissionStatus();
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
### Listen for incoming messages
|
|
363
|
-
|
|
364
|
-
Register a listener to handle push notifications when they arrive:
|
|
365
|
-
|
|
366
|
-
```js
|
|
367
|
-
import { useEffect } from 'react';
|
|
368
|
-
|
|
369
|
-
useEffect(() => {
|
|
370
|
-
const subscription = DashX.onMessageReceived((message) => {
|
|
371
|
-
console.log('Notification received:', message);
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
return () => subscription.remove();
|
|
375
|
-
}, []);
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
### Listen for deep links / universal links (iOS)
|
|
379
|
-
|
|
380
|
-
Register a listener that fires when the SDK receives a universal link. On the native side, `DashXRCTAppDelegate` forwards links via `DashX.handleUserActivity` automatically.
|
|
381
|
-
|
|
382
|
-
```js
|
|
383
|
-
useEffect(() => {
|
|
384
|
-
const subscription = DashX.onLinkReceived((url) => {
|
|
385
|
-
console.log('Link received:', url);
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
return () => subscription.remove();
|
|
389
|
-
}, []);
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
### Notification preferences
|
|
393
|
-
|
|
394
|
-
Fetch the user's stored notification preferences:
|
|
395
|
-
|
|
396
|
-
```js
|
|
397
|
-
const preferences = await DashX.fetchStoredPreferences();
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
Save updated preferences:
|
|
401
|
-
|
|
402
|
-
```js
|
|
403
|
-
await DashX.saveStoredPreferences({
|
|
404
|
-
marketing_emails: true,
|
|
405
|
-
product_updates: false,
|
|
406
|
-
});
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
### Upload an asset (iOS)
|
|
410
|
-
|
|
411
|
-
Upload a local file to DashX and associate it with a resource and attribute:
|
|
412
|
-
|
|
413
|
-
```js
|
|
414
|
-
const response = await DashX.uploadAsset(
|
|
415
|
-
'/path/to/local/file.jpg',
|
|
416
|
-
'user', // resource name
|
|
417
|
-
'avatar' // attribute name
|
|
418
|
-
);
|
|
419
|
-
// response: { status, data: { asset: { status, url, playbackIds } } }
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
### Fetch an asset (iOS)
|
|
423
|
-
|
|
424
|
-
Retrieve the status and URL of a previously uploaded asset by its ID:
|
|
425
|
-
|
|
426
|
-
```js
|
|
427
|
-
const asset = await DashX.fetchAsset('asset-id');
|
|
428
|
-
// asset: { status, data: { asset: { status, url, playbackIds } } }
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
### Lifecycle tracking (iOS)
|
|
432
|
-
|
|
433
|
-
Enable automatic app lifecycle event tracking (app opened, backgrounded, etc.):
|
|
434
|
-
|
|
435
|
-
```js
|
|
436
|
-
DashX.enableLifecycleTracking(); // no-op on Android
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
### Ad tracking / ATT (iOS)
|
|
440
|
-
|
|
441
|
-
Request App Tracking Transparency permission and enable IDFA tracking:
|
|
442
|
-
|
|
443
|
-
```js
|
|
444
|
-
DashX.enableAdTracking(); // no-op on Android
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
Make sure `NSUserTrackingUsageDescription` is set in your `Info.plist`.
|
|
448
|
-
|
|
449
|
-
### Logging
|
|
450
|
-
|
|
451
|
-
Set the SDK log level for debugging:
|
|
452
|
-
|
|
453
|
-
```js
|
|
454
|
-
DashX.setLogLevel(1); // 0 = off, 1 = errors, 2 = debug
|
|
455
|
-
```
|
|
456
|
-
|
|
457
|
-
## API Reference
|
|
458
|
-
|
|
459
|
-
| Method | Signature | Platforms | Returns | Description |
|
|
460
|
-
|--------|-----------|-----------|---------|-------------|
|
|
461
|
-
| `configure` | `(options: object)` | iOS, Android | `void` | Initialize the SDK with your public key |
|
|
462
|
-
| `identify` | `(options: object)` | iOS, Android | `void` | Identify the current user with traits |
|
|
463
|
-
| `setIdentity` | `(uid: string, token: string)` | iOS, Android | `void` | Set user identity with UID and auth token |
|
|
464
|
-
| `reset` | `()` | iOS, Android | `void` | Clear the current user identity |
|
|
465
|
-
| `track` | `(event: string, data?: object)` | iOS, Android | `void` | Track a named event with optional data |
|
|
466
|
-
| `screen` | `(screenName: string, data?: object)` | iOS, Android | `void` | Track a screen view |
|
|
467
|
-
| `fetchRecord` | `(urn: string, options?: object)` | iOS, Android | `Promise<object>` | Fetch a single record by URN (`"resource/uuid"`) |
|
|
468
|
-
| `searchRecords` | `(resource: string, options?: object)` | iOS, Android | `Promise<object[]>` | Search records with filter, order, limit, page, etc. |
|
|
469
|
-
| `subscribe` | `()` | iOS, Android | `void` | Subscribe device for push notifications |
|
|
470
|
-
| `unsubscribe` | `()` | iOS, Android | `void` | Unsubscribe device from push notifications |
|
|
471
|
-
| `fetchStoredPreferences` | `()` | iOS, Android | `Promise<object>` | Fetch stored notification preferences |
|
|
472
|
-
| `saveStoredPreferences` | `(data: object)` | iOS, Android | `Promise<object>` | Save notification preferences |
|
|
473
|
-
| `setLogLevel` | `(level: number)` | iOS, Android | `void` | Set SDK log verbosity (0=off, 1=errors, 2=debug) |
|
|
474
|
-
| `onMessageReceived` | `(callback: function)` | iOS, Android | `EmitterSubscription` | Listen for incoming push notifications |
|
|
475
|
-
| `requestNotificationPermission` | `()` | iOS | `Promise<number>` | Prompt for push permission; resolves with `UNAuthorizationStatus` (0-4) |
|
|
476
|
-
| `getNotificationPermissionStatus` | `()` | iOS | `Promise<number>` | Get current push permission status without prompting |
|
|
477
|
-
| `onLinkReceived` | `(callback: function)` | iOS | `EmitterSubscription` | Listen for universal/deep link events |
|
|
478
|
-
| `uploadAsset` | `(filePath: string, resource: string, attribute: string)` | iOS | `Promise<AssetResponse>` | Upload a local file and associate it with a resource attribute |
|
|
479
|
-
| `fetchAsset` | `(assetId: string)` | iOS | `Promise<AssetResponse>` | Fetch status and URL of an uploaded asset |
|
|
480
|
-
| `enableLifecycleTracking` | `()` | iOS | `void` | Enable automatic app lifecycle event tracking |
|
|
481
|
-
| `enableAdTracking` | `()` | iOS | `void` | Request ATT permission and enable IDFA tracking |
|
|
482
|
-
|
|
483
|
-
For detailed usage and advanced features, refer to the [DashX documentation](https://docs.dashx.com).
|
|
484
|
-
|
|
485
|
-
### Error Codes
|
|
486
|
-
|
|
487
|
-
Promise rejections from native methods use a consistent error code across both platforms:
|
|
488
|
-
|
|
489
|
-
| Code | Description |
|
|
490
|
-
|------|-------------|
|
|
491
|
-
| `EUNSPECIFIED` | An unspecified error occurred |
|
|
492
|
-
|
|
493
|
-
The error code is available on the `code` property of the rejected error:
|
|
494
|
-
|
|
495
|
-
```js
|
|
496
|
-
try {
|
|
497
|
-
await DashX.fetchRecord('article/123');
|
|
498
|
-
} catch (error) {
|
|
499
|
-
console.log(error.code); // "EUNSPECIFIED"
|
|
500
|
-
console.log(error.message); // human-readable description
|
|
501
|
-
}
|
|
502
|
-
```
|
|
503
|
-
|
|
504
|
-
A `DashXErrorCode` enum is exported from the TypeScript definitions for type-safe comparisons.
|
|
51
|
+
See the [Deep Linking & Push Navigation](https://docs.dashx.com/apps/messaging/deep-linking) guide for setup instructions, payload fields, and code examples.
|
|
505
52
|
|
|
506
53
|
## Contributing
|
|
507
54
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
You'll also need Apollo CLI to generate files:
|
|
511
|
-
|
|
512
|
-
```sh
|
|
513
|
-
npm i -g apollo
|
|
514
|
-
```
|
|
515
|
-
|
|
516
|
-
## Publishing
|
|
517
|
-
|
|
518
|
-
Use `yarn publish` to bump the version and release, then push the commit:
|
|
519
|
-
|
|
520
|
-
```sh
|
|
521
|
-
yarn publish
|
|
522
|
-
git push origin main
|
|
523
|
-
```
|
|
55
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and workflow.
|
|
524
56
|
|
|
525
57
|
## License
|
|
526
58
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const mockNativeModule = {
|
|
2
|
+
configure: jest.fn(),
|
|
3
|
+
identify: jest.fn(),
|
|
4
|
+
setIdentity: jest.fn(),
|
|
5
|
+
reset: jest.fn(),
|
|
6
|
+
track: jest.fn(),
|
|
7
|
+
screen: jest.fn(),
|
|
8
|
+
fetchRecord: jest.fn(),
|
|
9
|
+
searchRecords: jest.fn(),
|
|
10
|
+
fetchStoredPreferences: jest.fn(),
|
|
11
|
+
saveStoredPreferences: jest.fn(),
|
|
12
|
+
subscribe: jest.fn(),
|
|
13
|
+
unsubscribe: jest.fn(),
|
|
14
|
+
setLogLevel: jest.fn(),
|
|
15
|
+
uploadAsset: jest.fn(),
|
|
16
|
+
fetchAsset: jest.fn(),
|
|
17
|
+
enableLifecycleTracking: jest.fn(),
|
|
18
|
+
enableAdTracking: jest.fn(),
|
|
19
|
+
processURL: jest.fn(),
|
|
20
|
+
trackNotificationNavigation: jest.fn(),
|
|
21
|
+
requestNotificationPermission: jest.fn(),
|
|
22
|
+
getNotificationPermissionStatus: jest.fn(),
|
|
23
|
+
addListener: jest.fn(),
|
|
24
|
+
removeListeners: jest.fn(),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
jest.mock('react-native', () => ({
|
|
28
|
+
NativeModules: {
|
|
29
|
+
DashXReactNative: mockNativeModule,
|
|
30
|
+
},
|
|
31
|
+
NativeEventEmitter: jest.fn().mockImplementation(() => ({
|
|
32
|
+
addListener: jest.fn(() => ({ remove: jest.fn() })),
|
|
33
|
+
})),
|
|
34
|
+
Platform: {
|
|
35
|
+
OS: 'ios',
|
|
36
|
+
select: jest.fn((obj) => obj.default || ''),
|
|
37
|
+
},
|
|
38
|
+
TurboModuleRegistry: {
|
|
39
|
+
get: jest.fn(() => null),
|
|
40
|
+
getEnforcing: jest.fn(() => {
|
|
41
|
+
throw new Error('not available');
|
|
42
|
+
}),
|
|
43
|
+
},
|
|
44
|
+
}));
|
|
45
|
+
|
|
46
|
+
// TurboModule returns null -> should fall back to NativeModules
|
|
47
|
+
jest.mock('../src/NativeDashXReactNative', () => ({
|
|
48
|
+
__esModule: true,
|
|
49
|
+
default: null,
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
const DashX = require('../index').default;
|
|
53
|
+
|
|
54
|
+
describe('NativeModules fallback', () => {
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
jest.clearAllMocks();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('falls back to NativeModules.DashXReactNative when TurboModule is null', () => {
|
|
60
|
+
DashX.configure({ publicKey: 'pk_test' });
|
|
61
|
+
expect(mockNativeModule.configure).toHaveBeenCalledWith({
|
|
62
|
+
publicKey: 'pk_test',
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('calls track on the fallback module', () => {
|
|
67
|
+
DashX.track('event_name', { key: 'value' });
|
|
68
|
+
expect(mockNativeModule.track).toHaveBeenCalledWith('event_name', {
|
|
69
|
+
key: 'value',
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|