@bubblsdk/react-native-sdk 4.1.7 → 5.0.0-alpha.2

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 (176) hide show
  1. package/BubblReactNativeSdk.podspec +29 -9
  2. package/CHANGELOG.md +52 -1
  3. package/LICENSE +202 -1
  4. package/README.md +172 -83
  5. package/android/build.gradle +33 -30
  6. package/android/src/main/AndroidManifest.xml +1 -0
  7. package/android/src/main/java/tech/bubbl/reactnative/BubblJson.kt +135 -0
  8. package/android/src/main/java/tech/bubbl/reactnative/BubblSdkModule.kt +277 -0
  9. package/android/src/main/java/tech/bubbl/reactnative/BubblSdkPackage.kt +26 -0
  10. package/app.plugin.js +2 -0
  11. package/ios/BubblPush.swift +44 -0
  12. package/ios/BubblSdk.h +7 -0
  13. package/ios/BubblSdk.mm +252 -0
  14. package/ios/BubblSdkImpl.swift +335 -0
  15. package/ios-extension/BubblReactNativeNotificationService.podspec +44 -0
  16. package/ios-extension/Sources/BubblCore/API/ApiResponse.swift +90 -0
  17. package/ios-extension/Sources/BubblCore/API/CredentialStore.swift +116 -0
  18. package/ios-extension/Sources/BubblCore/API/DeviceApiClient.swift +239 -0
  19. package/ios-extension/Sources/BubblCore/API/ErrorActions.swift +68 -0
  20. package/ios-extension/Sources/BubblCore/API/Http.swift +39 -0
  21. package/ios-extension/Sources/BubblCore/API/ServerClock.swift +69 -0
  22. package/ios-extension/Sources/BubblCore/BubblVersion.swift +5 -0
  23. package/ios-extension/Sources/BubblCore/Device/ConfigSync.swift +216 -0
  24. package/ios-extension/Sources/BubblCore/Device/DeviceSync.swift +160 -0
  25. package/ios-extension/Sources/BubblCore/Device/ProvisioningProfile.swift +24 -0
  26. package/ios-extension/Sources/BubblCore/Engine/EngineCore.swift +523 -0
  27. package/ios-extension/Sources/BubblCore/Engine/Geofencing.swift +170 -0
  28. package/ios-extension/Sources/BubblCore/Engine/Permissions.swift +90 -0
  29. package/ios-extension/Sources/BubblCore/Engine/Privacy.swift +64 -0
  30. package/ios-extension/Sources/BubblCore/Engine/PrivacyControls.swift +184 -0
  31. package/ios-extension/Sources/BubblCore/Engine/Pushes.swift +61 -0
  32. package/ios-extension/Sources/BubblCore/Engine/Sandbox.swift +149 -0
  33. package/ios-extension/Sources/BubblCore/Events/EventQueue.swift +207 -0
  34. package/ios-extension/Sources/BubblCore/Events/EventStore.swift +159 -0
  35. package/ios-extension/Sources/BubblCore/Geofence/Geofence.swift +160 -0
  36. package/ios-extension/Sources/BubblCore/Geofence/GeofenceEngine.swift +488 -0
  37. package/ios-extension/Sources/BubblCore/Geofence/GeofenceState.swift +103 -0
  38. package/ios-extension/Sources/BubblCore/Geofence/RegionBudget.swift +62 -0
  39. package/ios-extension/Sources/BubblCore/Notification/BubblNotification.swift +137 -0
  40. package/ios-extension/Sources/BubblCore/Notification/NotificationEvents.swift +160 -0
  41. package/ios-extension/Sources/BubblCore/Notification/Push.swift +134 -0
  42. package/ios-extension/Sources/BubblCore/Notification/SurveyForm.swift +185 -0
  43. package/ios-extension/Sources/BubblCore/RequestSigner.swift +56 -0
  44. package/ios-extension/Sources/BubblCore/Support/AsyncMutex.swift +39 -0
  45. package/ios-extension/Sources/BubblCore/Support/BubblLog.swift +52 -0
  46. package/ios-extension/Sources/BubblCore/Support/JSON.swift +31 -0
  47. package/ios-extension/Sources/BubblCore/Support/JSONValue.swift +94 -0
  48. package/ios-extension/Sources/BubblCore/Support/Locking.swift +11 -0
  49. package/ios-extension/Sources/BubblCore/Support/ValueStore.swift +109 -0
  50. package/ios-extension/Sources/BubblNotificationService/BubblNotificationService.swift +124 -0
  51. package/ios-sdk/BubblCore/API/ApiResponse.swift +90 -0
  52. package/ios-sdk/BubblCore/API/CredentialStore.swift +116 -0
  53. package/ios-sdk/BubblCore/API/DeviceApiClient.swift +239 -0
  54. package/ios-sdk/BubblCore/API/ErrorActions.swift +68 -0
  55. package/ios-sdk/BubblCore/API/Http.swift +39 -0
  56. package/ios-sdk/BubblCore/API/ServerClock.swift +69 -0
  57. package/ios-sdk/BubblCore/BubblVersion.swift +5 -0
  58. package/ios-sdk/BubblCore/Device/ConfigSync.swift +216 -0
  59. package/ios-sdk/BubblCore/Device/DeviceSync.swift +160 -0
  60. package/ios-sdk/BubblCore/Device/ProvisioningProfile.swift +24 -0
  61. package/ios-sdk/BubblCore/Engine/EngineCore.swift +523 -0
  62. package/ios-sdk/BubblCore/Engine/Geofencing.swift +170 -0
  63. package/ios-sdk/BubblCore/Engine/Permissions.swift +90 -0
  64. package/ios-sdk/BubblCore/Engine/Privacy.swift +64 -0
  65. package/ios-sdk/BubblCore/Engine/PrivacyControls.swift +184 -0
  66. package/ios-sdk/BubblCore/Engine/Pushes.swift +61 -0
  67. package/ios-sdk/BubblCore/Engine/Sandbox.swift +149 -0
  68. package/ios-sdk/BubblCore/Events/EventQueue.swift +207 -0
  69. package/ios-sdk/BubblCore/Events/EventStore.swift +159 -0
  70. package/ios-sdk/BubblCore/Geofence/Geofence.swift +160 -0
  71. package/ios-sdk/BubblCore/Geofence/GeofenceEngine.swift +488 -0
  72. package/ios-sdk/BubblCore/Geofence/GeofenceState.swift +103 -0
  73. package/ios-sdk/BubblCore/Geofence/RegionBudget.swift +62 -0
  74. package/ios-sdk/BubblCore/Notification/BubblNotification.swift +137 -0
  75. package/ios-sdk/BubblCore/Notification/NotificationEvents.swift +160 -0
  76. package/ios-sdk/BubblCore/Notification/Push.swift +134 -0
  77. package/ios-sdk/BubblCore/Notification/SurveyForm.swift +185 -0
  78. package/ios-sdk/BubblCore/RequestSigner.swift +56 -0
  79. package/ios-sdk/BubblCore/Support/AsyncMutex.swift +39 -0
  80. package/ios-sdk/BubblCore/Support/BubblLog.swift +52 -0
  81. package/ios-sdk/BubblCore/Support/JSON.swift +31 -0
  82. package/ios-sdk/BubblCore/Support/JSONValue.swift +94 -0
  83. package/ios-sdk/BubblCore/Support/Locking.swift +11 -0
  84. package/ios-sdk/BubblCore/Support/ValueStore.swift +109 -0
  85. package/ios-sdk/BubblLaunch/BubblLaunch.m +45 -0
  86. package/ios-sdk/BubblLaunch/include/BubblLaunch.h +5 -0
  87. package/ios-sdk/BubblSDK/Bubbl.swift +308 -0
  88. package/ios-sdk/BubblSDK/BubblBackend.swift +118 -0
  89. package/ios-sdk/BubblSDK/BubblCredential.swift +30 -0
  90. package/ios-sdk/BubblSDK/BubblMessage.swift +151 -0
  91. package/ios-sdk/BubblSDK/BubblOptions.swift +39 -0
  92. package/ios-sdk/BubblSDK/BubblPermissions.swift +79 -0
  93. package/ios-sdk/BubblSDK/BubblTestDeviceResult.swift +10 -0
  94. package/ios-sdk/BubblSDK/Engine/BackgroundRefresh.swift +92 -0
  95. package/ios-sdk/BubblSDK/Engine/EngineHost+Geofences.swift +177 -0
  96. package/ios-sdk/BubblSDK/Engine/EngineHost+Privacy.swift +65 -0
  97. package/ios-sdk/BubblSDK/Engine/EngineHost+Push.swift +154 -0
  98. package/ios-sdk/BubblSDK/Engine/EngineHost.swift +356 -0
  99. package/ios-sdk/BubblSDK/Engine/SupportedBubbl.swift +320 -0
  100. package/ios-sdk/BubblSDK/Engine/SystemLog.swift +27 -0
  101. package/ios-sdk/BubblSDK/Engine/WorkRunner.swift +107 -0
  102. package/ios-sdk/BubblSDK/Notification/Look.swift +78 -0
  103. package/ios-sdk/BubblSDK/Notification/NotificationMedia.swift +329 -0
  104. package/ios-sdk/BubblSDK/Notification/NotificationModel.swift +172 -0
  105. package/ios-sdk/BubblSDK/Notification/NotificationScreen.swift +428 -0
  106. package/ios-sdk/BubblSDK/Notification/ScreenPresenter.swift +148 -0
  107. package/ios-sdk/BubblSDK/Permissions/PermissionFlow.swift +169 -0
  108. package/ios-sdk/BubblSDK/Permissions/PrivacyView.swift +110 -0
  109. package/ios-sdk/BubblSDK/Platform/AppleDevicePlatform.swift +95 -0
  110. package/ios-sdk/BubblSDK/Platform/KeychainCredentialStore.swift +114 -0
  111. package/ios-sdk/BubblSDK/Platform/LocationService.swift +418 -0
  112. package/ios-sdk/BubblSDK/Platform/PushIntegration.swift +288 -0
  113. package/ios-sdk/BubblSDK/Platform/URLSessionHttpClient.swift +69 -0
  114. package/ios-sdk/BubblSDK/PrivacyInfo.xcprivacy +76 -0
  115. package/jest/index.js +75 -0
  116. package/lib/commonjs/BubblModule.js +14 -0
  117. package/lib/commonjs/BubblModule.js.map +1 -0
  118. package/lib/commonjs/BubblModule.web.js +13 -0
  119. package/lib/commonjs/BubblModule.web.js.map +1 -0
  120. package/lib/commonjs/NativeBubblSdk.js +20 -0
  121. package/lib/commonjs/NativeBubblSdk.js.map +1 -0
  122. package/lib/commonjs/index.js +336 -0
  123. package/lib/commonjs/index.js.map +1 -0
  124. package/lib/commonjs/package.json +1 -0
  125. package/lib/commonjs/types.js +2 -0
  126. package/lib/commonjs/types.js.map +1 -0
  127. package/lib/module/BubblModule.js +5 -0
  128. package/lib/module/BubblModule.js.map +1 -0
  129. package/lib/module/BubblModule.web.js +9 -0
  130. package/lib/module/BubblModule.web.js.map +1 -0
  131. package/lib/module/NativeBubblSdk.js +18 -0
  132. package/lib/module/NativeBubblSdk.js.map +1 -0
  133. package/lib/module/index.js +331 -0
  134. package/lib/module/index.js.map +1 -0
  135. package/lib/module/package.json +1 -0
  136. package/lib/module/types.js +2 -0
  137. package/lib/module/types.js.map +1 -0
  138. package/lib/typescript/commonjs/package.json +1 -0
  139. package/lib/typescript/commonjs/src/BubblModule.d.ts +3 -0
  140. package/lib/typescript/commonjs/src/BubblModule.d.ts.map +1 -0
  141. package/lib/typescript/commonjs/src/BubblModule.web.d.ts +8 -0
  142. package/lib/typescript/commonjs/src/BubblModule.web.d.ts.map +1 -0
  143. package/lib/typescript/commonjs/src/NativeBubblSdk.d.ts +59 -0
  144. package/lib/typescript/commonjs/src/NativeBubblSdk.d.ts.map +1 -0
  145. package/lib/typescript/commonjs/src/index.d.ts +111 -0
  146. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  147. package/lib/typescript/commonjs/src/types.d.ts +192 -0
  148. package/lib/typescript/commonjs/src/types.d.ts.map +1 -0
  149. package/lib/typescript/module/package.json +1 -0
  150. package/lib/typescript/module/src/BubblModule.d.ts +3 -0
  151. package/lib/typescript/module/src/BubblModule.d.ts.map +1 -0
  152. package/lib/typescript/module/src/BubblModule.web.d.ts +8 -0
  153. package/lib/typescript/module/src/BubblModule.web.d.ts.map +1 -0
  154. package/lib/typescript/module/src/NativeBubblSdk.d.ts +59 -0
  155. package/lib/typescript/module/src/NativeBubblSdk.d.ts.map +1 -0
  156. package/lib/typescript/module/src/index.d.ts +111 -0
  157. package/lib/typescript/module/src/index.d.ts.map +1 -0
  158. package/lib/typescript/module/src/types.d.ts +192 -0
  159. package/lib/typescript/module/src/types.d.ts.map +1 -0
  160. package/package.json +105 -24
  161. package/plugin/build/imageNotifications.d.ts +35 -0
  162. package/plugin/build/imageNotifications.js +198 -0
  163. package/plugin/build/index.d.ts +84 -0
  164. package/plugin/build/index.js +176 -0
  165. package/src/BubblModule.ts +2 -0
  166. package/src/BubblModule.web.ts +9 -0
  167. package/src/NativeBubblSdk.ts +67 -0
  168. package/src/index.ts +338 -282
  169. package/src/types.ts +182 -0
  170. package/android/src/main/kotlin/tech/bubbl/reactnative/BubblSdkModule.kt +0 -680
  171. package/android/src/main/kotlin/tech/bubbl/reactnative/BubblSdkNotificationIntents.kt +0 -32
  172. package/android/src/main/kotlin/tech/bubbl/reactnative/BubblSdkPackage.kt +0 -14
  173. package/ios/BubblSdk.swift +0 -802
  174. package/ios/BubblSdkBridge.m +0 -86
  175. package/react-native.config.js +0 -11
  176. package/src/specs/NativeBubblSdk.ts +0 -54
