@dashx/react-native 1.1.1 → 1.1.3

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 (132) hide show
  1. package/.DS_Store +0 -0
  2. package/.claude/settings.local.json +14 -0
  3. package/.github/workflows/ci.yml +28 -0
  4. package/CONTRIBUTING.md +153 -0
  5. package/DashXReactNative.podspec +6 -2
  6. package/README.md +259 -97
  7. package/__tests__/index.test.js +363 -0
  8. package/android/.gitignore +10 -0
  9. package/android/.gradle/7.2/dependencies-accessors/dependencies-accessors.lock +0 -0
  10. package/android/.gradle/7.2/dependencies-accessors/gc.properties +0 -0
  11. package/android/.gradle/7.2/fileChanges/last-build.bin +0 -0
  12. package/android/.gradle/7.2/fileHashes/fileHashes.lock +0 -0
  13. package/android/.gradle/7.2/gc.properties +0 -0
  14. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  15. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  16. package/android/.gradle/checksums/checksums.lock +0 -0
  17. package/android/.gradle/checksums/md5-checksums.bin +0 -0
  18. package/android/.gradle/checksums/sha1-checksums.bin +0 -0
  19. package/android/.gradle/vcs-1/gc.properties +0 -0
  20. package/android/build/.transforms/9dceace6c3787533d2dbb1a387e9284c/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/dashx/rn/sdk/DashXReactNativeFirebaseMessagingService.dex +0 -0
  21. package/android/build/.transforms/9dceace6c3787533d2dbb1a387e9284c/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/dashx/rn/sdk/DashXReactNativeModule.dex +0 -0
  22. package/android/build/.transforms/9dceace6c3787533d2dbb1a387e9284c/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/dashx/rn/sdk/MessageReceivedEventHolder.dex +0 -0
  23. package/android/build/.transforms/9dceace6c3787533d2dbb1a387e9284c/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/dashx/rn/sdk/util/Utils$WhenMappings.dex +0 -0
  24. package/android/build/.transforms/9dceace6c3787533d2dbb1a387e9284c/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/dashx/rn/sdk/util/Utils.dex +0 -0
  25. package/android/build/.transforms/9dceace6c3787533d2dbb1a387e9284c/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
  26. package/android/build/.transforms/f3c6049e7ab4bb564c79f3a246b8575e/transformed/classes/classes_dex/classes.dex +0 -0
  27. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +16 -0
  28. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  29. package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +31 -5
  30. package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +16 -0
  31. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/dashx/rn/sdk/DashXReactNativeFirebaseMessagingService.class +0 -0
  32. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/dashx/rn/sdk/DashXReactNativeModule.class +0 -0
  33. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/dashx/rn/sdk/MessageReceivedEventHolder.class +0 -0
  34. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/dashx/rn/sdk/util/Utils$WhenMappings.class +0 -0
  35. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/dashx/rn/sdk/util/Utils.class +0 -0
  36. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  37. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
  38. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
  39. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
  40. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len +0 -0
  41. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
  42. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
  43. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
  44. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
  45. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
  46. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
  47. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
  48. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
  49. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
  50. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
  51. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
  52. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
  53. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
  54. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
  55. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
  56. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
  57. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
  58. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
  59. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
  60. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
  61. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab +0 -0
  62. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.values.at +0 -0
  63. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
  64. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
  65. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
  66. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
  67. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
  68. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
  69. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
  70. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
  71. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
  72. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len +0 -0
  73. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
  74. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
  75. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
  76. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream +0 -0
  77. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len +0 -0
  78. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len +0 -0
  79. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
  80. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i +0 -0
  81. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
  82. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
  83. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len +0 -0
  84. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len +0 -0
  85. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
  86. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
  87. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +1 -1
  88. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
  89. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
  90. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
  91. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len +0 -0
  92. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
  93. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
  94. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
  95. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
  96. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
  97. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
  98. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
  99. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
  100. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
  101. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
  102. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
  103. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
  104. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
  105. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
  106. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  107. package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
  108. package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
  109. package/android/build/outputs/logs/manifest-merger-debug-report.txt +25 -3
  110. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  111. package/android/build/tmp/kotlin-classes/debug/com/dashx/rn/sdk/DashXReactNativeFirebaseMessagingService.class +0 -0
  112. package/android/build/tmp/kotlin-classes/debug/com/dashx/rn/sdk/DashXReactNativeModule.class +0 -0
  113. package/android/build/tmp/kotlin-classes/debug/com/dashx/rn/sdk/MessageReceivedEventHolder.class +0 -0
  114. package/android/build/tmp/kotlin-classes/debug/com/dashx/rn/sdk/util/Utils$WhenMappings.class +0 -0
  115. package/android/build/tmp/kotlin-classes/debug/com/dashx/rn/sdk/util/Utils.class +0 -0
  116. package/android/build.gradle +4 -1
  117. package/android/src/main/AndroidManifest.xml +15 -3
  118. package/android/src/main/java/com/dashx/rn/sdk/DashXReactNativeFirebaseMessagingService.kt +72 -0
  119. package/android/src/main/java/com/dashx/rn/sdk/DashXReactNativeModule.kt +84 -15
  120. package/android/src/main/java/com/dashx/rn/sdk/MessageReceivedEventHolder.kt +14 -0
  121. package/android/src/main/java/com/dashx/rn/sdk/util/Utils.kt +14 -0
  122. package/babel.config.js +1 -1
  123. package/index.d.ts +107 -0
  124. package/index.js +81 -4
  125. package/ios/.DS_Store +0 -0
  126. package/ios/DashXEventEmitter.swift +3 -2
  127. package/ios/DashXRCTAppDelegate.swift +110 -44
  128. package/ios/DashXReactNative-Bridging-Header.h +2 -0
  129. package/ios/DashXReactNative.h +1 -0
  130. package/ios/DashXReactNative.mm +16 -0
  131. package/ios/DashXReactNative.swift +118 -28
  132. package/package.json +18 -5
