@dashx/react-native 1.1.5 → 1.3.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/.gitignore +1 -1
- package/CHANGELOG.md +34 -0
- package/DashXReactNative.podspec +12 -26
- package/README.md +3 -1
- package/__tests__/fallback.test.js +72 -0
- package/__tests__/index.test.js +46 -5
- 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 +24 -2
- package/index.js +22 -11
- package/ios/DashXNotificationHandler.swift +257 -0
- package/ios/DashXReactNative-Bridging-Header.h +0 -2
- package/ios/DashXReactNative.mm +32 -9
- package/ios/DashXReactNative.swift +27 -19
- 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/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
|
|
2
|
+
import NativeDashXReactNative from './src/NativeDashXReactNative';
|
|
2
3
|
|
|
3
4
|
function getLinkingError() {
|
|
4
5
|
return (
|
|
@@ -12,8 +13,10 @@ function getLinkingError() {
|
|
|
12
13
|
let _nativeDashX = null;
|
|
13
14
|
function getNativeDashX() {
|
|
14
15
|
if (!_nativeDashX) {
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
const nativeModule =
|
|
17
|
+
NativeDashXReactNative || NativeModules.DashXReactNative;
|
|
18
|
+
_nativeDashX = nativeModule
|
|
19
|
+
? nativeModule
|
|
17
20
|
: new Proxy(
|
|
18
21
|
{},
|
|
19
22
|
{
|
|
@@ -55,17 +58,16 @@ const DashX = {
|
|
|
55
58
|
},
|
|
56
59
|
|
|
57
60
|
setIdentity(uid, token) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
// Both uid and token are nullable passthroughs to the native SDK. Only
|
|
62
|
+
// validate TYPE here — the native side decides semantics. `undefined` is
|
|
63
|
+
// normalized to `null` because the RN bridge can't carry undefined.
|
|
64
|
+
if (uid !== null && uid !== undefined && typeof uid !== 'string') {
|
|
65
|
+
throw new Error('DashX.setIdentity: uid must be a string or null');
|
|
62
66
|
}
|
|
63
|
-
if (
|
|
64
|
-
throw new Error(
|
|
65
|
-
'DashX.setIdentity: token is required and must be a string'
|
|
66
|
-
);
|
|
67
|
+
if (token !== null && token !== undefined && typeof token !== 'string') {
|
|
68
|
+
throw new Error('DashX.setIdentity: token must be a string or null');
|
|
67
69
|
}
|
|
68
|
-
return getNativeDashX().setIdentity(uid, token);
|
|
70
|
+
return getNativeDashX().setIdentity(uid ?? null, token ?? null);
|
|
69
71
|
},
|
|
70
72
|
|
|
71
73
|
reset() {
|
|
@@ -216,6 +218,15 @@ const DashX = {
|
|
|
216
218
|
}
|
|
217
219
|
return getEventEmitter().addListener('linkReceived', callback);
|
|
218
220
|
},
|
|
221
|
+
|
|
222
|
+
onNotificationClicked(callback) {
|
|
223
|
+
if (typeof callback !== 'function') {
|
|
224
|
+
throw new Error(
|
|
225
|
+
'DashX.onNotificationClicked: callback must be a function'
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
return getEventEmitter().addListener('notificationClicked', callback);
|
|
229
|
+
},
|
|
219
230
|
};
|
|
220
231
|
|
|
221
232
|
export default DashX;
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import UIKit
|
|
3
|
+
import UserNotifications
|
|
4
|
+
import DashX
|
|
5
|
+
import FirebaseMessaging
|
|
6
|
+
|
|
7
|
+
/// The result of handling a notification response.
|
|
8
|
+
/// Consumers can use `url` to navigate and `actionIdentifier` for custom action handling.
|
|
9
|
+
@objc(DashXNotificationResponseResult)
|
|
10
|
+
public final class DashXNotificationResponseResult: NSObject {
|
|
11
|
+
@objc public let userInfo: [AnyHashable: Any]
|
|
12
|
+
@objc public let actionIdentifier: String
|
|
13
|
+
/// The DashX notification URL, if present in the payload.
|
|
14
|
+
@objc public let url: URL?
|
|
15
|
+
/// The resolved navigation intent for the tap / action button.
|
|
16
|
+
/// Non-@objc (the enum isn't representable in Obj-C); read via Swift.
|
|
17
|
+
public let navigationAction: NavigationAction?
|
|
18
|
+
|
|
19
|
+
init(userInfo: [AnyHashable: Any], actionIdentifier: String, url: URL?, navigationAction: NavigationAction?) {
|
|
20
|
+
self.userInfo = userInfo
|
|
21
|
+
self.actionIdentifier = actionIdentifier
|
|
22
|
+
self.url = url
|
|
23
|
+
self.navigationAction = navigationAction
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@objc(DashXNotificationHandler)
|
|
28
|
+
public final class DashXNotificationHandler: NSObject {
|
|
29
|
+
|
|
30
|
+
@objc
|
|
31
|
+
public static func handleRemoteNotification(
|
|
32
|
+
userInfo: [AnyHashable: Any],
|
|
33
|
+
completionHandler: @escaping (UIBackgroundFetchResult) -> Void
|
|
34
|
+
) {
|
|
35
|
+
Messaging.messaging().appDidReceiveMessage(userInfo)
|
|
36
|
+
|
|
37
|
+
DashXEventEmitter.instance.dispatch(
|
|
38
|
+
name: "messageReceived",
|
|
39
|
+
body: bridgeSafePayload(from: userInfo)
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
guard let dashxData = userInfo.dashxNotificationData() else {
|
|
43
|
+
completionHandler(.noData)
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
DashX.trackMessage(message: userInfo, event: .delivered)
|
|
48
|
+
|
|
49
|
+
let content = UNMutableNotificationContent()
|
|
50
|
+
content.sound = UNNotificationSound.default
|
|
51
|
+
content.title = dashxData.title
|
|
52
|
+
content.body = dashxData.body
|
|
53
|
+
content.userInfo = userInfo
|
|
54
|
+
content.categoryIdentifier = Constants.DASHX_NOTIFICATION_CATEGORY_IDENTIFIER
|
|
55
|
+
|
|
56
|
+
var actions: [UNNotificationAction] = []
|
|
57
|
+
if let actionButtons = dashxData.actionButtons {
|
|
58
|
+
for button in actionButtons {
|
|
59
|
+
actions.append(
|
|
60
|
+
UNNotificationAction(
|
|
61
|
+
identifier: button.identifier,
|
|
62
|
+
title: button.label,
|
|
63
|
+
options: [.foreground]
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let category = UNNotificationCategory(
|
|
70
|
+
identifier: Constants.DASHX_NOTIFICATION_CATEGORY_IDENTIFIER,
|
|
71
|
+
actions: actions,
|
|
72
|
+
intentIdentifiers: [],
|
|
73
|
+
options: .customDismissAction
|
|
74
|
+
)
|
|
75
|
+
UNUserNotificationCenter.current().setNotificationCategories([category])
|
|
76
|
+
|
|
77
|
+
if let imagePath = dashxData.image, let imageURL = URL(string: imagePath) {
|
|
78
|
+
createNotificationWithImage(id: dashxData.id, imageURL: imageURL, content: content)
|
|
79
|
+
} else {
|
|
80
|
+
createNotification(id: dashxData.id, content: content)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
completionHandler(.newData)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@objc
|
|
87
|
+
@discardableResult
|
|
88
|
+
public static func handleNotificationResponse(_ response: UNNotificationResponse) -> DashXNotificationResponseResult {
|
|
89
|
+
let userInfo = response.notification.request.content.userInfo
|
|
90
|
+
|
|
91
|
+
Messaging.messaging().appDidReceiveMessage(userInfo)
|
|
92
|
+
|
|
93
|
+
DashXEventEmitter.instance.dispatch(
|
|
94
|
+
name: "messageReceived",
|
|
95
|
+
body: bridgeSafePayload(from: userInfo)
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
if response.actionIdentifier == UNNotificationDismissActionIdentifier {
|
|
99
|
+
DashX.trackMessage(message: userInfo, event: .dismissed)
|
|
100
|
+
} else {
|
|
101
|
+
DashX.trackMessage(message: userInfo, event: .clicked)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let notificationUrl = userInfo.dashxNotificationUrl()
|
|
105
|
+
let dashxData = userInfo.dashxNotificationData()
|
|
106
|
+
let navigationAction = dashxData?.navigationAction(forActionIdentifier: response.actionIdentifier)
|
|
107
|
+
|
|
108
|
+
if response.actionIdentifier != UNNotificationDismissActionIdentifier {
|
|
109
|
+
DashXEventEmitter.instance.dispatch(
|
|
110
|
+
name: "notificationClicked",
|
|
111
|
+
body: [
|
|
112
|
+
"notification": bridgeSafePayload(from: userInfo),
|
|
113
|
+
"action": jsonDictionary(from: navigationAction) ?? NSNull(),
|
|
114
|
+
"actionIdentifier": response.actionIdentifier,
|
|
115
|
+
]
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return DashXNotificationResponseResult(
|
|
120
|
+
userInfo: userInfo,
|
|
121
|
+
actionIdentifier: response.actionIdentifier,
|
|
122
|
+
url: notificationUrl,
|
|
123
|
+
navigationAction: navigationAction
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// MARK: - Device Token
|
|
128
|
+
|
|
129
|
+
/// Bridges the APNS device token to Firebase Cloud Messaging and registers
|
|
130
|
+
/// the FCM token with DashX. Call this from
|
|
131
|
+
/// `application(_:didRegisterForRemoteNotificationsWithDeviceToken:)`.
|
|
132
|
+
@objc
|
|
133
|
+
public static func handleDeviceToken(_ deviceToken: Data) {
|
|
134
|
+
// Force the APNs environment explicitly rather than using `.unknown`
|
|
135
|
+
// (auto-detect). Firebase's auto-detection reads the token's aps
|
|
136
|
+
// entitlement from the signed binary and sometimes mis-tags dev
|
|
137
|
+
// builds as production, producing an FCM token whose pushes silently
|
|
138
|
+
// fail at APNs with 410 Unregistered.
|
|
139
|
+
#if DEBUG
|
|
140
|
+
Messaging.messaging().setAPNSToken(deviceToken, type: .sandbox)
|
|
141
|
+
#else
|
|
142
|
+
Messaging.messaging().setAPNSToken(deviceToken, type: .prod)
|
|
143
|
+
#endif
|
|
144
|
+
Messaging.messaging().token { token, error in
|
|
145
|
+
if let token = token {
|
|
146
|
+
DashX.setFCMToken(to: token)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// MARK: - Foreground Notification
|
|
152
|
+
|
|
153
|
+
/// Handles a notification that arrived while the app is in the foreground.
|
|
154
|
+
/// Tracks the delivery event, emits `messageReceived` to JS, forwards to
|
|
155
|
+
/// Firebase analytics, and presents the notification as a banner with sound.
|
|
156
|
+
/// Call this from `userNotificationCenter(_:willPresent:withCompletionHandler:)`.
|
|
157
|
+
@objc
|
|
158
|
+
public static func handleForegroundNotification(
|
|
159
|
+
_ notification: UNNotification,
|
|
160
|
+
completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
|
|
161
|
+
) {
|
|
162
|
+
let userInfo = notification.request.content.userInfo
|
|
163
|
+
|
|
164
|
+
Messaging.messaging().appDidReceiveMessage(userInfo)
|
|
165
|
+
|
|
166
|
+
DashX.trackMessage(message: userInfo, event: .delivered)
|
|
167
|
+
|
|
168
|
+
DashXEventEmitter.instance.dispatch(
|
|
169
|
+
name: "messageReceived",
|
|
170
|
+
body: bridgeSafePayload(from: userInfo)
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
completionHandler([.banner, .sound])
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// MARK: - Private Helpers
|
|
177
|
+
|
|
178
|
+
private static func createNotification(id: String, content: UNMutableNotificationContent) {
|
|
179
|
+
let request = UNNotificationRequest(identifier: id, content: content, trigger: nil)
|
|
180
|
+
UNUserNotificationCenter.current().add(request) { error in
|
|
181
|
+
if let error = error {
|
|
182
|
+
DashXLog.d(tag: #function, "Failed to schedule notification: \(error.localizedDescription)")
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
private static func createNotificationWithImage(
|
|
188
|
+
id: String,
|
|
189
|
+
imageURL: URL,
|
|
190
|
+
content: UNMutableNotificationContent
|
|
191
|
+
) {
|
|
192
|
+
let task = URLSession.shared.downloadTask(with: imageURL) { location, _, error in
|
|
193
|
+
guard let location = location, error == nil else {
|
|
194
|
+
createNotification(id: id, content: content)
|
|
195
|
+
return
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
let tmpDir = FileManager.default.temporaryDirectory
|
|
199
|
+
let tmpFile = tmpDir.appendingPathComponent(UUID().uuidString + ".png")
|
|
200
|
+
|
|
201
|
+
do {
|
|
202
|
+
try FileManager.default.moveItem(at: location, to: tmpFile)
|
|
203
|
+
let attachment = try UNNotificationAttachment(
|
|
204
|
+
identifier: "\(id)-attachment",
|
|
205
|
+
url: tmpFile,
|
|
206
|
+
options: nil
|
|
207
|
+
)
|
|
208
|
+
content.attachments = [attachment]
|
|
209
|
+
createNotification(id: id, content: content)
|
|
210
|
+
} catch {
|
|
211
|
+
createNotification(id: id, content: content)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
task.resume()
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/// Serializes a ``NavigationAction`` into the JS-bridge shape mirrored by
|
|
218
|
+
/// `NavigationAction` in `index.d.ts`. Returns `nil` for `nil` input.
|
|
219
|
+
private static func jsonDictionary(from action: NavigationAction?) -> [String: Any]? {
|
|
220
|
+
guard let action else { return nil }
|
|
221
|
+
switch action {
|
|
222
|
+
case .deepLink(let url):
|
|
223
|
+
return ["type": "deepLink", "url": url.absoluteString]
|
|
224
|
+
case .screen(let name, let data):
|
|
225
|
+
var dict: [String: Any] = ["type": "screen", "name": name]
|
|
226
|
+
if let data { dict["data"] = data }
|
|
227
|
+
return dict
|
|
228
|
+
case .richLanding(let url):
|
|
229
|
+
return ["type": "richLanding", "url": url.absoluteString]
|
|
230
|
+
case .clickAction(let actionString):
|
|
231
|
+
return ["type": "clickAction", "action": actionString]
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private static func bridgeSafePayload(from userInfo: [AnyHashable: Any]) -> [String: Any] {
|
|
236
|
+
userInfo.reduce(into: [String: Any]()) { result, pair in
|
|
237
|
+
let key = String(describing: pair.key)
|
|
238
|
+
let value = pair.value
|
|
239
|
+
if let str = value as? String {
|
|
240
|
+
result[key] = str
|
|
241
|
+
} else if let num = value as? NSNumber {
|
|
242
|
+
result[key] = num
|
|
243
|
+
} else if let dict = value as? [AnyHashable: Any] {
|
|
244
|
+
result[key] = bridgeSafePayload(from: dict)
|
|
245
|
+
} else if let arr = value as? [Any] {
|
|
246
|
+
result[key] = arr.map { item -> Any in
|
|
247
|
+
if let str = item as? String { return str }
|
|
248
|
+
if let num = item as? NSNumber { return num }
|
|
249
|
+
if let d = item as? [AnyHashable: Any] { return bridgeSafePayload(from: d) }
|
|
250
|
+
return "\(item)"
|
|
251
|
+
}
|
|
252
|
+
} else {
|
|
253
|
+
result[key] = "\(value)"
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
package/ios/DashXReactNative.mm
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
#import <React/RCTBridgeModule.h>
|
|
2
2
|
#import <React/RCTEventEmitter.h>
|
|
3
3
|
|
|
4
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
5
|
+
#import "RNDashXReactNativeSpec.h"
|
|
6
|
+
#endif
|
|
7
|
+
|
|
4
8
|
@interface RCT_EXTERN_MODULE(DashXReactNative, RCTEventEmitter)
|
|
5
9
|
|
|
6
10
|
RCT_EXTERN_METHOD(configure:(NSDictionary *)options);
|
|
@@ -13,13 +17,13 @@ RCT_EXTERN_METHOD(track:(NSString *)event data:(NSDictionary * _Nullable)data);
|
|
|
13
17
|
|
|
14
18
|
RCT_EXTERN_METHOD(screen:(NSString *)screenName data:(NSDictionary * _Nullable)data);
|
|
15
19
|
|
|
16
|
-
RCT_EXTERN_METHOD(fetchRecord:(NSString *)urn options:(NSDictionary * _Nullable)options
|
|
20
|
+
RCT_EXTERN_METHOD(fetchRecord:(NSString *)urn options:(NSDictionary * _Nullable)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
17
21
|
|
|
18
|
-
RCT_EXTERN_METHOD(searchRecords:(NSString *)resource options:(NSDictionary * _Nullable)options
|
|
22
|
+
RCT_EXTERN_METHOD(searchRecords:(NSString *)resource options:(NSDictionary * _Nullable)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
19
23
|
|
|
20
|
-
RCT_EXTERN_METHOD(fetchStoredPreferences:(RCTPromiseResolveBlock)resolve
|
|
24
|
+
RCT_EXTERN_METHOD(fetchStoredPreferences:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
21
25
|
|
|
22
|
-
RCT_EXTERN_METHOD(saveStoredPreferences:(NSDictionary *)preferenceData
|
|
26
|
+
RCT_EXTERN_METHOD(saveStoredPreferences:(NSDictionary *)preferenceData resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
23
27
|
|
|
24
28
|
RCT_EXTERN_METHOD(reset);
|
|
25
29
|
|
|
@@ -27,18 +31,37 @@ RCT_EXTERN_METHOD(subscribe);
|
|
|
27
31
|
|
|
28
32
|
RCT_EXTERN_METHOD(unsubscribe);
|
|
29
33
|
|
|
30
|
-
RCT_EXTERN_METHOD(setLogLevel:(
|
|
34
|
+
RCT_EXTERN_METHOD(setLogLevel:(double)level);
|
|
31
35
|
|
|
32
|
-
RCT_EXTERN_METHOD(uploadAsset:(NSString *)filePath resource:(NSString *)resource attribute:(NSString *)attribute
|
|
36
|
+
RCT_EXTERN_METHOD(uploadAsset:(NSString *)filePath resource:(NSString *)resource attribute:(NSString *)attribute resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
33
37
|
|
|
34
|
-
RCT_EXTERN_METHOD(fetchAsset:(NSString *)assetId
|
|
38
|
+
RCT_EXTERN_METHOD(fetchAsset:(NSString *)assetId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
35
39
|
|
|
36
40
|
RCT_EXTERN_METHOD(enableLifecycleTracking);
|
|
37
41
|
|
|
38
42
|
RCT_EXTERN_METHOD(enableAdTracking);
|
|
39
43
|
|
|
40
|
-
RCT_EXTERN_METHOD(
|
|
44
|
+
RCT_EXTERN_METHOD(processURL:(NSString *)url source:(NSString * _Nullable)source forwardToLinkHandler:(BOOL)forwardToLinkHandler);
|
|
45
|
+
|
|
46
|
+
RCT_EXTERN_METHOD(trackNotificationNavigation:(NSDictionary * _Nullable)action notificationId:(NSString * _Nullable)notificationId);
|
|
47
|
+
|
|
48
|
+
RCT_EXTERN_METHOD(requestNotificationPermission:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
49
|
+
|
|
50
|
+
RCT_EXTERN_METHOD(getNotificationPermissionStatus:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
51
|
+
|
|
52
|
+
@end
|
|
53
|
+
|
|
54
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
55
|
+
@interface DashXReactNative () <NativeDashXReactNativeSpec>
|
|
56
|
+
@end
|
|
57
|
+
|
|
58
|
+
@implementation DashXReactNative (TurboModule)
|
|
41
59
|
|
|
42
|
-
|
|
60
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
61
|
+
(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
62
|
+
{
|
|
63
|
+
return std::make_shared<facebook::react::NativeDashXReactNativeSpecJSI>(params);
|
|
64
|
+
}
|
|
43
65
|
|
|
44
66
|
@end
|
|
67
|
+
#endif
|
|
@@ -16,7 +16,7 @@ class DashXReactNative: RCTEventEmitter {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
override func supportedEvents() -> [String] {
|
|
19
|
-
return ["messageReceived", "linkReceived"]
|
|
19
|
+
return ["messageReceived", "linkReceived", "notificationClicked"]
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
@objc(configure:)
|
|
@@ -60,8 +60,8 @@ class DashXReactNative: RCTEventEmitter {
|
|
|
60
60
|
DashX.screen(screenName, withData: data as? [String: Any])
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
@objc(fetchRecord:options:
|
|
64
|
-
func fetchRecord(_ urn: String, options: NSDictionary?,
|
|
63
|
+
@objc(fetchRecord:options:resolve:reject:)
|
|
64
|
+
func fetchRecord(_ urn: String, options: NSDictionary?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
65
65
|
DashXClient.instance.fetchRecord(
|
|
66
66
|
urn: urn,
|
|
67
67
|
preview: options?["preview"] as? Bool,
|
|
@@ -77,8 +77,8 @@ class DashXReactNative: RCTEventEmitter {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
@objc(searchRecords:options:
|
|
81
|
-
func searchRecords(_ resource: String, options: NSDictionary?,
|
|
80
|
+
@objc(searchRecords:options:resolve:reject:)
|
|
81
|
+
func searchRecords(_ resource: String, options: NSDictionary?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
82
82
|
DashXClient.instance.searchRecords(
|
|
83
83
|
resource: resource,
|
|
84
84
|
filter: options?["filter"] as? [String: Any],
|
|
@@ -98,8 +98,8 @@ class DashXReactNative: RCTEventEmitter {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
@objc(fetchStoredPreferences:
|
|
102
|
-
func fetchStoredPreferences(_ resolve: @escaping RCTPromiseResolveBlock,
|
|
101
|
+
@objc(fetchStoredPreferences:reject:)
|
|
102
|
+
func fetchStoredPreferences(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
103
103
|
DashXClient.instance.fetchStoredPreferences { result in
|
|
104
104
|
switch result {
|
|
105
105
|
case .success(let prefs): resolve(prefs)
|
|
@@ -108,8 +108,8 @@ class DashXReactNative: RCTEventEmitter {
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
@objc(saveStoredPreferences:
|
|
112
|
-
func saveStoredPreferences(_ preferenceData: NSDictionary,
|
|
111
|
+
@objc(saveStoredPreferences:resolve:reject:)
|
|
112
|
+
func saveStoredPreferences(_ preferenceData: NSDictionary, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
113
113
|
guard let dict = preferenceData as? [String: Any] else {
|
|
114
114
|
reject("EINVAL", "preferenceData must be a plain object", nil)
|
|
115
115
|
return
|
|
@@ -133,13 +133,21 @@ class DashXReactNative: RCTEventEmitter {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
@objc(setLogLevel:)
|
|
136
|
-
func setLogLevel(_ level:
|
|
137
|
-
|
|
136
|
+
func setLogLevel(_ level: Double) {
|
|
137
|
+
// JS contract: 0 = off, 1 = errors, 2 = debug
|
|
138
|
+
// Native SDK: off = -1, error = 0, info = 1, debug = 2
|
|
139
|
+
let logLevel: DashXLog.LogLevel
|
|
140
|
+
switch Int(level) {
|
|
141
|
+
case 0: logLevel = .off
|
|
142
|
+
case 1: logLevel = .error
|
|
143
|
+
case 2: logLevel = .debug
|
|
144
|
+
default: logLevel = .off
|
|
145
|
+
}
|
|
138
146
|
DashXLog.setLogLevel(to: logLevel)
|
|
139
147
|
}
|
|
140
148
|
|
|
141
|
-
@objc(uploadAsset:resource:attribute:
|
|
142
|
-
func uploadAsset(_ filePath: String, resource: String, attribute: String,
|
|
149
|
+
@objc(uploadAsset:resource:attribute:resolve:reject:)
|
|
150
|
+
func uploadAsset(_ filePath: String, resource: String, attribute: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
143
151
|
let fileURL = URL(fileURLWithPath: filePath)
|
|
144
152
|
DashXClient.instance.uploadAsset(fileURL: fileURL, resource: resource, attribute: attribute) { result in
|
|
145
153
|
switch result {
|
|
@@ -156,8 +164,8 @@ class DashXReactNative: RCTEventEmitter {
|
|
|
156
164
|
}
|
|
157
165
|
}
|
|
158
166
|
|
|
159
|
-
@objc(fetchAsset:
|
|
160
|
-
func fetchAsset(_ assetId: String,
|
|
167
|
+
@objc(fetchAsset:resolve:reject:)
|
|
168
|
+
func fetchAsset(_ assetId: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
161
169
|
DashXClient.instance.fetchAsset(assetId: assetId) { result in
|
|
162
170
|
switch result {
|
|
163
171
|
case .success(let assetResponse):
|
|
@@ -217,13 +225,13 @@ class DashXReactNative: RCTEventEmitter {
|
|
|
217
225
|
DashX.trackNotificationNavigation(navigationAction, notificationId: notificationId as String?)
|
|
218
226
|
}
|
|
219
227
|
|
|
220
|
-
@objc(requestNotificationPermission:
|
|
221
|
-
func requestNotificationPermission(_ resolve: @escaping RCTPromiseResolveBlock,
|
|
228
|
+
@objc(requestNotificationPermission:reject:)
|
|
229
|
+
func requestNotificationPermission(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
222
230
|
DashX.requestNotificationPermission { status in resolve(status.rawValue) }
|
|
223
231
|
}
|
|
224
232
|
|
|
225
|
-
@objc(getNotificationPermissionStatus:
|
|
226
|
-
func getNotificationPermissionStatus(_ resolve: @escaping RCTPromiseResolveBlock,
|
|
233
|
+
@objc(getNotificationPermissionStatus:reject:)
|
|
234
|
+
func getNotificationPermissionStatus(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
227
235
|
DashX.getNotificationPermissionStatus { status in resolve(status.rawValue) }
|
|
228
236
|
}
|
|
229
237
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dashx/react-native",
|
|
3
3
|
"title": "DashX React Native",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.3.0",
|
|
5
5
|
"description": "DashX SDK for React Native",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"types": "index.d.ts",
|
|
@@ -22,8 +22,17 @@
|
|
|
22
22
|
"index.js",
|
|
23
23
|
"index.d.ts",
|
|
24
24
|
"ios",
|
|
25
|
+
"src",
|
|
25
26
|
"README.md"
|
|
26
27
|
],
|
|
28
|
+
"codegenConfig": {
|
|
29
|
+
"name": "RNDashXReactNativeSpec",
|
|
30
|
+
"type": "modules",
|
|
31
|
+
"jsSrcsDir": "src",
|
|
32
|
+
"android": {
|
|
33
|
+
"javaPackageName": "com.dashx.rn.sdk"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
27
36
|
"scripts": {
|
|
28
37
|
"test": "jest",
|
|
29
38
|
"lint": "eslint index.js"
|
|
@@ -49,7 +58,7 @@
|
|
|
49
58
|
},
|
|
50
59
|
"peerDependencies": {
|
|
51
60
|
"react": ">=17.0.0",
|
|
52
|
-
"react-native": ">=0.
|
|
61
|
+
"react-native": ">=0.74.0"
|
|
53
62
|
},
|
|
54
63
|
"devDependencies": {
|
|
55
64
|
"@commitlint/config-conventional": "^17.0.2",
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { TurboModule } from 'react-native';
|
|
2
|
+
import { TurboModuleRegistry } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export interface Spec extends TurboModule {
|
|
5
|
+
configure(options: Object): void;
|
|
6
|
+
identify(options: Object | null): void;
|
|
7
|
+
setIdentity(uid: string | null, token: string | null): void;
|
|
8
|
+
reset(): void;
|
|
9
|
+
track(event: string, data: Object | null): void;
|
|
10
|
+
screen(screenName: string, data: Object | null): void;
|
|
11
|
+
fetchRecord(urn: string, options: Object | null): Promise<Object>;
|
|
12
|
+
searchRecords(resource: string, options: Object | null): Promise<Object[]>;
|
|
13
|
+
fetchStoredPreferences(): Promise<Object>;
|
|
14
|
+
saveStoredPreferences(preferenceData: Object): Promise<Object>;
|
|
15
|
+
subscribe(): void;
|
|
16
|
+
unsubscribe(): void;
|
|
17
|
+
setLogLevel(level: number): void;
|
|
18
|
+
uploadAsset(
|
|
19
|
+
filePath: string,
|
|
20
|
+
resource: string,
|
|
21
|
+
attribute: string
|
|
22
|
+
): Promise<Object>;
|
|
23
|
+
fetchAsset(assetId: string): Promise<Object>;
|
|
24
|
+
enableLifecycleTracking(): void;
|
|
25
|
+
enableAdTracking(): void;
|
|
26
|
+
processURL(
|
|
27
|
+
url: string,
|
|
28
|
+
source: string | null,
|
|
29
|
+
forwardToLinkHandler: boolean
|
|
30
|
+
): void;
|
|
31
|
+
trackNotificationNavigation(
|
|
32
|
+
action: Object | null,
|
|
33
|
+
notificationId: string | null
|
|
34
|
+
): void;
|
|
35
|
+
requestNotificationPermission(): Promise<number>;
|
|
36
|
+
getNotificationPermissionStatus(): Promise<number>;
|
|
37
|
+
|
|
38
|
+
addListener(eventName: string): void;
|
|
39
|
+
removeListeners(count: number): void;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default TurboModuleRegistry.get<Spec>('DashXReactNative');
|