@@ -1,802 +0,0 @@
1
- import Foundation
2
- import React
3
- import BubblSDK
4
- import UIKit
5
-
6
- #if canImport(CoreLocation)
7
- import CoreLocation
8
- #endif
9
-
10
- @objc(BubblSdk)
11
- final class BubblSdk: RCTEventEmitter {
12
- private let sdk = BubblClient.shared
13
- private var eventTask: Task<Void, Never>?
14
-
15
- #if canImport(CoreLocation)
16
- @MainActor private lazy var locationMonitor = BubblLocationMonitor(sdk: sdk)
17
- #endif
18
-
19
- override static func requiresMainQueueSetup() -> Bool {
20
- false
21
- }
22
-
23
- override init() {
24
- super.init()
25
- Task { @MainActor in
26
- BubblNotificationCenterDelegate.installDefault()
27
- }
28
- }
29
-
30
- override func supportedEvents() -> [String]! {
31
- [Self.eventName]
32
- }
33
-
34
- override func startObserving() {
35
- eventTask?.cancel()
36
- eventTask = Task { [sdk] in
37
- let stream = await sdk.events
38
- for await event in stream {
39
- await MainActor.run {
40
- self.sendEvent(withName: Self.eventName, body: event.reactMap())
41
- }
42
- }
43
- }
44
- }
45
-
46
- override func stopObserving() {
47
- eventTask?.cancel()
48
- eventTask = nil
49
- }
50
-
51
- @objc(boot:resolver:rejecter:)
52
- func boot(
53
- _ config: NSDictionary,
54
- resolve: @escaping RCTPromiseResolveBlock,
55
- reject: @escaping RCTPromiseRejectBlock
56
- ) {
57
- resolveAsync(resolve, reject) {
58
- try await self.sdk.boot(try config.swiftMap.bubblConfig()).reactMap()
59
- }
60
- }
61
-
62
- @objc(shutdown:rejecter:)
63
- func shutdown(
64
- _ resolve: @escaping RCTPromiseResolveBlock,
65
- reject: @escaping RCTPromiseRejectBlock
66
- ) {
67
- resolveAsync(resolve, reject) {
68
- await self.sdk.shutdown()
69
- return nil
70
- }
71
- }
72
-
73
- @objc(startLocationTracking:rejecter:)
74
- func startLocationTracking(
75
- _ resolve: @escaping RCTPromiseResolveBlock,
76
- reject: @escaping RCTPromiseRejectBlock
77
- ) {
78
- Task {
79
- #if canImport(CoreLocation)
80
- await MainActor.run { self.locationMonitor.start() }
81
- #endif
82
- resolve(NSNull())
83
- }
84
- }
85
-
86
- @objc(stopLocationTracking:rejecter:)
87
- func stopLocationTracking(
88
- _ resolve: @escaping RCTPromiseResolveBlock,
89
- reject: @escaping RCTPromiseRejectBlock
90
- ) {
91
- Task {
92
- #if canImport(CoreLocation)
93
- await MainActor.run { self.locationMonitor.stop() }
94
- #endif
95
- resolve(NSNull())
96
- }
97
- }
98
-
99
- @objc(refresh:rejecter:)
100
- func refresh(
101
- _ resolve: @escaping RCTPromiseResolveBlock,
102
- reject: @escaping RCTPromiseRejectBlock
103
- ) {
104
- resolveAsync(resolve, reject) {
105
- try await self.sdk.refresh()
106
- return nil
107
- }
108
- }
109
-
110
- @objc(refreshGeofence:longitude:resolver:rejecter:)
111
- func refreshGeofence(
112
- _ latitude: Double,
113
- longitude: Double,
114
- resolve: @escaping RCTPromiseResolveBlock,
115
- reject: @escaping RCTPromiseRejectBlock
116
- ) {
117
- resolveAsync(resolve, reject) {
118
- let location = BubblLocation(latitude: latitude, longitude: longitude)
119
- try await self.sdk.refreshGeofence(location)
120
- #if canImport(CoreLocation)
121
- await self.locationMonitor.refreshBackgroundRegions(near: location)
122
- #endif
123
- return nil
124
- }
125
- }
126
-
127
- @objc(handleLocationUpdate:longitude:resolver:rejecter:)
128
- func handleLocationUpdate(
129
- _ latitude: Double,
130
- longitude: Double,
131
- resolve: @escaping RCTPromiseResolveBlock,
132
- reject: @escaping RCTPromiseRejectBlock
133
- ) {
134
- resolveAsync(resolve, reject) {
135
- let location = BubblLocation(latitude: latitude, longitude: longitude)
136
- try await self.sdk.handleLocationUpdate(location)
137
- #if canImport(CoreLocation)
138
- await self.locationMonitor.refreshBackgroundRegions(near: location)
139
- #endif
140
- return nil
141
- }
142
- }
143
-
144
- @objc(refreshPush:rejecter:)
145
- func refreshPush(
146
- _ resolve: @escaping RCTPromiseResolveBlock,
147
- reject: @escaping RCTPromiseRejectBlock
148
- ) {
149
- resolveAsync(resolve, reject) {
150
- try await self.sdk.refreshPush()
151
- return nil
152
- }
153
- }
154
-
155
- @objc(getConfiguration:rejecter:)
156
- func getConfiguration(
157
- _ resolve: @escaping RCTPromiseResolveBlock,
158
- reject: @escaping RCTPromiseRejectBlock
159
- ) {
160
- resolveAsync(resolve, reject) {
161
- await self.sdk.getConfiguration()?.reactMap()
162
- }
163
- }
164
-
165
- @objc(getPrivacyText:rejecter:)
166
- func getPrivacyText(
167
- _ resolve: @escaping RCTPromiseResolveBlock,
168
- reject: @escaping RCTPromiseRejectBlock
169
- ) {
170
- resolveAsync(resolve, reject) {
171
- await self.sdk.getPrivacyText()
172
- }
173
- }
174
-
175
- @objc(updateSegments:resolver:rejecter:)
176
- func updateSegments(
177
- _ tags: NSArray,
178
- resolve: @escaping RCTPromiseResolveBlock,
179
- reject: @escaping RCTPromiseRejectBlock
180
- ) {
181
- resolveAsync(resolve, reject) {
182
- try await self.sdk.updateSegments(tags.compactMap { $0 as? String })
183
- return nil
184
- }
185
- }
186
-
187
- @objc(setCorrelationId:resolver:rejecter:)
188
- func setCorrelationId(
189
- _ value: NSString,
190
- resolve: @escaping RCTPromiseResolveBlock,
191
- reject: @escaping RCTPromiseRejectBlock
192
- ) {
193
- resolveAsync(resolve, reject) {
194
- try await self.sdk.setCorrelationId(value as String)
195
- return nil
196
- }
197
- }
198
-
199
- @objc(clearCorrelationId:rejecter:)
200
- func clearCorrelationId(
201
- _ resolve: @escaping RCTPromiseResolveBlock,
202
- reject: @escaping RCTPromiseRejectBlock
203
- ) {
204
- resolveAsync(resolve, reject) {
205
- try await self.sdk.clearCorrelationId()
206
- return nil
207
- }
208
- }
209
-
210
- @objc(setDefaultNotificationModalEnabled:resolver:rejecter:)
211
- func setDefaultNotificationModalEnabled(
212
- _ enabled: Bool,
213
- resolve: @escaping RCTPromiseResolveBlock,
214
- reject: @escaping RCTPromiseRejectBlock
215
- ) {
216
- resolveAsync(resolve, reject) {
217
- try await self.sdk.setDefaultNotificationModalEnabled(enabled)
218
- return nil
219
- }
220
- }
221
-
222
- @objc(setDefaultNotificationModalStyle:resolver:rejecter:)
223
- func setDefaultNotificationModalStyle(
224
- _ style: NSDictionary?,
225
- resolve: @escaping RCTPromiseResolveBlock,
226
- reject: @escaping RCTPromiseRejectBlock
227
- ) {
228
- resolveAsync(resolve, reject) {
229
- try await self.sdk.setDefaultNotificationModalStyle(try style?.swiftMap.notificationModalStyle())
230
- return nil
231
- }
232
- }
233
-
234
- @objc(registerPushToken:resolver:rejecter:)
235
- func registerPushToken(
236
- _ token: NSString,
237
- resolve: @escaping RCTPromiseResolveBlock,
238
- reject: @escaping RCTPromiseRejectBlock
239
- ) {
240
- resolveAsync(resolve, reject) {
241
- try await self.sdk.registerPushToken(token as String)
242
- _ = await self.sdk.flush()
243
- return nil
244
- }
245
- }
246
-
247
- @objc(handleFirebasePayload:resolver:rejecter:)
248
- func handleFirebasePayload(
249
- _ payload: NSDictionary,
250
- resolve: @escaping RCTPromiseResolveBlock,
251
- reject: @escaping RCTPromiseRejectBlock
252
- ) {
253
- resolveAsync(resolve, reject) {
254
- try await self.sdk.handleFirebasePayload(payload.swiftMap.mapValues { String(describing: $0) })?.reactMap()
255
- }
256
- }
257
-
258
- @objc(showNotification:resolver:rejecter:)
259
- func showNotification(
260
- _ payload: NSDictionary,
261
- resolve: @escaping RCTPromiseResolveBlock,
262
- reject: @escaping RCTPromiseRejectBlock
263
- ) {
264
- resolveAsync(resolve, reject) {
265
- try await self.sdk.showNotification(try payload.swiftMap.notificationPayload()).reactMap()
266
- }
267
- }
268
-
269
- @objc(handleNotificationPayload:resolver:rejecter:)
270
- func handleNotificationPayload(
271
- _ payload: NSDictionary,
272
- resolve: @escaping RCTPromiseResolveBlock,
273
- reject: @escaping RCTPromiseRejectBlock
274
- ) {
275
- resolveAsync(resolve, reject) {
276
- try await self.sdk.handleNotificationPayload(try payload.swiftMap.notificationPayload()).reactMap()
277
- }
278
- }
279
-
280
- @objc(handleNotificationOpen:action:resolver:rejecter:)
281
- func handleNotificationOpen(
282
- _ payload: NSDictionary,
283
- action: NSString?,
284
- resolve: @escaping RCTPromiseResolveBlock,
285
- reject: @escaping RCTPromiseRejectBlock
286
- ) {
287
- resolveAsync(resolve, reject) {
288
- try await self.sdk.handleNotificationOpen(try payload.swiftMap.notificationPayload(), action: action as String?)
289
- return nil
290
- }
291
- }
292
-
293
- @objc(openNotificationModal:action:resolver:rejecter:)
294
- func openNotificationModal(
295
- _ payload: NSDictionary,
296
- action: NSString?,
297
- resolve: @escaping RCTPromiseResolveBlock,
298
- reject: @escaping RCTPromiseRejectBlock
299
- ) {
300
- resolveAsync(resolve, reject) {
301
- try await self.sdk.openNotificationModal(try payload.swiftMap.notificationPayload(), action: action as String?)
302
- }
303
- }
304
-
305
- @objc(handleNotificationCta:action:resolver:rejecter:)
306
- func handleNotificationCta(
307
- _ payload: NSDictionary,
308
- action: NSString?,
309
- resolve: @escaping RCTPromiseResolveBlock,
310
- reject: @escaping RCTPromiseRejectBlock
311
- ) {
312
- resolveAsync(resolve, reject) {
313
- try await self.sdk.handleNotificationCTA(try payload.swiftMap.notificationPayload(), action: action as String?)
314
- return nil
315
- }
316
- }
317
-
318
- @objc(handleNotificationMediaViewed:resolver:rejecter:)
319
- func handleNotificationMediaViewed(
320
- _ payload: NSDictionary,
321
- resolve: @escaping RCTPromiseResolveBlock,
322
- reject: @escaping RCTPromiseRejectBlock
323
- ) {
324
- resolveAsync(resolve, reject) {
325
- try await self.sdk.handleNotificationMediaViewed(try payload.swiftMap.notificationPayload())
326
- return nil
327
- }
328
- }
329
-
330
- @objc(handleNotificationSurveyRequested:resolver:rejecter:)
331
- func handleNotificationSurveyRequested(
332
- _ payload: NSDictionary,
333
- resolve: @escaping RCTPromiseResolveBlock,
334
- reject: @escaping RCTPromiseRejectBlock
335
- ) {
336
- resolveAsync(resolve, reject) {
337
- try await self.sdk.handleNotificationSurveyRequested(try payload.swiftMap.notificationPayload())
338
- return nil
339
- }
340
- }
341
-
342
- @objc(track:resolver:rejecter:)
343
- func track(
344
- _ event: NSDictionary,
345
- resolve: @escaping RCTPromiseResolveBlock,
346
- reject: @escaping RCTPromiseRejectBlock
347
- ) {
348
- resolveAsync(resolve, reject) {
349
- try await self.sdk.track(try event.swiftMap.trackEvent())
350
- return nil
351
- }
352
- }
353
-
354
- @objc(submitSurveyResponse:resolver:rejecter:)
355
- func submitSurveyResponse(
356
- _ response: NSDictionary,
357
- resolve: @escaping RCTPromiseResolveBlock,
358
- reject: @escaping RCTPromiseRejectBlock
359
- ) {
360
- resolveAsync(resolve, reject) {
361
- try await self.sdk.submitSurveyResponse(try response.swiftMap.surveyResponse())
362
- return nil
363
- }
364
- }
365
-
366
- @objc(flush:rejecter:)
367
- func flush(
368
- _ resolve: @escaping RCTPromiseResolveBlock,
369
- reject: @escaping RCTPromiseRejectBlock
370
- ) {
371
- resolveAsync(resolve, reject) {
372
- await self.sdk.flush().reactMap()
373
- }
374
- }
375
-
376
- @objc(diagnostics:rejecter:)
377
- func diagnostics(
378
- _ resolve: @escaping RCTPromiseResolveBlock,
379
- reject: @escaping RCTPromiseRejectBlock
380
- ) {
381
- resolveAsync(resolve, reject) {
382
- var diagnostics = await self.sdk.diagnostics()
383
- diagnostics.platform = "react-native"
384
- return diagnostics.reactMap()
385
- }
386
- }
387
-
388
- private func resolveAsync(
389
- _ resolve: @escaping RCTPromiseResolveBlock,
390
- _ reject: @escaping RCTPromiseRejectBlock,
391
- _ body: @escaping () async throws -> Any?
392
- ) {
393
- Task {
394
- do {
395
- resolve(try await body() ?? NSNull())
396
- } catch let error as BubblReactNativeError {
397
- reject(error.code, error.message, error)
398
- } catch {
399
- reject("bubbl_error", String(describing: error), error)
400
- }
401
- }
402
- }
403
-
404
- private static let eventName = "BubblSdkEvent"
405
- }
406
-
407
- @objc(BubblSdkLocationLaunchHandler)
408
- public final class BubblSdkLocationLaunchHandler: NSObject {
409
- #if canImport(CoreLocation)
410
- @MainActor private static let locationMonitor = BubblLocationMonitor(sdk: .shared)
411
- #endif
412
-
413
- @objc(handleLaunchOptions:)
414
- public static func handleLaunchOptions(_ launchOptions: NSDictionary?) -> Bool {
415
- let launchedForLocation = launchOptions?[UIApplication.LaunchOptionsKey.location.rawValue] != nil
416
- || launchOptions?[UIApplication.LaunchOptionsKey.location] != nil
417
-
418
- guard launchedForLocation else {
419
- return false
420
- }
421
-
422
- #if canImport(CoreLocation)
423
- Task { @MainActor in
424
- await locationMonitor.resumeForBackgroundLocationLaunch()
425
- }
426
- #endif
427
-
428
- return true
429
- }
430
- }
431
-
432
- private struct BubblReactNativeError: Error {
433
- let code: String
434
- let message: String
435
- }
436
-
437
- private func reactValue(_ value: Any?) -> Any {
438
- value ?? NSNull()
439
- }
440
-
441
- private extension NSDictionary {
442
- var swiftMap: [String: Any] {
443
- var output: [String: Any] = [:]
444
- for (key, value) in self {
445
- guard let key = key as? String else { continue }
446
- output[key] = value
447
- }
448
- return output
449
- }
450
- }
451
-
452
- private extension Dictionary where Key == String, Value == Any {
453
- func requiredString(_ key: String) throws -> String {
454
- guard let value = self[key] as? String, !value.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
455
- throw BubblReactNativeError(code: "invalid_argument", message: "\(key) is required.")
456
- }
457
- return value
458
- }
459
-
460
- func string(_ key: String) -> String? {
461
- self[key] as? String
462
- }
463
-
464
- func bool(_ key: String, default defaultValue: Bool) -> Bool {
465
- self[key] as? Bool ?? defaultValue
466
- }
467
-
468
- func int(_ key: String, default defaultValue: Int) -> Int {
469
- (self[key] as? NSNumber)?.intValue ?? defaultValue
470
- }
471
-
472
- func double(_ key: String) -> Double {
473
- (self[key] as? NSNumber)?.doubleValue ?? 0
474
- }
475
-
476
- func optionalDouble(_ key: String) -> Double? {
477
- (self[key] as? NSNumber)?.doubleValue
478
- }
479
-
480
- func stringArray(_ key: String) -> [String] {
481
- (self[key] as? [Any] ?? []).map { String(describing: $0) }
482
- }
483
-
484
- func map(_ key: String) -> [String: Any]? {
485
- self[key] as? [String: Any]
486
- }
487
-
488
- func mapArray(_ key: String) -> [[String: Any]] {
489
- self[key] as? [[String: Any]] ?? []
490
- }
491
-
492
- func bubblConfig() throws -> BubblConfig {
493
- BubblConfig(
494
- apiKey: try requiredString("apiKey"),
495
- environment: BubblEnvironment(rawValue: string("environment") ?? "staging") ?? .staging,
496
- runtimeBaseUrl: string("runtimeBaseUrl").flatMap(URL.init(string:)),
497
- transmissionBaseUrl: string("transmissionBaseUrl").flatMap(URL.init(string:)),
498
- ingestBaseUrl: string("ingestBaseUrl").flatMap(URL.init(string:)),
499
- segments: stringArray("segments"),
500
- correlationId: string("correlationId"),
501
- defaultDistanceMeters: int("defaultDistanceMeters", default: 10),
502
- refreshIntervalSeconds: int("refreshIntervalSeconds", default: 300),
503
- enablePushHandling: bool("enablePushHandling", default: true),
504
- enableLocationTracking: bool("enableLocationTracking", default: false),
505
- notificationRenderingMode: BubblNotificationRenderingMode(rawValue: string("notificationRenderingMode") ?? "sdkDefault") ?? .sdkDefault,
506
- enableDefaultNotificationModal: bool("enableDefaultNotificationModal", default: true),
507
- defaultNotificationModalStyle: try map("defaultNotificationModalStyle")?.notificationModalStyle(),
508
- enableDefaultSurveyUi: bool("enableDefaultSurveyUi", default: true),
509
- logLevel: BubblLogLevel(rawValue: string("logLevel") ?? "warn") ?? .warn
510
- )
511
- }
512
-
513
- func notificationModalStyle() throws -> BubblNotificationModalStyle {
514
- BubblNotificationModalStyle(
515
- theme: BubblNotificationModalTheme(rawValue: string("theme") ?? "light") ?? .light,
516
- transparentBackdrop: bool("transparentBackdrop", default: true),
517
- backdropColor: string("backdropColor"),
518
- cardBackgroundColor: string("cardBackgroundColor"),
519
- cardBorderColor: string("cardBorderColor"),
520
- titleColor: string("titleColor"),
521
- bodyColor: string("bodyColor"),
522
- accentColor: string("accentColor"),
523
- iconBackgroundColor: string("iconBackgroundColor"),
524
- iconTextColor: string("iconTextColor"),
525
- primaryButtonBackgroundColor: string("primaryButtonBackgroundColor"),
526
- primaryButtonTextColor: string("primaryButtonTextColor"),
527
- secondaryButtonBackgroundColor: string("secondaryButtonBackgroundColor"),
528
- secondaryButtonTextColor: string("secondaryButtonTextColor"),
529
- textButtonColor: string("textButtonColor"),
530
- surveyBackgroundColor: string("surveyBackgroundColor"),
531
- inputBackgroundColor: string("inputBackgroundColor"),
532
- inputTextColor: string("inputTextColor"),
533
- inputBorderColor: string("inputBorderColor"),
534
- cornerRadius: optionalDouble("cornerRadius"),
535
- buttonCornerRadius: optionalDouble("buttonCornerRadius")
536
- )
537
- }
538
-
539
- func trackEvent() throws -> BubblTrackEvent {
540
- BubblTrackEvent(
541
- type: try requiredString("type"),
542
- activity: try requiredString("activity"),
543
- locationId: string("locationId"),
544
- curatedNotificationId: string("curatedNotificationId"),
545
- latitude: optionalDouble("latitude"),
546
- longitude: optionalDouble("longitude")
547
- )
548
- }
549
-
550
- func surveyResponse() throws -> BubblSurveyResponse {
551
- BubblSurveyResponse(
552
- curatedNotificationId: try requiredString("curatedNotificationId"),
553
- locationId: string("locationId"),
554
- answers: try mapArray("answers").map { try $0.surveyAnswer() }
555
- )
556
- }
557
-
558
- func surveyAnswer() throws -> BubblSurveyAnswer {
559
- BubblSurveyAnswer(
560
- questionId: try requiredString("questionId"),
561
- type: try requiredString("type"),
562
- value: string("value"),
563
- choiceIds: stringArray("choiceIds")
564
- )
565
- }
566
-
567
- func notificationPayload() throws -> BubblNotificationPayload {
568
- BubblNotificationPayload(
569
- id: try requiredString("id"),
570
- title: try requiredString("title"),
571
- body: try requiredString("body"),
572
- source: BubblNotificationSource(rawValue: string("source") ?? "manual") ?? .manual,
573
- locationId: string("locationId"),
574
- curatedNotificationId: string("curatedNotificationId"),
575
- correlationId: string("correlationId"),
576
- media: try map("media")?.notificationMedia(),
577
- cta: try map("cta")?.notificationCTA(),
578
- survey: try map("survey")?.notificationSurvey(),
579
- raw: map("raw")?.mapValues { String(describing: $0) } ?? [:]
580
- )
581
- }
582
-
583
- func notificationMedia() throws -> BubblNotificationMedia {
584
- guard let url = URL(string: try requiredString("url")) else {
585
- throw BubblReactNativeError(code: "invalid_argument", message: "media.url is invalid.")
586
- }
587
- return BubblNotificationMedia(url: url, type: string("type"), altText: string("altText"))
588
- }
589
-
590
- func notificationCTA() throws -> BubblNotificationCTA {
591
- BubblNotificationCTA(
592
- label: try requiredString("label"),
593
- url: string("url").flatMap(URL.init(string:)),
594
- action: string("action")
595
- )
596
- }
597
-
598
- func notificationSurvey() throws -> BubblNotificationSurvey {
599
- BubblNotificationSurvey(questions: try mapArray("questions").map { try $0.surveyQuestion() })
600
- }
601
-
602
- func surveyQuestion() throws -> BubblSurveyQuestion {
603
- BubblSurveyQuestion(
604
- id: try requiredString("id"),
605
- title: try requiredString("title"),
606
- type: try requiredString("type"),
607
- choices: try mapArray("choices").map { try $0.surveyChoice() }
608
- )
609
- }
610
-
611
- func surveyChoice() throws -> BubblSurveyChoice {
612
- BubblSurveyChoice(id: try requiredString("id"), label: try requiredString("label"))
613
- }
614
- }
615
-
616
- private extension BubblBootResult {
617
- func reactMap() -> [String: Any] {
618
- [
619
- "ready": ready,
620
- "fromCache": fromCache,
621
- "deviceRegistered": deviceRegistered,
622
- "requiresPermission": requiresPermission,
623
- "warnings": warnings
624
- ]
625
- }
626
- }
627
-
628
- private extension BubblConfiguration {
629
- func reactMap() -> [String: Any] {
630
- [
631
- "notificationsCount": notificationsCount,
632
- "daysCount": daysCount,
633
- "batteryCount": batteryCount,
634
- "privacyText": privacyText
635
- ]
636
- }
637
- }
638
-
639
- private extension BubblDiagnostics {
640
- func reactMap() -> [String: Any] {
641
- [
642
- "sdkVersion": sdkVersion,
643
- "platform": platform,
644
- "booted": booted,
645
- "pendingIngestCount": pendingIngestCount,
646
- "pushTokenSuffix": reactValue(pushTokenSuffix)
647
- ]
648
- }
649
- }
650
-
651
- private extension BubblFlushResult {
652
- func reactMap() -> [String: Any] {
653
- ["pendingCount": pendingCount]
654
- }
655
- }
656
-
657
- private extension BubblNotificationDisplayResult {
658
- func reactMap() -> [String: Any] {
659
- ["displayed": displayed, "reason": reactValue(reason)]
660
- }
661
- }
662
-
663
- private extension BubblLocation {
664
- func reactMap() -> [String: Any] {
665
- ["latitude": latitude, "longitude": longitude]
666
- }
667
- }
668
-
669
- private extension BubblGeofenceTransition {
670
- func reactMap() -> [String: Any] {
671
- [
672
- "type": type.rawValue,
673
- "campaignId": reactValue(campaignId),
674
- "locationId": reactValue(locationId),
675
- "location": location.reactMap()
676
- ]
677
- }
678
- }
679
-
680
- private extension BubblGeofenceVertex {
681
- func reactMap() -> [String: Any] {
682
- ["latitude": latitude, "longitude": longitude]
683
- }
684
- }
685
-
686
- private extension BubblGeofencePolygon {
687
- func reactMap() -> [String: Any] {
688
- [
689
- "campaignId": reactValue(campaignId),
690
- "campaignName": reactValue(campaignName),
691
- "locationId": reactValue(locationId),
692
- "vertices": vertices.map { $0.reactMap() }
693
- ]
694
- }
695
- }
696
-
697
- private extension BubblGeofenceCircle {
698
- func reactMap() -> [String: Any] {
699
- [
700
- "campaignId": reactValue(campaignId),
701
- "campaignName": reactValue(campaignName),
702
- "locationId": reactValue(locationId),
703
- "center": center.reactMap(),
704
- "radiusMeters": radiusMeters
705
- ]
706
- }
707
- }
708
-
709
- private extension BubblGeofenceSnapshot {
710
- func reactMap() -> [String: Any] {
711
- [
712
- "stats": [
713
- "campaignsTotal": stats.campaignsTotal,
714
- "polygonsTotal": stats.polygonsTotal
715
- ],
716
- "polygons": polygons.map { $0.reactMap() },
717
- "circles": circles.map { $0.reactMap() }
718
- ]
719
- }
720
- }
721
-
722
- private extension BubblNotificationPayload {
723
- func reactMap() -> [String: Any] {
724
- [
725
- "id": id,
726
- "title": title,
727
- "body": body,
728
- "source": source.rawValue,
729
- "locationId": reactValue(locationId),
730
- "curatedNotificationId": reactValue(curatedNotificationId),
731
- "correlationId": reactValue(correlationId),
732
- "media": reactValue(media?.reactMap()),
733
- "cta": reactValue(cta?.reactMap()),
734
- "survey": reactValue(survey?.reactMap()),
735
- "raw": raw
736
- ]
737
- }
738
- }
739
-
740
- private extension BubblNotificationMedia {
741
- func reactMap() -> [String: Any] {
742
- ["url": url.absoluteString, "type": reactValue(type), "altText": reactValue(altText)]
743
- }
744
- }
745
-
746
- private extension BubblNotificationCTA {
747
- func reactMap() -> [String: Any] {
748
- ["label": label, "url": reactValue(url?.absoluteString), "action": reactValue(action)]
749
- }
750
- }
751
-
752
- private extension BubblNotificationSurvey {
753
- func reactMap() -> [String: Any] {
754
- ["questions": questions.map { $0.reactMap() }]
755
- }
756
- }
757
-
758
- private extension BubblSurveyQuestion {
759
- func reactMap() -> [String: Any] {
760
- ["id": id, "title": title, "type": type, "choices": choices.map { $0.reactMap() }]
761
- }
762
- }
763
-
764
- private extension BubblSurveyChoice {
765
- func reactMap() -> [String: Any] {
766
- ["id": id, "label": label]
767
- }
768
- }
769
-
770
- private extension BubblEvent {
771
- func reactMap() -> [String: Any] {
772
- switch self {
773
- case .ready:
774
- return ["type": "ready"]
775
- case .diagnostic(var diagnostics):
776
- diagnostics.platform = "react-native"
777
- return ["type": "diagnostic", "diagnostics": diagnostics.reactMap()]
778
- case .notificationReceived(let payload):
779
- return ["type": "notificationReceived", "payload": payload.reactMap()]
780
- case .notificationDisplayed(let payload):
781
- return ["type": "notificationDisplayed", "payload": payload.reactMap()]
782
- case .notificationTapped(let payload, let action):
783
- return ["type": "notificationTapped", "payload": payload.reactMap(), "action": reactValue(action)]
784
- case .notificationCtaTapped(let payload, let action):
785
- return ["type": "notificationCtaTapped", "payload": payload.reactMap(), "action": reactValue(action)]
786
- case .notificationMediaViewed(let payload):
787
- return ["type": "notificationMediaViewed", "payload": payload.reactMap()]
788
- case .notificationSurveyRequested(let payload):
789
- return ["type": "notificationSurveyRequested", "payload": payload.reactMap()]
790
- case .locationUpdated(let location):
791
- return ["type": "locationUpdated", "location": location.reactMap()]
792
- case .geofenceSnapshot(let snapshot):
793
- return ["type": "geofenceSnapshot", "snapshot": snapshot.reactMap()]
794
- case .geofenceEntered(let transition):
795
- return ["type": "geofenceEntered", "transition": transition.reactMap()]
796
- case .geofenceExited(let transition):
797
- return ["type": "geofenceExited", "transition": transition.reactMap()]
798
- case .error(let code, let message):
799
- return ["type": "error", "code": code, "message": message]
800
- }
801
- }
802
- }