@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.
- package/BubblReactNativeSdk.podspec +29 -9
- package/CHANGELOG.md +52 -1
- package/LICENSE +202 -1
- package/README.md +172 -83
- package/android/build.gradle +33 -30
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/java/tech/bubbl/reactnative/BubblJson.kt +135 -0
- package/android/src/main/java/tech/bubbl/reactnative/BubblSdkModule.kt +277 -0
- package/android/src/main/java/tech/bubbl/reactnative/BubblSdkPackage.kt +26 -0
- package/app.plugin.js +2 -0
- package/ios/BubblPush.swift +44 -0
- package/ios/BubblSdk.h +7 -0
- package/ios/BubblSdk.mm +252 -0
- package/ios/BubblSdkImpl.swift +335 -0
- package/ios-extension/BubblReactNativeNotificationService.podspec +44 -0
- package/ios-extension/Sources/BubblCore/API/ApiResponse.swift +90 -0
- package/ios-extension/Sources/BubblCore/API/CredentialStore.swift +116 -0
- package/ios-extension/Sources/BubblCore/API/DeviceApiClient.swift +239 -0
- package/ios-extension/Sources/BubblCore/API/ErrorActions.swift +68 -0
- package/ios-extension/Sources/BubblCore/API/Http.swift +39 -0
- package/ios-extension/Sources/BubblCore/API/ServerClock.swift +69 -0
- package/ios-extension/Sources/BubblCore/BubblVersion.swift +5 -0
- package/ios-extension/Sources/BubblCore/Device/ConfigSync.swift +216 -0
- package/ios-extension/Sources/BubblCore/Device/DeviceSync.swift +160 -0
- package/ios-extension/Sources/BubblCore/Device/ProvisioningProfile.swift +24 -0
- package/ios-extension/Sources/BubblCore/Engine/EngineCore.swift +523 -0
- package/ios-extension/Sources/BubblCore/Engine/Geofencing.swift +170 -0
- package/ios-extension/Sources/BubblCore/Engine/Permissions.swift +90 -0
- package/ios-extension/Sources/BubblCore/Engine/Privacy.swift +64 -0
- package/ios-extension/Sources/BubblCore/Engine/PrivacyControls.swift +184 -0
- package/ios-extension/Sources/BubblCore/Engine/Pushes.swift +61 -0
- package/ios-extension/Sources/BubblCore/Engine/Sandbox.swift +149 -0
- package/ios-extension/Sources/BubblCore/Events/EventQueue.swift +207 -0
- package/ios-extension/Sources/BubblCore/Events/EventStore.swift +159 -0
- package/ios-extension/Sources/BubblCore/Geofence/Geofence.swift +160 -0
- package/ios-extension/Sources/BubblCore/Geofence/GeofenceEngine.swift +488 -0
- package/ios-extension/Sources/BubblCore/Geofence/GeofenceState.swift +103 -0
- package/ios-extension/Sources/BubblCore/Geofence/RegionBudget.swift +62 -0
- package/ios-extension/Sources/BubblCore/Notification/BubblNotification.swift +137 -0
- package/ios-extension/Sources/BubblCore/Notification/NotificationEvents.swift +160 -0
- package/ios-extension/Sources/BubblCore/Notification/Push.swift +134 -0
- package/ios-extension/Sources/BubblCore/Notification/SurveyForm.swift +185 -0
- package/ios-extension/Sources/BubblCore/RequestSigner.swift +56 -0
- package/ios-extension/Sources/BubblCore/Support/AsyncMutex.swift +39 -0
- package/ios-extension/Sources/BubblCore/Support/BubblLog.swift +52 -0
- package/ios-extension/Sources/BubblCore/Support/JSON.swift +31 -0
- package/ios-extension/Sources/BubblCore/Support/JSONValue.swift +94 -0
- package/ios-extension/Sources/BubblCore/Support/Locking.swift +11 -0
- package/ios-extension/Sources/BubblCore/Support/ValueStore.swift +109 -0
- package/ios-extension/Sources/BubblNotificationService/BubblNotificationService.swift +124 -0
- package/ios-sdk/BubblCore/API/ApiResponse.swift +90 -0
- package/ios-sdk/BubblCore/API/CredentialStore.swift +116 -0
- package/ios-sdk/BubblCore/API/DeviceApiClient.swift +239 -0
- package/ios-sdk/BubblCore/API/ErrorActions.swift +68 -0
- package/ios-sdk/BubblCore/API/Http.swift +39 -0
- package/ios-sdk/BubblCore/API/ServerClock.swift +69 -0
- package/ios-sdk/BubblCore/BubblVersion.swift +5 -0
- package/ios-sdk/BubblCore/Device/ConfigSync.swift +216 -0
- package/ios-sdk/BubblCore/Device/DeviceSync.swift +160 -0
- package/ios-sdk/BubblCore/Device/ProvisioningProfile.swift +24 -0
- package/ios-sdk/BubblCore/Engine/EngineCore.swift +523 -0
- package/ios-sdk/BubblCore/Engine/Geofencing.swift +170 -0
- package/ios-sdk/BubblCore/Engine/Permissions.swift +90 -0
- package/ios-sdk/BubblCore/Engine/Privacy.swift +64 -0
- package/ios-sdk/BubblCore/Engine/PrivacyControls.swift +184 -0
- package/ios-sdk/BubblCore/Engine/Pushes.swift +61 -0
- package/ios-sdk/BubblCore/Engine/Sandbox.swift +149 -0
- package/ios-sdk/BubblCore/Events/EventQueue.swift +207 -0
- package/ios-sdk/BubblCore/Events/EventStore.swift +159 -0
- package/ios-sdk/BubblCore/Geofence/Geofence.swift +160 -0
- package/ios-sdk/BubblCore/Geofence/GeofenceEngine.swift +488 -0
- package/ios-sdk/BubblCore/Geofence/GeofenceState.swift +103 -0
- package/ios-sdk/BubblCore/Geofence/RegionBudget.swift +62 -0
- package/ios-sdk/BubblCore/Notification/BubblNotification.swift +137 -0
- package/ios-sdk/BubblCore/Notification/NotificationEvents.swift +160 -0
- package/ios-sdk/BubblCore/Notification/Push.swift +134 -0
- package/ios-sdk/BubblCore/Notification/SurveyForm.swift +185 -0
- package/ios-sdk/BubblCore/RequestSigner.swift +56 -0
- package/ios-sdk/BubblCore/Support/AsyncMutex.swift +39 -0
- package/ios-sdk/BubblCore/Support/BubblLog.swift +52 -0
- package/ios-sdk/BubblCore/Support/JSON.swift +31 -0
- package/ios-sdk/BubblCore/Support/JSONValue.swift +94 -0
- package/ios-sdk/BubblCore/Support/Locking.swift +11 -0
- package/ios-sdk/BubblCore/Support/ValueStore.swift +109 -0
- package/ios-sdk/BubblLaunch/BubblLaunch.m +45 -0
- package/ios-sdk/BubblLaunch/include/BubblLaunch.h +5 -0
- package/ios-sdk/BubblSDK/Bubbl.swift +308 -0
- package/ios-sdk/BubblSDK/BubblBackend.swift +118 -0
- package/ios-sdk/BubblSDK/BubblCredential.swift +30 -0
- package/ios-sdk/BubblSDK/BubblMessage.swift +151 -0
- package/ios-sdk/BubblSDK/BubblOptions.swift +39 -0
- package/ios-sdk/BubblSDK/BubblPermissions.swift +79 -0
- package/ios-sdk/BubblSDK/BubblTestDeviceResult.swift +10 -0
- package/ios-sdk/BubblSDK/Engine/BackgroundRefresh.swift +92 -0
- package/ios-sdk/BubblSDK/Engine/EngineHost+Geofences.swift +177 -0
- package/ios-sdk/BubblSDK/Engine/EngineHost+Privacy.swift +65 -0
- package/ios-sdk/BubblSDK/Engine/EngineHost+Push.swift +154 -0
- package/ios-sdk/BubblSDK/Engine/EngineHost.swift +356 -0
- package/ios-sdk/BubblSDK/Engine/SupportedBubbl.swift +320 -0
- package/ios-sdk/BubblSDK/Engine/SystemLog.swift +27 -0
- package/ios-sdk/BubblSDK/Engine/WorkRunner.swift +107 -0
- package/ios-sdk/BubblSDK/Notification/Look.swift +78 -0
- package/ios-sdk/BubblSDK/Notification/NotificationMedia.swift +329 -0
- package/ios-sdk/BubblSDK/Notification/NotificationModel.swift +172 -0
- package/ios-sdk/BubblSDK/Notification/NotificationScreen.swift +428 -0
- package/ios-sdk/BubblSDK/Notification/ScreenPresenter.swift +148 -0
- package/ios-sdk/BubblSDK/Permissions/PermissionFlow.swift +169 -0
- package/ios-sdk/BubblSDK/Permissions/PrivacyView.swift +110 -0
- package/ios-sdk/BubblSDK/Platform/AppleDevicePlatform.swift +95 -0
- package/ios-sdk/BubblSDK/Platform/KeychainCredentialStore.swift +114 -0
- package/ios-sdk/BubblSDK/Platform/LocationService.swift +418 -0
- package/ios-sdk/BubblSDK/Platform/PushIntegration.swift +288 -0
- package/ios-sdk/BubblSDK/Platform/URLSessionHttpClient.swift +69 -0
- package/ios-sdk/BubblSDK/PrivacyInfo.xcprivacy +76 -0
- package/jest/index.js +75 -0
- package/lib/commonjs/BubblModule.js +14 -0
- package/lib/commonjs/BubblModule.js.map +1 -0
- package/lib/commonjs/BubblModule.web.js +13 -0
- package/lib/commonjs/BubblModule.web.js.map +1 -0
- package/lib/commonjs/NativeBubblSdk.js +20 -0
- package/lib/commonjs/NativeBubblSdk.js.map +1 -0
- package/lib/commonjs/index.js +336 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/types.js +2 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/module/BubblModule.js +5 -0
- package/lib/module/BubblModule.js.map +1 -0
- package/lib/module/BubblModule.web.js +9 -0
- package/lib/module/BubblModule.web.js.map +1 -0
- package/lib/module/NativeBubblSdk.js +18 -0
- package/lib/module/NativeBubblSdk.js.map +1 -0
- package/lib/module/index.js +331 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/src/BubblModule.d.ts +3 -0
- package/lib/typescript/commonjs/src/BubblModule.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/BubblModule.web.d.ts +8 -0
- package/lib/typescript/commonjs/src/BubblModule.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/NativeBubblSdk.d.ts +59 -0
- package/lib/typescript/commonjs/src/NativeBubblSdk.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/index.d.ts +111 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/types.d.ts +192 -0
- package/lib/typescript/commonjs/src/types.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/lib/typescript/module/src/BubblModule.d.ts +3 -0
- package/lib/typescript/module/src/BubblModule.d.ts.map +1 -0
- package/lib/typescript/module/src/BubblModule.web.d.ts +8 -0
- package/lib/typescript/module/src/BubblModule.web.d.ts.map +1 -0
- package/lib/typescript/module/src/NativeBubblSdk.d.ts +59 -0
- package/lib/typescript/module/src/NativeBubblSdk.d.ts.map +1 -0
- package/lib/typescript/module/src/index.d.ts +111 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -0
- package/lib/typescript/module/src/types.d.ts +192 -0
- package/lib/typescript/module/src/types.d.ts.map +1 -0
- package/package.json +105 -24
- package/plugin/build/imageNotifications.d.ts +35 -0
- package/plugin/build/imageNotifications.js +198 -0
- package/plugin/build/index.d.ts +84 -0
- package/plugin/build/index.js +176 -0
- package/src/BubblModule.ts +2 -0
- package/src/BubblModule.web.ts +9 -0
- package/src/NativeBubblSdk.ts +67 -0
- package/src/index.ts +338 -282
- package/src/types.ts +182 -0
- package/android/src/main/kotlin/tech/bubbl/reactnative/BubblSdkModule.kt +0 -680
- package/android/src/main/kotlin/tech/bubbl/reactnative/BubblSdkNotificationIntents.kt +0 -32
- package/android/src/main/kotlin/tech/bubbl/reactnative/BubblSdkPackage.kt +0 -14
- package/ios/BubblSdk.swift +0 -802
- package/ios/BubblSdkBridge.m +0 -86
- package/react-native.config.js +0 -11
- package/src/specs/NativeBubblSdk.ts +0 -54
package/ios/BubblSdk.mm
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#import "BubblSdk.h"
|
|
2
|
+
|
|
3
|
+
// Before the Swift header: BubblPush's signatures use UserNotifications types.
|
|
4
|
+
#import <UserNotifications/UserNotifications.h>
|
|
5
|
+
|
|
6
|
+
#if __has_include(<BubblReactNativeSdk/BubblReactNativeSdk-Swift.h>)
|
|
7
|
+
#import <BubblReactNativeSdk/BubblReactNativeSdk-Swift.h>
|
|
8
|
+
#else
|
|
9
|
+
#import "BubblReactNativeSdk-Swift.h"
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
static NSString *const BubblSdkEvent = @"BubblSdkEvent";
|
|
13
|
+
|
|
14
|
+
@implementation BubblSdk {
|
|
15
|
+
BubblSdkImpl *_impl;
|
|
16
|
+
BOOL _hasListeners;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
RCT_EXPORT_MODULE(BubblSdk)
|
|
20
|
+
|
|
21
|
+
- (instancetype)init
|
|
22
|
+
{
|
|
23
|
+
if (self = [super init]) {
|
|
24
|
+
__weak BubblSdk *weakSelf = self;
|
|
25
|
+
_impl = [[BubblSdkImpl alloc] initWithEmit:^BOOL(NSString *json) {
|
|
26
|
+
return [weakSelf emit:json];
|
|
27
|
+
}];
|
|
28
|
+
}
|
|
29
|
+
return self;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
+ (BOOL)requiresMainQueueSetup
|
|
33
|
+
{
|
|
34
|
+
return NO;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
- (NSArray<NSString *> *)supportedEvents
|
|
38
|
+
{
|
|
39
|
+
return @[ BubblSdkEvent ];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
- (void)startObserving
|
|
43
|
+
{
|
|
44
|
+
_hasListeners = YES;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
- (void)stopObserving
|
|
48
|
+
{
|
|
49
|
+
_hasListeners = NO;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/// Whether JS got it: with no JS listener it can't (a notification then stays Bubbl's to show).
|
|
53
|
+
- (BOOL)emit:(NSString *)json
|
|
54
|
+
{
|
|
55
|
+
if (!_hasListeners) {
|
|
56
|
+
return NO;
|
|
57
|
+
}
|
|
58
|
+
[self sendEventWithName:BubblSdkEvent body:json];
|
|
59
|
+
return YES;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
- (void)invalidate
|
|
63
|
+
{
|
|
64
|
+
[_impl invalidate];
|
|
65
|
+
[super invalidate];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// MARK: - Starting, consent and privacy
|
|
69
|
+
|
|
70
|
+
- (NSNumber *)isSupported
|
|
71
|
+
{
|
|
72
|
+
return @([_impl isSupported]);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
- (void)start:(NSString *)apiKey optionsJson:(NSString *)optionsJson
|
|
76
|
+
{
|
|
77
|
+
[_impl startWithApiKey:apiKey optionsJson:optionsJson];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
- (void)startWithCredential:(NSString *)keyId
|
|
81
|
+
secret:(NSString *)secret
|
|
82
|
+
installId:(NSString *)installId
|
|
83
|
+
optionsJson:(NSString *)optionsJson
|
|
84
|
+
{
|
|
85
|
+
[_impl startWithCredentialWithKeyId:keyId secret:secret installId:installId optionsJson:optionsJson];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
- (void)stop
|
|
89
|
+
{
|
|
90
|
+
[_impl stop];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
- (void)setConsent:(BOOL)granted
|
|
94
|
+
{
|
|
95
|
+
[_impl setConsent:granted];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
- (void)optOut
|
|
99
|
+
{
|
|
100
|
+
[_impl optOut];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
- (void)deleteMyData
|
|
104
|
+
{
|
|
105
|
+
[_impl deleteMyData];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
- (void)setLocationEnabled:(BOOL)enabled
|
|
109
|
+
{
|
|
110
|
+
[_impl setLocationEnabled:enabled];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// MARK: - Permissions (JSON, or null before start)
|
|
114
|
+
|
|
115
|
+
- (void)permissionStatus:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
|
|
116
|
+
{
|
|
117
|
+
resolve([_impl permissionStatus]);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
- (void)requestNotifications:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
|
|
121
|
+
{
|
|
122
|
+
[_impl requestNotifications:^(NSString *json) {
|
|
123
|
+
resolve(json);
|
|
124
|
+
}];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
- (void)requestLocation:(BOOL)always resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
|
|
128
|
+
{
|
|
129
|
+
[_impl requestLocationWithAlways:always completion:^(NSString *json) {
|
|
130
|
+
resolve(json);
|
|
131
|
+
}];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
- (void)openSettings
|
|
135
|
+
{
|
|
136
|
+
[_impl openSettings];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// MARK: - Targeting and events
|
|
140
|
+
|
|
141
|
+
- (void)setSegments:(NSArray *)segments
|
|
142
|
+
{
|
|
143
|
+
NSMutableArray<NSString *> *names = [NSMutableArray array];
|
|
144
|
+
for (id segment in segments) {
|
|
145
|
+
if ([segment isKindOfClass:[NSString class]] && [segment length] > 0) {
|
|
146
|
+
[names addObject:segment];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
[_impl setSegments:names];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
- (void)track:(NSString *)name propertiesJson:(NSString *)propertiesJson
|
|
153
|
+
{
|
|
154
|
+
[_impl trackWithName:name propertiesJson:propertiesJson];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// MARK: - Notifications
|
|
158
|
+
|
|
159
|
+
- (void)setNotificationListenerEnabled:(BOOL)enabled
|
|
160
|
+
{
|
|
161
|
+
[_impl setNotificationListenerEnabled:enabled];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
- (void)claimNotification:(NSString *)token
|
|
165
|
+
{
|
|
166
|
+
[_impl claimNotification:token];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
- (void)finishNotification:(NSString *)token appShowsIt:(BOOL)appShowsIt
|
|
170
|
+
{
|
|
171
|
+
[_impl finishNotification:token appShowsIt:appShowsIt];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
- (void)present:(NSString *)messageJson
|
|
175
|
+
{
|
|
176
|
+
[_impl present:messageJson];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
- (void)reportDisplayed:(NSString *)messageJson
|
|
180
|
+
{
|
|
181
|
+
[_impl reportDisplayed:messageJson];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
- (void)reportOpened:(NSString *)messageJson
|
|
185
|
+
{
|
|
186
|
+
[_impl reportOpened:messageJson];
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
- (void)reportCtaClicked:(NSString *)messageJson
|
|
190
|
+
{
|
|
191
|
+
[_impl reportCtaClicked:messageJson];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
- (void)reportDismissed:(NSString *)messageJson
|
|
195
|
+
{
|
|
196
|
+
[_impl reportDismissed:messageJson];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
- (void)reportMediaViewed:(NSString *)messageJson
|
|
200
|
+
{
|
|
201
|
+
[_impl reportMediaViewed:messageJson];
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
- (void)reportMediaCompleted:(NSString *)messageJson durationSeconds:(double)durationSeconds
|
|
205
|
+
{
|
|
206
|
+
[_impl reportMediaCompleted:messageJson durationSeconds:durationSeconds];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
- (void)reportSurveyStarted:(NSString *)messageJson
|
|
210
|
+
{
|
|
211
|
+
[_impl reportSurveyStarted:messageJson];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
- (void)submitSurvey:(NSString *)messageJson
|
|
215
|
+
answersJson:(NSString *)answersJson
|
|
216
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
217
|
+
reject:(RCTPromiseRejectBlock)reject
|
|
218
|
+
{
|
|
219
|
+
resolve(@([_impl submitSurvey:messageJson answersJson:answersJson]));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
- (void)openCta:(NSString *)messageJson
|
|
223
|
+
{
|
|
224
|
+
[_impl openCta:messageJson];
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// MARK: - Sandbox
|
|
228
|
+
|
|
229
|
+
- (void)registerTestDevice:(NSString *)code resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
|
|
230
|
+
{
|
|
231
|
+
[_impl registerTestDevice:code completion:^(NSString *json) {
|
|
232
|
+
resolve(json);
|
|
233
|
+
}];
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// MARK: - Diagnostics
|
|
237
|
+
|
|
238
|
+
- (void)diagnostics:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
|
|
239
|
+
{
|
|
240
|
+
[_impl diagnostics:^(NSString *json) {
|
|
241
|
+
resolve(json);
|
|
242
|
+
}];
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// MARK: - TurboModule
|
|
246
|
+
|
|
247
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
248
|
+
{
|
|
249
|
+
return std::make_shared<facebook::react::NativeBubblSdkSpecJSI>(params);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
@end
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
/// The Swift side of the React Native module (BubblSdk.mm calls it): each function passes straight
|
|
5
|
+
/// to the iOS SDK (`Bubbl`, built into this pod), with JSON across the bridge in the same shapes as
|
|
6
|
+
/// the Android module and the Flutter wrapper:
|
|
7
|
+
/// - a message goes to JS as the public BubblMessage fields plus its contract JSON, and comes back
|
|
8
|
+
/// as that JSON alone (`BubblMessage(json:)`);
|
|
9
|
+
/// - events go as {"type": "notification.received", ...}, the SDK's own event names;
|
|
10
|
+
/// - options, properties, answers and diagnostics are JSON objects.
|
|
11
|
+
///
|
|
12
|
+
/// The notification listener: while JS has one and the app is active, this takes the notification
|
|
13
|
+
/// over and hands it to JS ("notification.handle"), which shows it itself or calls present().
|
|
14
|
+
/// Otherwise Bubbl shows it as usual.
|
|
15
|
+
@objc(BubblSdkImpl)
|
|
16
|
+
public final class BubblSdkImpl: NSObject {
|
|
17
|
+
/// Sends JSON to JS on the module's one event (BubblSdkEvent); false when JS isn't listening.
|
|
18
|
+
private let emit: (String) -> Bool
|
|
19
|
+
private var eventToken: BubblEventToken?
|
|
20
|
+
|
|
21
|
+
/// How long JS has to claim a notification handed to it before Bubbl shows it.
|
|
22
|
+
static let claimTimeout: TimeInterval = 5
|
|
23
|
+
|
|
24
|
+
/// The instance whose JS set the app's notification listener (main thread only).
|
|
25
|
+
private static weak var owner: BubblSdkImpl?
|
|
26
|
+
|
|
27
|
+
/// Notifications handed to JS and not yet settled, by token (main thread only): JS claims one
|
|
28
|
+
/// when it arrives and finishes it once the app's listener has decided.
|
|
29
|
+
private var handedOver: [String: (message: BubblMessage, timeout: DispatchWorkItem)] = [:]
|
|
30
|
+
private var nextToken = 0
|
|
31
|
+
|
|
32
|
+
@objc public init(emit: @escaping (String) -> Bool) {
|
|
33
|
+
self.emit = emit
|
|
34
|
+
super.init()
|
|
35
|
+
eventToken = Bubbl.addEventListener { [weak self] event in
|
|
36
|
+
guard let self, let json = Self.event(event).flatMap(Self.json) else { return }
|
|
37
|
+
_ = self.emit(json)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// The module is going away (a JS reload): stop listening, and show whatever JS was handed and
|
|
42
|
+
/// hadn't settled. The app's listener is cleared only if this instance set it.
|
|
43
|
+
@objc public func invalidate() {
|
|
44
|
+
if let eventToken { Bubbl.removeEventListener(eventToken) }
|
|
45
|
+
eventToken = nil
|
|
46
|
+
DispatchQueue.main.async { [self] in
|
|
47
|
+
for handover in handedOver.values {
|
|
48
|
+
handover.timeout.cancel()
|
|
49
|
+
Bubbl.present(handover.message)
|
|
50
|
+
}
|
|
51
|
+
handedOver.removeAll()
|
|
52
|
+
if Self.owner === self {
|
|
53
|
+
Self.owner = nil
|
|
54
|
+
Bubbl.setNotificationListener(nil)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// MARK: - Starting, consent and privacy
|
|
60
|
+
|
|
61
|
+
/// Bubbl works on this device (iOS 17 and later); below, every call does nothing.
|
|
62
|
+
@objc public var isSupported: Bool { Bubbl.isSupported }
|
|
63
|
+
|
|
64
|
+
/// A mistake (an empty key, an http:// URL) is logged by the SDK, never thrown.
|
|
65
|
+
@objc public func start(apiKey: String, optionsJson: String) {
|
|
66
|
+
Bubbl.start(apiKey: apiKey, options: Self.options(Self.object(optionsJson)))
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/// The secret goes to the SDK and nowhere else: it arrives as its own argument (never inside
|
|
70
|
+
/// JSON), and the SDK logs an incomplete credential without it (BubblCredential's description
|
|
71
|
+
/// hides it).
|
|
72
|
+
@objc public func startWithCredential(keyId: String, secret: String, installId: String, optionsJson: String) {
|
|
73
|
+
Bubbl.start(
|
|
74
|
+
credential: BubblCredential(keyId: keyId, secret: secret, installId: installId),
|
|
75
|
+
options: Self.options(Self.object(optionsJson))
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@objc public func stop() { Bubbl.stop() }
|
|
80
|
+
@objc public func setConsent(_ granted: Bool) { Bubbl.setConsent(granted) }
|
|
81
|
+
@objc public func optOut() { Bubbl.optOut() }
|
|
82
|
+
@objc public func deleteMyData() { Bubbl.deleteMyData() }
|
|
83
|
+
@objc public func setLocationEnabled(_ enabled: Bool) { Bubbl.setLocationEnabled(enabled) }
|
|
84
|
+
|
|
85
|
+
// MARK: - Targeting and events
|
|
86
|
+
|
|
87
|
+
@objc public func setSegments(_ segments: [String]) { Bubbl.setSegments(segments) }
|
|
88
|
+
|
|
89
|
+
@objc public func track(name: String, propertiesJson: String) {
|
|
90
|
+
Bubbl.track(name, properties: Self.plain(Self.object(propertiesJson)))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// MARK: - Notifications
|
|
94
|
+
|
|
95
|
+
@objc public func setNotificationListenerEnabled(_ enabled: Bool) {
|
|
96
|
+
DispatchQueue.main.async { [self] in
|
|
97
|
+
guard enabled else {
|
|
98
|
+
if Self.owner === self {
|
|
99
|
+
Self.owner = nil
|
|
100
|
+
Bubbl.setNotificationListener(nil)
|
|
101
|
+
}
|
|
102
|
+
return
|
|
103
|
+
}
|
|
104
|
+
Self.owner = self
|
|
105
|
+
Bubbl.setNotificationListener { @MainActor [weak self] (message: BubblMessage) -> Bool in
|
|
106
|
+
self?.handOver(message) ?? false
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/// JS has the notification: the timeout that would show it is off.
|
|
112
|
+
@objc public func claimNotification(_ token: String) {
|
|
113
|
+
DispatchQueue.main.async { [self] in handedOver[token]?.timeout.cancel() }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/// The app's listener decided: Bubbl shows the notification unless the app does.
|
|
117
|
+
@objc public func finishNotification(_ token: String, appShowsIt: Bool) {
|
|
118
|
+
DispatchQueue.main.async { [self] in
|
|
119
|
+
guard let handover = handedOver.removeValue(forKey: token) else { return }
|
|
120
|
+
handover.timeout.cancel()
|
|
121
|
+
if !appShowsIt { Bubbl.present(handover.message) }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@objc public func present(_ json: String) { withMessage(json, "present") { Bubbl.present($0) } }
|
|
126
|
+
@objc public func reportDisplayed(_ json: String) { withMessage(json, "reportDisplayed") { Bubbl.reportDisplayed($0) } }
|
|
127
|
+
@objc public func reportOpened(_ json: String) { withMessage(json, "reportOpened") { Bubbl.reportOpened($0) } }
|
|
128
|
+
@objc public func reportCtaClicked(_ json: String) { withMessage(json, "reportCtaClicked") { Bubbl.reportCtaClicked($0) } }
|
|
129
|
+
@objc public func reportDismissed(_ json: String) { withMessage(json, "reportDismissed") { Bubbl.reportDismissed($0) } }
|
|
130
|
+
@objc public func reportMediaViewed(_ json: String) { withMessage(json, "reportMediaViewed") { Bubbl.reportMediaViewed($0) } }
|
|
131
|
+
@objc public func reportSurveyStarted(_ json: String) { withMessage(json, "reportSurveyStarted") { Bubbl.reportSurveyStarted($0) } }
|
|
132
|
+
@objc public func openCta(_ json: String) { withMessage(json, "openCta") { Bubbl.openCta($0) } }
|
|
133
|
+
|
|
134
|
+
@objc public func reportMediaCompleted(_ json: String, durationSeconds: Double) {
|
|
135
|
+
withMessage(json, "reportMediaCompleted") { Bubbl.reportMediaCompleted($0, durationSeconds: durationSeconds) }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@objc public func submitSurvey(_ json: String, answersJson: String) -> Bool {
|
|
139
|
+
guard let message = BubblMessage(json: json) else {
|
|
140
|
+
NSLog("[Bubbl] Bubbl.submitSurvey: that isn't a Bubbl message's json")
|
|
141
|
+
return false
|
|
142
|
+
}
|
|
143
|
+
return Bubbl.submitSurvey(message, answers: Self.plain(Self.object(answersJson)))
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// MARK: - Permissions
|
|
147
|
+
|
|
148
|
+
/// Where the device stands, as JSON; nil before start.
|
|
149
|
+
@objc public func permissionStatus() -> String? {
|
|
150
|
+
Bubbl.permissions.status().flatMap { Self.json(Self.permissions($0)) }
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/// The privacy view if the dashboard says so, then the system prompt; the status after, on the
|
|
154
|
+
/// main thread (nil before start).
|
|
155
|
+
@objc public func requestNotifications(_ completion: @escaping (String?) -> Void) {
|
|
156
|
+
Bubbl.permissions.requestNotifications { status in
|
|
157
|
+
completion(status.flatMap { Self.json(Self.permissions($0)) })
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/// The same for location; with `always`, the second step to "Always" too.
|
|
162
|
+
@objc public func requestLocation(always: Bool, completion: @escaping (String?) -> Void) {
|
|
163
|
+
Bubbl.permissions.requestLocation(always: always) { status in
|
|
164
|
+
completion(status.flatMap { Self.json(Self.permissions($0)) })
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
@objc public func openSettings() { Bubbl.permissions.openSettings() }
|
|
169
|
+
|
|
170
|
+
// MARK: - Sandbox
|
|
171
|
+
|
|
172
|
+
/// Approve this device as a Sandbox test device with the dashboard's code: {approved, message}
|
|
173
|
+
/// as JSON, on the main thread.
|
|
174
|
+
@objc public func registerTestDevice(_ code: String, completion: @escaping (String) -> Void) {
|
|
175
|
+
Bubbl.registerTestDevice(code) { result in
|
|
176
|
+
completion(Self.json(["approved": result.approved, "message": result.message ?? NSNull()]) ?? "{\"approved\":false}")
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// MARK: - Diagnostics
|
|
181
|
+
|
|
182
|
+
/// Bubbl.Diagnostics as JSON, on the main thread.
|
|
183
|
+
@objc public func diagnostics(_ completion: @escaping (String) -> Void) {
|
|
184
|
+
Bubbl.diagnostics { diagnostics in completion(Self.json(Self.diagnostics(diagnostics)) ?? "{}") }
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// MARK: -
|
|
188
|
+
|
|
189
|
+
private func withMessage(_ json: String, _ call: String, _ action: (BubblMessage) -> Void) {
|
|
190
|
+
guard let message = BubblMessage(json: json) else {
|
|
191
|
+
NSLog("[Bubbl] Bubbl.%@: that isn't a Bubbl message's json", call)
|
|
192
|
+
return
|
|
193
|
+
}
|
|
194
|
+
action(message)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/// The SDK asks, on the main thread, whether the app shows `message` itself: yes while the app
|
|
198
|
+
/// is active and JS is listening, and JS decides; no otherwise. Handed over, it's JS's to settle;
|
|
199
|
+
/// if JS doesn't claim it in time (reloading, stuck), Bubbl shows it: it's never lost.
|
|
200
|
+
@MainActor
|
|
201
|
+
private func handOver(_ message: BubblMessage) -> Bool {
|
|
202
|
+
nextToken += 1
|
|
203
|
+
let token = String(nextToken)
|
|
204
|
+
guard UIApplication.shared.applicationState == .active,
|
|
205
|
+
let json = Self.json(["type": "notification.handle", "token": token, "message": Self.message(message)])
|
|
206
|
+
else { return false }
|
|
207
|
+
let timeout = DispatchWorkItem { [weak self] in
|
|
208
|
+
if let handover = self?.handedOver.removeValue(forKey: token) { Bubbl.present(handover.message) }
|
|
209
|
+
}
|
|
210
|
+
handedOver[token] = (message, timeout)
|
|
211
|
+
guard emit(json) else {
|
|
212
|
+
handedOver[token] = nil
|
|
213
|
+
return false
|
|
214
|
+
}
|
|
215
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + Self.claimTimeout, execute: timeout)
|
|
216
|
+
return true
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// MARK: - JSON (the same shapes as android/…/BubblJson.kt)
|
|
220
|
+
|
|
221
|
+
static func object(_ text: String) -> [String: Any] {
|
|
222
|
+
guard let data = text.data(using: .utf8),
|
|
223
|
+
let object = try? JSONSerialization.jsonObject(with: data) as? [String: Any]
|
|
224
|
+
else { return [:] }
|
|
225
|
+
return object
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/// JSON nulls as nil, for the SDK's `[String: Any?]` parameters.
|
|
229
|
+
static func plain(_ object: [String: Any]) -> [String: Any?] {
|
|
230
|
+
object.mapValues { value -> Any? in value is NSNull ? nil : value }
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
static func json(_ object: [String: Any]) -> String? {
|
|
234
|
+
guard let data = try? JSONSerialization.data(withJSONObject: object) else { return nil }
|
|
235
|
+
return String(data: data, encoding: .utf8)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
static func options(_ json: [String: Any]) -> BubblOptions {
|
|
239
|
+
let name = json["logLevel"] as? String
|
|
240
|
+
return BubblOptions(
|
|
241
|
+
baseUrl: json["baseUrl"] as? String ?? "",
|
|
242
|
+
requireConsent: json["requireConsent"] as? Bool ?? false,
|
|
243
|
+
logLevel: BubblOptions.LogLevel.allCases.first { "\($0)" == name } ?? .warning,
|
|
244
|
+
segments: json["segments"] as? [String]
|
|
245
|
+
)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/// The public BubblMessage for JS: its fields as the SDK works them out, and its JSON.
|
|
249
|
+
static func message(_ message: BubblMessage) -> [String: Any] {
|
|
250
|
+
[
|
|
251
|
+
"id": message.id,
|
|
252
|
+
"headline": message.headline,
|
|
253
|
+
"body": message.body,
|
|
254
|
+
"isSurvey": message.isSurvey,
|
|
255
|
+
"isSandbox": message.isSandbox,
|
|
256
|
+
"mediaType": message.mediaType ?? NSNull(),
|
|
257
|
+
"mediaUrl": message.mediaUrl ?? NSNull(),
|
|
258
|
+
"mediaThumbnailUrl": message.mediaThumbnailUrl ?? NSNull(),
|
|
259
|
+
"ctaLabel": message.ctaLabel ?? NSNull(),
|
|
260
|
+
"ctaUrl": message.ctaUrl ?? NSNull(),
|
|
261
|
+
"questions": message.questions.map { question -> [String: Any] in
|
|
262
|
+
[
|
|
263
|
+
"id": question.id,
|
|
264
|
+
"text": question.text,
|
|
265
|
+
// The case name (openEnded, singleChoice…), as the TS type names them.
|
|
266
|
+
"type": "\(question.type)",
|
|
267
|
+
"required": question.required,
|
|
268
|
+
"choices": question.choices.map { ["id": $0.id, "text": $0.text] },
|
|
269
|
+
]
|
|
270
|
+
},
|
|
271
|
+
"json": message.json,
|
|
272
|
+
]
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
static func event(_ event: BubblEvent) -> [String: Any]? {
|
|
276
|
+
func with(_ type: String, _ message: BubblMessage) -> [String: Any] { ["type": type, "message": Self.message(message)] }
|
|
277
|
+
switch event {
|
|
278
|
+
case .notificationReceived(let message): return with("notification.received", message)
|
|
279
|
+
case .notificationDisplayed(let message): return with("notification.displayed", message)
|
|
280
|
+
case .notificationOpened(let message): return with("notification.opened", message)
|
|
281
|
+
case .notificationCtaClicked(let message): return with("notification.cta_clicked", message)
|
|
282
|
+
case .notificationDismissed(let message): return with("notification.dismissed", message)
|
|
283
|
+
case .mediaViewed(let message): return with("media.viewed", message)
|
|
284
|
+
case .mediaCompleted(let message): return with("media.completed", message)
|
|
285
|
+
case .surveyStarted(let message): return with("survey.started", message)
|
|
286
|
+
case .surveySubmitted(let message): return with("survey.submitted", message)
|
|
287
|
+
case .geofenceEntered(let locationId): return ["type": "geofence.entered", "locationId": locationId]
|
|
288
|
+
case .geofenceExited(let locationId): return ["type": "geofence.exited", "locationId": locationId]
|
|
289
|
+
case .error(let message): return ["type": "error", "message": message]
|
|
290
|
+
case .credentialRejected: return ["type": "credential.rejected"]
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/// {notifications, location, preciseLocation}, with the case names (notDetermined, whenInUse…)
|
|
295
|
+
/// the TS type and the Android module use.
|
|
296
|
+
static func permissions(_ status: BubblPermissionStatus) -> [String: Any] {
|
|
297
|
+
[
|
|
298
|
+
"notifications": "\(status.notifications)",
|
|
299
|
+
"location": "\(status.location)",
|
|
300
|
+
"preciseLocation": status.preciseLocation,
|
|
301
|
+
]
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/// The same fields as the Android module sends; Android's own extras are null here.
|
|
305
|
+
static func diagnostics(_ diagnostics: Bubbl.Diagnostics) -> [String: Any] {
|
|
306
|
+
[
|
|
307
|
+
"started": diagnostics.started,
|
|
308
|
+
"sdkVersion": diagnostics.sdkVersion,
|
|
309
|
+
"supported": diagnostics.supported,
|
|
310
|
+
"sdkSupported": diagnostics.sdkSupported,
|
|
311
|
+
"registered": diagnostics.registered,
|
|
312
|
+
"installId": diagnostics.installId ?? NSNull(),
|
|
313
|
+
"active": diagnostics.active,
|
|
314
|
+
"pausedUntil": diagnostics.pausedUntil.map { NSNumber(value: $0) } ?? NSNull(),
|
|
315
|
+
"consentRequired": diagnostics.consentRequired,
|
|
316
|
+
"consent": diagnostics.consent.map { NSNumber(value: $0) } ?? NSNull(),
|
|
317
|
+
"locationEnabled": diagnostics.locationEnabled,
|
|
318
|
+
"permissions": diagnostics.permissions.map(Self.permissions) ?? NSNull(),
|
|
319
|
+
"hasPushToken": diagnostics.hasPushToken,
|
|
320
|
+
"geofences": diagnostics.geofences,
|
|
321
|
+
"queuedEvents": diagnostics.queuedEvents,
|
|
322
|
+
"lastError": diagnostics.lastError ?? NSNull(),
|
|
323
|
+
"credentialRejected": diagnostics.credentialRejected,
|
|
324
|
+
"environment": diagnostics.environment ?? NSNull(),
|
|
325
|
+
"testDevice": diagnostics.testDevice.map { ["status": $0.status, "code": $0.code ?? NSNull()] as [String: Any] } ?? NSNull(),
|
|
326
|
+
"backgroundLocation": diagnostics.backgroundLocation,
|
|
327
|
+
"transitionsDroppedWhileLocked": diagnostics.transitionsDroppedWhileLocked,
|
|
328
|
+
"backgroundRestricted": NSNull(),
|
|
329
|
+
"batteryOptimized": NSNull(),
|
|
330
|
+
"backgroundRefreshAvailable": diagnostics.backgroundRefreshAvailable,
|
|
331
|
+
"lowPowerMode": diagnostics.lowPowerMode,
|
|
332
|
+
"osWatchesGeofences": diagnostics.osWatchesGeofences,
|
|
333
|
+
]
|
|
334
|
+
}
|
|
335
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
|
|
4
|
+
|
|
5
|
+
# Bubbl's pictures on pushes, for the app's Notification Service Extension target (optional): the
|
|
6
|
+
# iOS SDK's BubblNotificationService and the plain-Swift core it reads pushes with, copied into
|
|
7
|
+
# Sources/ by scripts/sync-ios-sources.mjs. No React Native in it: an extension is its own small
|
|
8
|
+
# process. In the Podfile, for the extension's target:
|
|
9
|
+
#
|
|
10
|
+
# target 'NotificationService' do
|
|
11
|
+
# pod 'BubblReactNativeNotificationService', :path => '../node_modules/@bubblsdk/react-native-sdk/ios-extension'
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# and the extension's principal class:
|
|
15
|
+
#
|
|
16
|
+
# import BubblNotificationService
|
|
17
|
+
# class NotificationService: BubblNotificationService {}
|
|
18
|
+
#
|
|
19
|
+
# Its own folder (not the package root), so React Native's autolinking never adds it to the app.
|
|
20
|
+
Pod::Spec.new do |s|
|
|
21
|
+
s.name = 'BubblReactNativeNotificationService'
|
|
22
|
+
# Imported as the iOS SDK's own product is: `import BubblNotificationService`.
|
|
23
|
+
s.module_name = 'BubblNotificationService'
|
|
24
|
+
s.version = package['version']
|
|
25
|
+
s.summary = "Pictures on Bubbl's pushes, for a React Native app's Notification Service Extension."
|
|
26
|
+
s.homepage = 'https://bubbl.tech'
|
|
27
|
+
s.license = { :type => 'Apache-2.0' }
|
|
28
|
+
s.author = { 'Bubbl' => 'engineering@bubbl.tech' }
|
|
29
|
+
s.source = { :git => 'https://github.com/bubbl-platform/renewed-sdk.git', :tag => "v#{s.version}" }
|
|
30
|
+
|
|
31
|
+
# The service shows pictures on iOS 17 and up and passes pushes through untouched below.
|
|
32
|
+
s.platforms = { :ios => defined?(min_ios_version_supported) ? min_ios_version_supported : '13.0' }
|
|
33
|
+
s.swift_version = '5.9'
|
|
34
|
+
s.source_files = 'Sources/**/*.swift'
|
|
35
|
+
s.frameworks = 'UserNotifications'
|
|
36
|
+
# iOS 14 and up (used only on 17 and up): weak, so an older iOS still loads the extension.
|
|
37
|
+
s.weak_frameworks = 'UniformTypeIdentifiers'
|
|
38
|
+
s.pod_target_xcconfig = {
|
|
39
|
+
'DEFINES_MODULE' => 'YES',
|
|
40
|
+
'APPLICATION_EXTENSION_API_ONLY' => 'YES',
|
|
41
|
+
# The core's `package` declarations, built here into one module with the service.
|
|
42
|
+
'OTHER_SWIFT_FLAGS' => '$(inherited) -package-name BubblReactNativeNotificationService',
|
|
43
|
+
}
|
|
44
|
+
end
|