@@ -1,6 +1,6 @@
1
1
  class DashXEventEmitter {
2
2
  static let instance = DashXEventEmitter()
3
- private static var eventEmitter: DashXReactNative!
3
+ private static var eventEmitter: DashXReactNative?
4
4
 
5
5
  private init() {}
6
6
 
@@ -9,6 +9,7 @@ class DashXEventEmitter {
9
9
  }
10
10
 
11
11
  func dispatch(name: String, body: Any?) {
12
- DashXEventEmitter.eventEmitter.sendEvent(withName: name, body: body)
12
+ guard let emitter = DashXEventEmitter.eventEmitter else { return }
13
+ emitter.sendEvent(withName: name, body: body)
13
14
  }
14
15
  }
@@ -1,90 +1,108 @@
1
- import FirebaseCore
2
- import FirebaseMessaging
3
1
  import Foundation
4
2
  import UIKit
5
3
  import DashX
4
+ #if canImport(FirebaseCore)
5
+ import FirebaseCore
6
+ #endif
7
+ #if canImport(FirebaseMessaging)
8
+ import FirebaseMessaging
9
+ #endif
6
10
 
7
11
  @objc(DashXRCTAppDelegate)
8
- open class DashXRCTAppDelegate: RCTAppDelegate, MessagingDelegate, UNUserNotificationCenterDelegate {
9
- // MARK: Getters
10
- private var app: UIApplication = .shared
11
-
12
- // MARK: Init
12
+ open class DashXRCTAppDelegate: RCTDefaultReactNativeFactoryDelegate, UIApplicationDelegate, UNUserNotificationCenterDelegate {
13
13
 
14
- public override init() {
15
- super.init()
14
+ public var window: UIWindow?
15
+ private var reactNativeFactory: RCTReactNativeFactory?
16
16
 
17
- UNUserNotificationCenter.current().delegate = self
18
-
19
- // Register to ensure device token can be fetched
20
- app.registerForRemoteNotifications()
21
- }
17
+ /// The React Native module name. Defaults to "main". Override to match your app's registered component name.
18
+ open var moduleName: String { "main" }
22
19
 
23
- // MARK: MessagingDelegate
20
+ // MARK: - UIApplicationDelegate
24
21
 
25
- open override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
22
+ open func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
23
+ #if canImport(FirebaseCore)
26
24
  FirebaseApp.configure()
25
+ #endif
26
+ #if canImport(FirebaseMessaging)
27
27
  Messaging.messaging().delegate = self
28
+ #endif
29
+
30
+ UNUserNotificationCenter.current().delegate = self
28
31
 
29
- // Requesting Push Notifications Permission
30
32
  DashX.requestNotificationPermission { authorizationStatus in
31
33
  switch authorizationStatus {
32
34
  case .authorized:
33
35
  DashXLog.d(tag: #function, "permission authorized to receive push notifications")
36
+ DispatchQueue.main.async {
37
+ application.registerForRemoteNotifications()
38
+ }
34
39
  default:
35
40
  DashXLog.d(tag: #function, "permission denied to receive push notifications")
36
41
  }
37
42
  }
38
43
 
39
- return super.application(application, didFinishLaunchingWithOptions: launchOptions)
44
+ let factory = RCTReactNativeFactory(delegate: self)
45
+ reactNativeFactory = factory
46
+
47
+ window = UIWindow(frame: UIScreen.main.bounds)
48
+ factory.startReactNative(withModuleName: moduleName, in: window, launchOptions: launchOptions)
49
+
50
+ return true
40
51
  }
41
52
 
42
53
  // MARK: - APNS Token Management
43
54
 
44
- public override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
55
+ open func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
45
56
  DashXLog.d(tag: #function, "Unable to register for remote notifications: \(error.localizedDescription)")
46
57
  }
47
58
 
48
- public override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
59
+ open func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
60
+ #if canImport(FirebaseMessaging)
49
61
  Messaging.messaging().setAPNSToken(deviceToken, type: .unknown)
50
- }
51
-
52
- public func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
53
- guard let token = fcmToken else {
54
- DashXLog.d(tag: #function, "FCM Token is empty")
55
- return
62
+ Messaging.messaging().token { token, error in
63
+ if let token = token {
64
+ DashX.setFCMToken(to: token)
65
+ }
56
66
  }
67
+ #endif
68
+ }
57
69
 
58
- DashXLog.d(tag: #function, "FCM Token: \(token)")
70
+ // MARK: - Universal Links
59
71
 
60
- DashX.setFCMToken(to: token)
72
+ open func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
73
+ DashX.handleUserActivity(userActivity: userActivity)
74
+ return true
61
75
  }
62
76
 
63
77
  // MARK: - Push Notifications
64
78
 
65
- public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
79
+ open func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
66
80
  let message = notification.request.content.userInfo
67
81
 
68
- // Pass notification reciept information to Firebase
82
+ #if canImport(FirebaseMessaging)
69
83
  Messaging.messaging().appDidReceiveMessage(message)
84
+ #endif
70
85
 
71
- DashX.trackNotification(message: message, event: .delivered)
86
+ DashX.trackMessage(message: message, event: .delivered)
72
87
 
73
- let presentationOptions = notificationDeliveredInForeground(message: message)
88
+ DashXEventEmitter.instance.dispatch(name: "messageReceived", body: bridgeSafePayload(from: message))
74
89
 
75
- completionHandler(presentationOptions)
90
+ completionHandler(notificationDeliveredInForeground(message: message))
76
91
  }
77
92
 
78
- public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
93
+ open func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
79
94
  let message = response.notification.request.content.userInfo
80
95
 
81
- // Pass notification reciept information to Firebase
96
+ #if canImport(FirebaseMessaging)
82
97
  Messaging.messaging().appDidReceiveMessage(message)
98
+ #endif
99
+
100
+ DashXEventEmitter.instance.dispatch(name: "messageReceived", body: bridgeSafePayload(from: message))
83
101
 
84
102
  if response.actionIdentifier == UNNotificationDismissActionIdentifier {
85
- DashX.trackNotification(message: message, event: .dismissed)
103
+ DashX.trackMessage(message: message, event: .dismissed)
86
104
  } else {
87
- DashX.trackNotification(message: message, event: .clicked)
105
+ DashX.trackMessage(message: message, event: .clicked)
88
106
 
89
107
  if let url = message.dashxNotificationUrl() {
90
108
  handleLink(url: url)
@@ -96,9 +114,12 @@ open class DashXRCTAppDelegate: RCTAppDelegate, MessagingDelegate, UNUserNotific
96
114
  completionHandler()
97
115
  }
98
116
 
99
- public override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
100
- // Pass notification reciept information to Firebase
117
+ open func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
118
+ #if canImport(FirebaseMessaging)
101
119
  Messaging.messaging().appDidReceiveMessage(userInfo)
120
+ #endif
121
+
122
+ DashXEventEmitter.instance.dispatch(name: "messageReceived", body: bridgeSafePayload(from: userInfo))
102
123
 
103
124
  guard let dashxData = userInfo.dashxNotificationData() else {
104
125
  DashXLog.d(tag: #function, "Unable to parse DashX notification data")
@@ -147,13 +168,46 @@ open class DashXRCTAppDelegate: RCTAppDelegate, MessagingDelegate, UNUserNotific
147
168
  completionHandler(.newData)
148
169
  }
149
170
 
150
- // MARK: - Push Notifications handlers
171
+ // MARK: - Override points
151
172
 
152
- open func notificationDeliveredInForeground(message: [AnyHashable: Any]) -> UNNotificationPresentationOptions { return [] }
173
+ open func notificationDeliveredInForeground(message: [AnyHashable: Any]) -> UNNotificationPresentationOptions { return [.banner, .sound] }
153
174
 
154
175
  open func notificationClicked(message: [AnyHashable: Any], actionIdentifier: String) {}
155
176
 
156
177
  open func handleLink(url: URL) {}
178
+
179
+ // MARK: - Helpers
180
+
181
+ private func bridgeSafePayload(from userInfo: [AnyHashable: Any]) -> [String: Any] {
182
+ userInfo.reduce(into: [String: Any]()) { result, pair in
183
+ let key = String(describing: pair.key)
184
+ let value = pair.value
185
+ if let str = value as? String {
186
+ result[key] = str
187
+ } else if let num = value as? NSNumber {
188
+ result[key] = num
189
+ } else if let dict = value as? [AnyHashable: Any] {
190
+ result[key] = bridgeSafePayload(from: dict)
191
+ } else if let arr = value as? [Any] {
192
+ result[key] = arr.map { item -> Any in
193
+ if let str = item as? String { return str }
194
+ if let num = item as? NSNumber { return num }
195
+ if let d = item as? [AnyHashable: Any] { return bridgeSafePayload(from: d) }
196
+ if let a = item as? [Any] {
197
+ return a.map { sub -> Any in
198
+ if let s = sub as? String { return s }
199
+ if let n = sub as? NSNumber { return n }
200
+ if let sd = sub as? [AnyHashable: Any] { return bridgeSafePayload(from: sd) }
201
+ return "\(sub)"
202
+ }
203
+ }
204
+ return "\(item)"
205
+ }
206
+ } else {
207
+ result[key] = "\(value)"
208
+ }
209
+ }
210
+ }
157
211
  }
158
212
 
159
213
  extension DashXRCTAppDelegate {
@@ -178,16 +232,13 @@ extension DashXRCTAppDelegate {
178
232
  return
179
233
  }
180
234
 
181
- // Create a temporary file URL to save the downloaded image
182
235
  let tmpDirectoryURL = FileManager.default.temporaryDirectory
183
236
  let uuid = UUID().uuidString
184
237
  let tmpFileURL = tmpDirectoryURL.appendingPathComponent(uuid + ".png")
185
238
 
186
239
  do {
187
- // Move the downloaded file to the temporary file URL
188
240
  try FileManager.default.moveItem(at: location, to: tmpFileURL)
189
241
 
190
- // Create the notification attachment from the temporary file URL
191
242
  let attachment = try UNNotificationAttachment(identifier: "\(id)-attachment", url: tmpFileURL, options: nil)
192
243
  content.attachments = [attachment]
193
244
  self.createNotification(id: id, content: content)
@@ -198,3 +249,18 @@ extension DashXRCTAppDelegate {
198
249
  task.resume()
199
250
  }
200
251
  }
252
+
253
+ #if canImport(FirebaseMessaging)
254
+ extension DashXRCTAppDelegate: MessagingDelegate {
255
+ open func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
256
+ guard let token = fcmToken else {
257
+ DashXLog.d(tag: #function, "FCM Token is empty")
258
+ return
259
+ }
260
+
261
+ DashXLog.d(tag: #function, "FCM Token: \(token)")
262
+
263
+ DashX.setFCMToken(to: token)
264
+ }
265
+ }
266
+ #endif
@@ -1,3 +1,5 @@
1
1
  #import <React/RCTBridgeModule.h>
2
2
  #import <React/RCTEventEmitter.h>
3
3
  #import <React/RCTViewManager.h>
4
+ #import <React_RCTAppDelegate/RCTDefaultReactNativeFactoryDelegate.h>
5
+ #import <React_RCTAppDelegate/RCTReactNativeFactory.h>
@@ -0,0 +1 @@
1
+ #import "DashXRCTAppDelegate.h"
@@ -13,6 +13,10 @@ RCT_EXTERN_METHOD(track:(NSString *)event data:(NSDictionary * _Nullable)data);
13
13
 
14
14
  RCT_EXTERN_METHOD(screen:(NSString *)screenName data:(NSDictionary * _Nullable)data);
15
15
 
16
+ RCT_EXTERN_METHOD(fetchRecord:(NSString *)urn options:(NSDictionary * _Nullable)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject);
17
+
18
+ RCT_EXTERN_METHOD(searchRecords:(NSString *)resource options:(NSDictionary * _Nullable)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject);
19
+
16
20
  RCT_EXTERN_METHOD(fetchStoredPreferences:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject);
17
21
 
18
22
  RCT_EXTERN_METHOD(saveStoredPreferences:(NSDictionary *)preferenceData resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject);
@@ -25,4 +29,16 @@ RCT_EXTERN_METHOD(unsubscribe);
25
29
 
26
30
  RCT_EXTERN_METHOD(setLogLevel:(int *)level);
27
31
 
32
+ RCT_EXTERN_METHOD(uploadAsset:(NSString *)filePath resource:(NSString *)resource attribute:(NSString *)attribute resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject);
33
+
34
+ RCT_EXTERN_METHOD(fetchAsset:(NSString *)assetId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject);
35
+
36
+ RCT_EXTERN_METHOD(enableLifecycleTracking);
37
+
38
+ RCT_EXTERN_METHOD(enableAdTracking);
39
+
40
+ RCT_EXTERN_METHOD(requestNotificationPermission:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject);
41
+
42
+ RCT_EXTERN_METHOD(getNotificationPermissionStatus:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject);
43
+
28
44
  @end
@@ -1,13 +1,14 @@
1
1
  import Foundation
2
2
  import DashX
3
3
 
4
- typealias CBU = CallbackUtils
5
-
6
4
  @objc(DashXReactNative)
7
5
  class DashXReactNative: RCTEventEmitter {
8
6
  override init() {
9
7
  super.init()
10
8
  DashXEventEmitter.instance.registerEventEmitter(eventEmitter: self)
9
+ DashX.linkHandler = { url in
10
+ DashXEventEmitter.instance.dispatch(name: "linkReceived", body: url.absoluteString)
11
+ }
11
12
  }
12
13
 
13
14
  override static func requiresMainQueueSetup() -> Bool {
@@ -15,14 +16,16 @@ class DashXReactNative: RCTEventEmitter {
15
16
  }
16
17
 
17
18
  override func supportedEvents() -> [String] {
18
- return ["messageReceived"]
19
+ return ["messageReceived", "linkReceived"]
19
20
  }
20
21
 
21
22
  @objc(configure:)
22
23
  func configure(_ options: NSDictionary) {
23
- let publicKey = options["publicKey"] as! String,
24
- baseURI = options["baseURI"] as? String,
25
- targetEnvironment = options["targetEnvironment"] as? String
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
26
29
 
27
30
  DashX.configure(
28
31
  withPublicKey: publicKey,
@@ -33,7 +36,8 @@ class DashXReactNative: RCTEventEmitter {
33
36
 
34
37
  @objc(identify:)
35
38
  func identify(_ options: NSDictionary) {
36
- try? DashX.identify(withOptions: options)
39
+ let stringOptions = (options as? [String: Any])?.compactMapValues { ($0 as? CustomStringConvertible)?.description } ?? [:]
40
+ try? DashX.identify(options: stringOptions)
37
41
  }
38
42
 
39
43
  @objc(setIdentity:token:)
@@ -48,29 +52,74 @@ class DashXReactNative: RCTEventEmitter {
48
52
 
49
53
  @objc(track:data:)
50
54
  func track(_ event: String, _ data: NSDictionary?) {
51
- DashX.track(event, withData: data)
55
+ DashX.track(event, withData: data as? [String: Any])
52
56
  }
53
57
 
54
58
  @objc(screen:data:)
55
59
  func screen(_ screenName: String, _ data: NSDictionary?) {
56
- DashX.screen(screenName, withData: data)
60
+ DashX.screen(screenName, withData: data as? [String: Any])
61
+ }
62
+
63
+ @objc(fetchRecord:options:resolver:rejecter:)
64
+ func fetchRecord(_ urn: String, options: NSDictionary?, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter 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:resolver:rejecter:)
81
+ func searchRecords(_ resource: String, options: NSDictionary?, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter 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
+ }
57
99
  }
58
100
 
59
101
  @objc(fetchStoredPreferences:rejecter:)
60
102
  func fetchStoredPreferences(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
61
- DashX.fetchStoredPreferences(
62
- successCallback: CBU.resolveToSuccessCallback(resolve),
63
- failureCallback: CBU.rejectToFailureCallback(reject)
64
- )
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
+ }
65
109
  }
66
110
 
67
- @objc(saveStoredPreferences:resolve:rejecter:)
68
- func saveStoredPreferences(_ preferenceData: NSDictionary, _ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
69
- DashX.saveStoredPreferences(
70
- preferenceData: preferenceData,
71
- successCallback: CBU.resolveToSuccessCallback(resolve),
72
- failureCallback: CBU.rejectToFailureCallback(reject)
73
- )
111
+ @objc(saveStoredPreferences:resolver:rejecter:)
112
+ func saveStoredPreferences(_ preferenceData: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter 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
+ }
74
123
  }
75
124
 
76
125
  @objc
@@ -88,18 +137,59 @@ class DashXReactNative: RCTEventEmitter {
88
137
  let logLevel = DashXLog.LogLevel(rawValue: level) ?? DashXLog.LogLevel.off
89
138
  DashXLog.setLogLevel(to: logLevel)
90
139
  }
91
- }
92
140
 
93
- class CallbackUtils {
94
- static func resolveToSuccessCallback(_ resolve: @escaping RCTPromiseResolveBlock) -> SuccessCallback {
95
- return resolve
141
+ @objc(uploadAsset:resource:attribute:resolver:rejecter:)
142
+ func uploadAsset(_ filePath: String, resource: String, attribute: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
143
+ let fileURL = URL(fileURLWithPath: filePath)
144
+ DashXClient.instance.uploadAsset(fileURL: fileURL, resource: resource, attribute: attribute) { result in
145
+ switch result {
146
+ case .success(let assetResponse):
147
+ if let data = try? JSONEncoder().encode(assetResponse),
148
+ let dict = try? JSONSerialization.jsonObject(with: data) as? NSDictionary {
149
+ resolve(dict)
150
+ } else {
151
+ resolve(nil)
152
+ }
153
+ case .failure(let error):
154
+ reject("EUNSPECIFIED", error.localizedDescription, error)
155
+ }
156
+ }
96
157
  }
97
158
 
98
- static func rejectToFailureCallback(_ reject: @escaping RCTPromiseRejectBlock) -> FailureCallback {
99
- let result: FailureCallback = { (error) in
100
- reject("\((error as NSError).code)", error.localizedDescription, error)
159
+ @objc(fetchAsset:resolver:rejecter:)
160
+ func fetchAsset(_ assetId: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
161
+ DashXClient.instance.fetchAsset(assetId: assetId) { result in
162
+ switch result {
163
+ case .success(let assetResponse):
164
+ if let data = try? JSONEncoder().encode(assetResponse),
165
+ let dict = try? JSONSerialization.jsonObject(with: data) as? NSDictionary {
166
+ resolve(dict)
167
+ } else {
168
+ resolve(nil)
169
+ }
170
+ case .failure(let error):
171
+ reject("EUNSPECIFIED", error.localizedDescription, error)
172
+ }
101
173
  }
174
+ }
175
+
176
+ @objc
177
+ func enableLifecycleTracking() {
178
+ DispatchQueue.main.async { DashX.enableLifecycleTracking() }
179
+ }
180
+
181
+ @objc
182
+ func enableAdTracking() {
183
+ DashX.enableAdTracking()
184
+ }
185
+
186
+ @objc(requestNotificationPermission:rejecter:)
187
+ func requestNotificationPermission(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
188
+ DashX.requestNotificationPermission { status in resolve(status.rawValue) }
189
+ }
102
190
 
103
- return result
191
+ @objc(getNotificationPermissionStatus:rejecter:)
192
+ func getNotificationPermissionStatus(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
193
+ DashX.getNotificationPermissionStatus { status in resolve(status.rawValue) }
104
194
  }
105
195
  }
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.1.1",
4
+ "version": "1.1.3",
5
5
  "description": "DashX SDK for React Native",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
@@ -25,7 +25,8 @@
25
25
  "README.md"
26
26
  ],
27
27
  "scripts": {
28
- "test": "echo \"Error: no test specified\" && exit 1"
28
+ "test": "jest",
29
+ "lint": "eslint index.js"
29
30
  },
30
31
  "repository": {
31
32
  "type": "git",
@@ -37,7 +38,7 @@
37
38
  "android"
38
39
  ],
39
40
  "author": {
40
- "name": "DashXDev",
41
+ "name": "Team DashX",
41
42
  "email": "dev@dashx.com"
42
43
  },
43
44
  "license": "MIT",
@@ -47,8 +48,8 @@
47
48
  "registry": "https://registry.npmjs.org/"
48
49
  },
49
50
  "peerDependencies": {
50
- "react": "*",
51
- "react-native": "*"
51
+ "react": ">=17.0.0",
52
+ "react-native": ">=0.71.0"
52
53
  },
53
54
  "devDependencies": {
54
55
  "@commitlint/config-conventional": "^17.0.2",
@@ -74,6 +75,9 @@
74
75
  "@react-native",
75
76
  "prettier"
76
77
  ],
78
+ "plugins": [
79
+ "prettier"
80
+ ],
77
81
  "rules": {
78
82
  "prettier/prettier": [
79
83
  "error",
@@ -95,5 +99,14 @@
95
99
  "quoteProps": "consistent",
96
100
  "singleQuote": true,
97
101
  "trailingComma": "es5"
102
+ },
103
+ "jest": {
104
+ "testEnvironment": "node",
105
+ "transform": {
106
+ "^.+\\.js$": "babel-jest"
107
+ },
108
+ "transformIgnorePatterns": [
109
+ "node_modules/(?!react-native)"
110
+ ]
98
111
  }
99
112
  }