@dashx/react-native 1.5.0 → 1.5.1
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 +1 -1
- package/ios/DashXReactNative.mm +7 -7
- package/ios/DashXReactNative.swift +15 -11
- package/package.json +13 -11
- package/.claude/settings.local.json +0 -7
- package/.claude/worktrees/autocapture-conventions-review-78f665/.gitattributes +0 -1
- package/.claude/worktrees/autocapture-conventions-review-78f665/.github/workflows/ci.yml +0 -67
- package/.claude/worktrees/autocapture-conventions-review-78f665/.gitignore +0 -49
- package/.claude/worktrees/autocapture-conventions-review-78f665/.nvmrc +0 -1
- package/.claude/worktrees/autocapture-conventions-review-78f665/CHANGELOG.md +0 -144
- package/.claude/worktrees/autocapture-conventions-review-78f665/CONTRIBUTING.md +0 -190
- package/.claude/worktrees/autocapture-conventions-review-78f665/DashXReactNative.podspec +0 -38
- package/.claude/worktrees/autocapture-conventions-review-78f665/LICENSE +0 -21
- package/.claude/worktrees/autocapture-conventions-review-78f665/README.md +0 -97
- package/.claude/worktrees/autocapture-conventions-review-78f665/__tests__/fallback.test.js +0 -72
- package/.claude/worktrees/autocapture-conventions-review-78f665/__tests__/index.test.js +0 -702
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gitignore +0 -10
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/8.14.3/checksums/checksums.lock +0 -0
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/8.14.3/fileChanges/last-build.bin +0 -0
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/8.14.3/fileHashes/fileHashes.lock +0 -0
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/8.14.3/gc.properties +0 -0
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/buildOutputCleanup/cache.properties +0 -2
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/vcs-1/gc.properties +0 -0
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/build/reports/problems/problems-report.html +0 -663
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/build.gradle +0 -121
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/gradle/wrapper/gradle-wrapper.properties +0 -6
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/gradle.properties +0 -1
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/gradlew +0 -185
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/gradlew.bat +0 -89
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/settings.gradle +0 -27
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/AndroidManifest.xml +0 -19
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/DashXNotificationClickedListener.kt +0 -113
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/DashXReactNativeFirebaseMessagingService.kt +0 -72
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/DashXReactNativeModuleImpl.kt +0 -445
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/MessageReceivedEventHolder.kt +0 -14
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/ReactNativeLibraryInfoProvider.kt +0 -8
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/util/Utils.kt +0 -208
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/resources/META-INF/services/com.dashx.android.DashXLibraryInfoProvider +0 -1
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/newarch/java/com/dashx/rn/sdk/DashXReactNativeModule.kt +0 -85
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/newarch/java/com/dashx/rn/sdk/DashXReactNativePackage.kt +0 -33
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/oldarch/java/com/dashx/rn/sdk/DashXReactNativeModule.kt +0 -106
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/oldarch/java/com/dashx/rn/sdk/DashXReactNativePackage.kt +0 -33
- package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/test/java/com/dashx/rn/sdk/util/UtilsTest.kt +0 -305
- package/.claude/worktrees/autocapture-conventions-review-78f665/babel.config.js +0 -3
- package/.claude/worktrees/autocapture-conventions-review-78f665/index.d.ts +0 -321
- package/.claude/worktrees/autocapture-conventions-review-78f665/index.js +0 -300
- package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXEventEmitter.swift +0 -15
- package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXNotificationHandler.swift +0 -301
- package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative-Bridging-Header.h +0 -3
- package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative.mm +0 -77
- package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative.swift +0 -244
- package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative.xcodeproj/project.pbxproj +0 -280
- package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative.xcworkspace/contents.xcworkspacedata +0 -7
- package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/.claude/worktrees/autocapture-conventions-review-78f665/package.json +0 -123
- package/.claude/worktrees/autocapture-conventions-review-78f665/scripts/generate-bridge-shim.js +0 -259
- package/.claude/worktrees/autocapture-conventions-review-78f665/src/NativeDashXReactNative.ts +0 -42
- package/.claude/worktrees/autocapture-conventions-review-78f665/yarn.lock +0 -6244
- package/.gitattributes +0 -1
- package/.github/workflows/ci.yml +0 -67
- package/.gitignore +0 -49
- package/.nvmrc +0 -1
- package/CHANGELOG.md +0 -144
- package/CONTRIBUTING.md +0 -190
- package/__tests__/fallback.test.js +0 -72
- package/__tests__/index.test.js +0 -702
- package/android/.gitignore +0 -10
- package/android/.gradle/8.14.3/checksums/checksums.lock +0 -0
- package/android/.gradle/8.14.3/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.14.3/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.14.3/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/build/reports/problems/problems-report.html +0 -663
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +0 -6
- package/android/gradlew +0 -185
- package/android/gradlew.bat +0 -89
- package/android/src/test/java/com/dashx/rn/sdk/util/UtilsTest.kt +0 -305
- package/babel.config.js +0 -3
- package/scripts/generate-bridge-shim.js +0 -259
- package/yarn.lock +0 -6244
package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXNotificationHandler.swift
DELETED
|
@@ -1,301 +0,0 @@
|
|
|
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
|
-
// Alert pushes (aps.alert present) are displayed by iOS directly via
|
|
43
|
-
// the Notification Service Extension. Skipping the silent-push
|
|
44
|
-
// reconstruction prevents a duplicate `add()` from racing the
|
|
45
|
-
// system-displayed banner and clobbering its NSE-attached image.
|
|
46
|
-
if let aps = userInfo["aps"] as? [AnyHashable: Any], aps["alert"] != nil {
|
|
47
|
-
completionHandler(.newData)
|
|
48
|
-
return
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
guard let dashxData = userInfo.dashxNotificationData() else {
|
|
52
|
-
completionHandler(.noData)
|
|
53
|
-
return
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
DashX.trackMessage(message: userInfo, event: .delivered)
|
|
57
|
-
|
|
58
|
-
let content = UNMutableNotificationContent()
|
|
59
|
-
content.sound = UNNotificationSound.default
|
|
60
|
-
content.title = dashxData.title
|
|
61
|
-
content.body = dashxData.body
|
|
62
|
-
content.userInfo = userInfo
|
|
63
|
-
content.categoryIdentifier = Constants.DASHX_NOTIFICATION_CATEGORY_IDENTIFIER
|
|
64
|
-
|
|
65
|
-
var actions: [UNNotificationAction] = []
|
|
66
|
-
if let actionButtons = dashxData.actionButtons {
|
|
67
|
-
for button in actionButtons {
|
|
68
|
-
actions.append(
|
|
69
|
-
UNNotificationAction(
|
|
70
|
-
identifier: button.identifier,
|
|
71
|
-
title: button.label,
|
|
72
|
-
options: [.foreground]
|
|
73
|
-
)
|
|
74
|
-
)
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
let category = UNNotificationCategory(
|
|
79
|
-
identifier: Constants.DASHX_NOTIFICATION_CATEGORY_IDENTIFIER,
|
|
80
|
-
actions: actions,
|
|
81
|
-
intentIdentifiers: [],
|
|
82
|
-
options: .customDismissAction
|
|
83
|
-
)
|
|
84
|
-
UNUserNotificationCenter.current().setNotificationCategories([category])
|
|
85
|
-
|
|
86
|
-
// Defer the completion handler until after the local notification has
|
|
87
|
-
// actually been added. iOS suspends the process the moment we call
|
|
88
|
-
// `completionHandler`, so firing it before the async download + add
|
|
89
|
-
// chain finishes was dropping notifications mid-flight. The 25s budget
|
|
90
|
-
// sits comfortably under iOS's ~30s background-push limit.
|
|
91
|
-
let fire = makeOnceFire(completionHandler)
|
|
92
|
-
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(25)) {
|
|
93
|
-
fire(.newData)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if let imagePath = dashxData.image, let imageURL = URL(string: imagePath) {
|
|
97
|
-
createNotificationWithImage(id: dashxData.id, imageURL: imageURL, content: content) {
|
|
98
|
-
fire(.newData)
|
|
99
|
-
}
|
|
100
|
-
} else {
|
|
101
|
-
createNotification(id: dashxData.id, content: content) {
|
|
102
|
-
fire(.newData)
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/// Wraps `completionHandler` so it can be invoked safely from any of the
|
|
108
|
-
/// (download done) / (add done) / (timeout) callbacks — second invocation
|
|
109
|
-
/// is a no-op.
|
|
110
|
-
private static func makeOnceFire(
|
|
111
|
-
_ completionHandler: @escaping (UIBackgroundFetchResult) -> Void
|
|
112
|
-
) -> (UIBackgroundFetchResult) -> Void {
|
|
113
|
-
let lock = NSLock()
|
|
114
|
-
var fired = false
|
|
115
|
-
return { result in
|
|
116
|
-
lock.lock()
|
|
117
|
-
defer { lock.unlock() }
|
|
118
|
-
guard !fired else { return }
|
|
119
|
-
fired = true
|
|
120
|
-
completionHandler(result)
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
@objc
|
|
125
|
-
@discardableResult
|
|
126
|
-
public static func handleNotificationResponse(_ response: UNNotificationResponse) -> DashXNotificationResponseResult {
|
|
127
|
-
let userInfo = response.notification.request.content.userInfo
|
|
128
|
-
|
|
129
|
-
Messaging.messaging().appDidReceiveMessage(userInfo)
|
|
130
|
-
|
|
131
|
-
DashXEventEmitter.instance.dispatch(
|
|
132
|
-
name: "messageReceived",
|
|
133
|
-
body: bridgeSafePayload(from: userInfo)
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
if response.actionIdentifier == UNNotificationDismissActionIdentifier {
|
|
137
|
-
DashX.trackMessage(message: userInfo, event: .dismissed)
|
|
138
|
-
} else {
|
|
139
|
-
DashX.trackMessage(message: userInfo, event: .clicked)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
let notificationUrl = userInfo.dashxNotificationUrl()
|
|
143
|
-
let dashxData = userInfo.dashxNotificationData()
|
|
144
|
-
let navigationAction = dashxData?.navigationAction(forActionIdentifier: response.actionIdentifier)
|
|
145
|
-
|
|
146
|
-
if response.actionIdentifier != UNNotificationDismissActionIdentifier {
|
|
147
|
-
DashXEventEmitter.instance.dispatch(
|
|
148
|
-
name: "notificationClicked",
|
|
149
|
-
body: [
|
|
150
|
-
"notification": bridgeSafePayload(from: userInfo),
|
|
151
|
-
"action": jsonDictionary(from: navigationAction) ?? NSNull(),
|
|
152
|
-
"actionIdentifier": response.actionIdentifier,
|
|
153
|
-
]
|
|
154
|
-
)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return DashXNotificationResponseResult(
|
|
158
|
-
userInfo: userInfo,
|
|
159
|
-
actionIdentifier: response.actionIdentifier,
|
|
160
|
-
url: notificationUrl,
|
|
161
|
-
navigationAction: navigationAction
|
|
162
|
-
)
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// MARK: - Device Token
|
|
166
|
-
|
|
167
|
-
/// Bridges the APNS device token to Firebase Cloud Messaging and registers
|
|
168
|
-
/// the FCM token with DashX. Call this from
|
|
169
|
-
/// `application(_:didRegisterForRemoteNotificationsWithDeviceToken:)`.
|
|
170
|
-
@objc
|
|
171
|
-
public static func handleDeviceToken(_ deviceToken: Data) {
|
|
172
|
-
// Force the APNs environment explicitly rather than using `.unknown`
|
|
173
|
-
// (auto-detect). Firebase's auto-detection reads the token's aps
|
|
174
|
-
// entitlement from the signed binary and sometimes mis-tags dev
|
|
175
|
-
// builds as production, producing an FCM token whose pushes silently
|
|
176
|
-
// fail at APNs with 410 Unregistered.
|
|
177
|
-
#if DEBUG
|
|
178
|
-
Messaging.messaging().setAPNSToken(deviceToken, type: .sandbox)
|
|
179
|
-
#else
|
|
180
|
-
Messaging.messaging().setAPNSToken(deviceToken, type: .prod)
|
|
181
|
-
#endif
|
|
182
|
-
Messaging.messaging().token { token, error in
|
|
183
|
-
if let token = token {
|
|
184
|
-
DashX.setFCMToken(to: token)
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// MARK: - Foreground Notification
|
|
190
|
-
|
|
191
|
-
/// Handles a notification that arrived while the app is in the foreground.
|
|
192
|
-
/// Tracks the delivery event, emits `messageReceived` to JS, forwards to
|
|
193
|
-
/// Firebase analytics, and presents the notification as a banner with sound.
|
|
194
|
-
/// Call this from `userNotificationCenter(_:willPresent:withCompletionHandler:)`.
|
|
195
|
-
@objc
|
|
196
|
-
public static func handleForegroundNotification(
|
|
197
|
-
_ notification: UNNotification,
|
|
198
|
-
completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
|
|
199
|
-
) {
|
|
200
|
-
let userInfo = notification.request.content.userInfo
|
|
201
|
-
|
|
202
|
-
Messaging.messaging().appDidReceiveMessage(userInfo)
|
|
203
|
-
|
|
204
|
-
DashX.trackMessage(message: userInfo, event: .delivered)
|
|
205
|
-
|
|
206
|
-
DashXEventEmitter.instance.dispatch(
|
|
207
|
-
name: "messageReceived",
|
|
208
|
-
body: bridgeSafePayload(from: userInfo)
|
|
209
|
-
)
|
|
210
|
-
|
|
211
|
-
completionHandler([.banner, .sound])
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// MARK: - Private Helpers
|
|
215
|
-
|
|
216
|
-
private static func createNotification(
|
|
217
|
-
id: String,
|
|
218
|
-
content: UNMutableNotificationContent,
|
|
219
|
-
completion: @escaping () -> Void
|
|
220
|
-
) {
|
|
221
|
-
let request = UNNotificationRequest(identifier: id, content: content, trigger: nil)
|
|
222
|
-
UNUserNotificationCenter.current().add(request) { error in
|
|
223
|
-
if let error = error {
|
|
224
|
-
DashXLog.d(tag: #function, "Failed to schedule notification: \(error.localizedDescription)")
|
|
225
|
-
}
|
|
226
|
-
completion()
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
private static func createNotificationWithImage(
|
|
231
|
-
id: String,
|
|
232
|
-
imageURL: URL,
|
|
233
|
-
content: UNMutableNotificationContent,
|
|
234
|
-
completion: @escaping () -> Void
|
|
235
|
-
) {
|
|
236
|
-
let task = URLSession.shared.downloadTask(with: imageURL) { location, _, error in
|
|
237
|
-
guard let location = location, error == nil else {
|
|
238
|
-
createNotification(id: id, content: content, completion: completion)
|
|
239
|
-
return
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
let tmpDir = FileManager.default.temporaryDirectory
|
|
243
|
-
let tmpFile = tmpDir.appendingPathComponent(UUID().uuidString + ".png")
|
|
244
|
-
|
|
245
|
-
do {
|
|
246
|
-
try FileManager.default.moveItem(at: location, to: tmpFile)
|
|
247
|
-
let attachment = try UNNotificationAttachment(
|
|
248
|
-
identifier: "\(id)-attachment",
|
|
249
|
-
url: tmpFile,
|
|
250
|
-
options: nil
|
|
251
|
-
)
|
|
252
|
-
content.attachments = [attachment]
|
|
253
|
-
} catch {
|
|
254
|
-
// fall through with no attachment
|
|
255
|
-
}
|
|
256
|
-
createNotification(id: id, content: content, completion: completion)
|
|
257
|
-
}
|
|
258
|
-
task.resume()
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/// Serializes a ``NavigationAction`` into the JS-bridge shape mirrored by
|
|
262
|
-
/// `NavigationAction` in `index.d.ts`. Returns `nil` for `nil` input.
|
|
263
|
-
private static func jsonDictionary(from action: NavigationAction?) -> [String: Any]? {
|
|
264
|
-
guard let action else { return nil }
|
|
265
|
-
switch action {
|
|
266
|
-
case .deepLink(let url):
|
|
267
|
-
return ["type": "deepLink", "url": url.absoluteString]
|
|
268
|
-
case .screen(let name, let data):
|
|
269
|
-
var dict: [String: Any] = ["type": "screen", "name": name]
|
|
270
|
-
if let data { dict["data"] = data }
|
|
271
|
-
return dict
|
|
272
|
-
case .richLanding(let url):
|
|
273
|
-
return ["type": "richLanding", "url": url.absoluteString]
|
|
274
|
-
case .clickAction(let actionString):
|
|
275
|
-
return ["type": "clickAction", "action": actionString]
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
private static func bridgeSafePayload(from userInfo: [AnyHashable: Any]) -> [String: Any] {
|
|
280
|
-
userInfo.reduce(into: [String: Any]()) { result, pair in
|
|
281
|
-
let key = String(describing: pair.key)
|
|
282
|
-
let value = pair.value
|
|
283
|
-
if let str = value as? String {
|
|
284
|
-
result[key] = str
|
|
285
|
-
} else if let num = value as? NSNumber {
|
|
286
|
-
result[key] = num
|
|
287
|
-
} else if let dict = value as? [AnyHashable: Any] {
|
|
288
|
-
result[key] = bridgeSafePayload(from: dict)
|
|
289
|
-
} else if let arr = value as? [Any] {
|
|
290
|
-
result[key] = arr.map { item -> Any in
|
|
291
|
-
if let str = item as? String { return str }
|
|
292
|
-
if let num = item as? NSNumber { return num }
|
|
293
|
-
if let d = item as? [AnyHashable: Any] { return bridgeSafePayload(from: d) }
|
|
294
|
-
return "\(item)"
|
|
295
|
-
}
|
|
296
|
-
} else {
|
|
297
|
-
result[key] = "\(value)"
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// AUTO-GENERATED FROM DashXReactNative.swift — DO NOT EDIT.
|
|
3
|
-
// Regenerate with `yarn sync-bridge-shim` after editing the Swift file.
|
|
4
|
-
//
|
|
5
|
-
// The Swift class's @objc method declarations are the source of truth.
|
|
6
|
-
// This file mirrors them so old-arch React Native consumers (which discover
|
|
7
|
-
// methods via RCT_EXTERN_METHOD) and new-arch consumers (which dispatch via
|
|
8
|
-
// the codegen-generated TurboModule spec) both find consistent signatures.
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
#import <React/RCTBridgeModule.h>
|
|
12
|
-
#import <React/RCTEventEmitter.h>
|
|
13
|
-
|
|
14
|
-
#ifdef RCT_NEW_ARCH_ENABLED
|
|
15
|
-
#import "RNDashXReactNativeSpec.h"
|
|
16
|
-
#endif
|
|
17
|
-
|
|
18
|
-
@interface RCT_EXTERN_MODULE(DashXReactNative, RCTEventEmitter)
|
|
19
|
-
|
|
20
|
-
RCT_EXTERN_METHOD(configure:(NSDictionary *)options);
|
|
21
|
-
|
|
22
|
-
RCT_EXTERN_METHOD(identify:(NSDictionary *)options);
|
|
23
|
-
|
|
24
|
-
RCT_EXTERN_METHOD(setIdentity:(NSString * _Nullable)uid token:(NSString * _Nullable)token);
|
|
25
|
-
|
|
26
|
-
RCT_EXTERN_METHOD(reset);
|
|
27
|
-
|
|
28
|
-
RCT_EXTERN_METHOD(track:(NSString *)event data:(NSDictionary * _Nullable)data);
|
|
29
|
-
|
|
30
|
-
RCT_EXTERN_METHOD(screen:(NSString *)screenName data:(NSDictionary * _Nullable)data);
|
|
31
|
-
|
|
32
|
-
RCT_EXTERN_METHOD(fetchRecord:(NSString *)urn options:(NSDictionary * _Nullable)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
33
|
-
|
|
34
|
-
RCT_EXTERN_METHOD(searchRecords:(NSString *)resource options:(NSDictionary * _Nullable)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
35
|
-
|
|
36
|
-
RCT_EXTERN_METHOD(fetchStoredPreferences:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
37
|
-
|
|
38
|
-
RCT_EXTERN_METHOD(saveStoredPreferences:(NSDictionary *)preferenceData resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
39
|
-
|
|
40
|
-
RCT_EXTERN_METHOD(subscribe);
|
|
41
|
-
|
|
42
|
-
RCT_EXTERN_METHOD(unsubscribe:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
43
|
-
|
|
44
|
-
RCT_EXTERN_METHOD(setLogLevel:(double)level);
|
|
45
|
-
|
|
46
|
-
RCT_EXTERN_METHOD(uploadAsset:(NSString *)filePath resource:(NSString *)resource attribute:(NSString *)attribute resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
47
|
-
|
|
48
|
-
RCT_EXTERN_METHOD(fetchAsset:(NSString *)assetId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
49
|
-
|
|
50
|
-
RCT_EXTERN_METHOD(enableLifecycleTracking);
|
|
51
|
-
|
|
52
|
-
RCT_EXTERN_METHOD(enableAdTracking);
|
|
53
|
-
|
|
54
|
-
RCT_EXTERN_METHOD(processURL:(NSString *)url source:(NSString * _Nullable)source forwardToLinkHandler:(BOOL)forwardToLinkHandler);
|
|
55
|
-
|
|
56
|
-
RCT_EXTERN_METHOD(trackNotificationNavigation:(NSDictionary * _Nullable)action notificationId:(NSString * _Nullable)notificationId);
|
|
57
|
-
|
|
58
|
-
RCT_EXTERN_METHOD(requestNotificationPermission:(BOOL)fallbackToSettings resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
59
|
-
|
|
60
|
-
RCT_EXTERN_METHOD(getNotificationPermissionStatus:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
|
|
61
|
-
|
|
62
|
-
@end
|
|
63
|
-
|
|
64
|
-
#ifdef RCT_NEW_ARCH_ENABLED
|
|
65
|
-
@interface DashXReactNative () <NativeDashXReactNativeSpec>
|
|
66
|
-
@end
|
|
67
|
-
|
|
68
|
-
@implementation DashXReactNative (TurboModule)
|
|
69
|
-
|
|
70
|
-
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
71
|
-
(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
72
|
-
{
|
|
73
|
-
return std::make_shared<facebook::react::NativeDashXReactNativeSpecJSI>(params);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
@end
|
|
77
|
-
#endif
|
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
import DashX
|
|
3
|
-
|
|
4
|
-
@objc(DashXReactNative)
|
|
5
|
-
class DashXReactNative: RCTEventEmitter {
|
|
6
|
-
override init() {
|
|
7
|
-
super.init()
|
|
8
|
-
DashXEventEmitter.instance.registerEventEmitter(eventEmitter: self)
|
|
9
|
-
DashX.linkHandler = { url in
|
|
10
|
-
DashXEventEmitter.instance.dispatch(name: "linkReceived", body: url.absoluteString)
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
override static func requiresMainQueueSetup() -> Bool {
|
|
15
|
-
return true
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
override func supportedEvents() -> [String] {
|
|
19
|
-
return ["messageReceived", "linkReceived", "notificationClicked"]
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
@objc(configure:)
|
|
23
|
-
func configure(_ options: NSDictionary) {
|
|
24
|
-
guard let publicKey = options["publicKey"] as? String, !publicKey.isEmpty else {
|
|
25
|
-
return
|
|
26
|
-
}
|
|
27
|
-
let baseURI = options["baseURI"] as? String
|
|
28
|
-
let targetEnvironment = options["targetEnvironment"] as? String
|
|
29
|
-
|
|
30
|
-
DashX.configure(
|
|
31
|
-
withPublicKey: publicKey,
|
|
32
|
-
baseURI: baseURI,
|
|
33
|
-
targetEnvironment: targetEnvironment
|
|
34
|
-
)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
@objc(identify:)
|
|
38
|
-
func identify(_ options: NSDictionary) {
|
|
39
|
-
let stringOptions = (options as? [String: Any])?.compactMapValues { ($0 as? CustomStringConvertible)?.description } ?? [:]
|
|
40
|
-
try? DashX.identify(options: stringOptions)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
@objc(setIdentity:token:)
|
|
44
|
-
func setIdentity(_ uid: NSString?, _ token: NSString?) {
|
|
45
|
-
DashX.setIdentity(uid: uid as String?, token: token as String?)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
@objc
|
|
49
|
-
func reset() {
|
|
50
|
-
DashX.reset()
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
@objc(track:data:)
|
|
54
|
-
func track(_ event: String, _ data: NSDictionary?) {
|
|
55
|
-
DashX.track(event, withData: data as? [String: Any])
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
@objc(screen:data:)
|
|
59
|
-
func screen(_ screenName: String, _ data: NSDictionary?) {
|
|
60
|
-
DashX.screen(screenName, withData: data as? [String: Any])
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
@objc(fetchRecord:options:resolve:reject:)
|
|
64
|
-
func fetchRecord(_ urn: String, options: NSDictionary?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
65
|
-
DashXClient.instance.fetchRecord(
|
|
66
|
-
urn: urn,
|
|
67
|
-
preview: options?["preview"] as? Bool,
|
|
68
|
-
language: options?["language"] as? String,
|
|
69
|
-
fields: options?["fields"] as? [[String: Any]],
|
|
70
|
-
include: options?["include"] as? [[String: Any]],
|
|
71
|
-
exclude: options?["exclude"] as? [[String: Any]]
|
|
72
|
-
) { result in
|
|
73
|
-
switch result {
|
|
74
|
-
case .success(let record): resolve(record)
|
|
75
|
-
case .failure(let error): reject("EUNSPECIFIED", error.localizedDescription, error)
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
@objc(searchRecords:options:resolve:reject:)
|
|
81
|
-
func searchRecords(_ resource: String, options: NSDictionary?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
82
|
-
DashXClient.instance.searchRecords(
|
|
83
|
-
resource: resource,
|
|
84
|
-
filter: options?["filter"] as? [String: Any],
|
|
85
|
-
order: options?["order"] as? [[String: Any]],
|
|
86
|
-
limit: options?["limit"] as? Int,
|
|
87
|
-
page: options?["page"] as? Int,
|
|
88
|
-
preview: options?["preview"] as? Bool,
|
|
89
|
-
language: options?["language"] as? String,
|
|
90
|
-
fields: options?["fields"] as? [[String: Any]],
|
|
91
|
-
include: options?["include"] as? [[String: Any]],
|
|
92
|
-
exclude: options?["exclude"] as? [[String: Any]]
|
|
93
|
-
) { result in
|
|
94
|
-
switch result {
|
|
95
|
-
case .success(let records): resolve(records)
|
|
96
|
-
case .failure(let error): reject("EUNSPECIFIED", error.localizedDescription, error)
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
@objc(fetchStoredPreferences:reject:)
|
|
102
|
-
func fetchStoredPreferences(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
103
|
-
DashXClient.instance.fetchStoredPreferences { result in
|
|
104
|
-
switch result {
|
|
105
|
-
case .success(let prefs): resolve(prefs)
|
|
106
|
-
case .failure(let error): reject("EUNSPECIFIED", error.localizedDescription, error)
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
@objc(saveStoredPreferences:resolve:reject:)
|
|
112
|
-
func saveStoredPreferences(_ preferenceData: NSDictionary, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
113
|
-
guard let dict = preferenceData as? [String: Any] else {
|
|
114
|
-
reject("EINVAL", "preferenceData must be a plain object", nil)
|
|
115
|
-
return
|
|
116
|
-
}
|
|
117
|
-
DashXClient.instance.saveStoredPreferences(preferenceData: dict) { result in
|
|
118
|
-
switch result {
|
|
119
|
-
case .success(let success): resolve(success)
|
|
120
|
-
case .failure(let error): reject("EUNSPECIFIED", error.localizedDescription, error)
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
@objc
|
|
126
|
-
func subscribe() {
|
|
127
|
-
DashX.subscribe()
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
@objc(unsubscribe:reject:)
|
|
131
|
-
func unsubscribe(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
132
|
-
DashX.unsubscribe { result in
|
|
133
|
-
switch result {
|
|
134
|
-
case .success(let didUnsubscribe):
|
|
135
|
-
resolve(["success": didUnsubscribe])
|
|
136
|
-
case .failure(let error):
|
|
137
|
-
reject("EUNSPECIFIED", error.localizedDescription, error)
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
@objc(setLogLevel:)
|
|
143
|
-
func setLogLevel(_ level: Double) {
|
|
144
|
-
// JS contract: 0 = off, 1 = errors, 2 = debug
|
|
145
|
-
// Native SDK: off = -1, error = 0, info = 1, debug = 2
|
|
146
|
-
let logLevel: DashXLog.LogLevel
|
|
147
|
-
switch Int(level) {
|
|
148
|
-
case 0: logLevel = .off
|
|
149
|
-
case 1: logLevel = .error
|
|
150
|
-
case 2: logLevel = .debug
|
|
151
|
-
default: logLevel = .off
|
|
152
|
-
}
|
|
153
|
-
DashXLog.setLogLevel(to: logLevel)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
@objc(uploadAsset:resource:attribute:resolve:reject:)
|
|
157
|
-
func uploadAsset(_ filePath: String, resource: String, attribute: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
158
|
-
let fileURL = URL(fileURLWithPath: filePath)
|
|
159
|
-
DashXClient.instance.uploadAsset(fileURL: fileURL, resource: resource, attribute: attribute) { result in
|
|
160
|
-
switch result {
|
|
161
|
-
case .success(let assetResponse):
|
|
162
|
-
if let data = try? JSONEncoder().encode(assetResponse),
|
|
163
|
-
let dict = try? JSONSerialization.jsonObject(with: data) as? NSDictionary {
|
|
164
|
-
resolve(dict)
|
|
165
|
-
} else {
|
|
166
|
-
resolve(nil)
|
|
167
|
-
}
|
|
168
|
-
case .failure(let error):
|
|
169
|
-
reject("EUNSPECIFIED", error.localizedDescription, error)
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
@objc(fetchAsset:resolve:reject:)
|
|
175
|
-
func fetchAsset(_ assetId: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
176
|
-
DashXClient.instance.fetchAsset(assetId: assetId) { result in
|
|
177
|
-
switch result {
|
|
178
|
-
case .success(let assetResponse):
|
|
179
|
-
if let data = try? JSONEncoder().encode(assetResponse),
|
|
180
|
-
let dict = try? JSONSerialization.jsonObject(with: data) as? NSDictionary {
|
|
181
|
-
resolve(dict)
|
|
182
|
-
} else {
|
|
183
|
-
resolve(nil)
|
|
184
|
-
}
|
|
185
|
-
case .failure(let error):
|
|
186
|
-
reject("EUNSPECIFIED", error.localizedDescription, error)
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
@objc
|
|
192
|
-
func enableLifecycleTracking() {
|
|
193
|
-
DispatchQueue.main.async { DashX.enableLifecycleTracking() }
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
@objc
|
|
197
|
-
func enableAdTracking() {
|
|
198
|
-
DashX.enableAdTracking()
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
@objc(processURL:source:forwardToLinkHandler:)
|
|
202
|
-
func processURL(_ url: String, source: NSString?, forwardToLinkHandler: Bool) {
|
|
203
|
-
guard let parsedURL = URL(string: url) else { return }
|
|
204
|
-
DashX.processURL(parsedURL, source: source as String?, forwardToLinkHandler: forwardToLinkHandler)
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
@objc(trackNotificationNavigation:notificationId:)
|
|
208
|
-
func trackNotificationNavigation(_ action: NSDictionary?, notificationId: NSString?) {
|
|
209
|
-
var navigationAction: NavigationAction? = nil
|
|
210
|
-
if let action = action, let type = action["type"] as? String {
|
|
211
|
-
switch type {
|
|
212
|
-
case "deepLink":
|
|
213
|
-
if let urlString = action["url"] as? String, let url = URL(string: urlString) {
|
|
214
|
-
navigationAction = .deepLink(url: url)
|
|
215
|
-
}
|
|
216
|
-
case "screen":
|
|
217
|
-
if let name = action["name"] as? String {
|
|
218
|
-
navigationAction = .screen(name: name, data: action["data"] as? [String: String])
|
|
219
|
-
}
|
|
220
|
-
case "richLanding":
|
|
221
|
-
if let urlString = action["url"] as? String, let url = URL(string: urlString) {
|
|
222
|
-
navigationAction = .richLanding(url: url)
|
|
223
|
-
}
|
|
224
|
-
case "clickAction":
|
|
225
|
-
if let actionStr = action["action"] as? String {
|
|
226
|
-
navigationAction = .clickAction(action: actionStr)
|
|
227
|
-
}
|
|
228
|
-
default:
|
|
229
|
-
break
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
DashX.trackNotificationNavigation(navigationAction, notificationId: notificationId as String?)
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
@objc(requestNotificationPermission:resolve:reject:)
|
|
236
|
-
func requestNotificationPermission(_ fallbackToSettings: Bool, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
237
|
-
DashX.requestNotificationPermission(fallbackToSettings: fallbackToSettings) { status in resolve(status.rawValue) }
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
@objc(getNotificationPermissionStatus:reject:)
|
|
241
|
-
func getNotificationPermissionStatus(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
242
|
-
DashX.getNotificationPermissionStatus { status in resolve(status.rawValue) }
|
|
243
|
-
}
|
|
244
|
-
}
|