react-native-notify-kit 10.1.0 → 10.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -96
- package/android/build.gradle +2 -2
- package/android/src/main/AndroidManifest.xml +0 -1
- package/android/src/main/java/app/notifee/core/ForegroundService.java +1 -0
- package/android/src/main/java/app/notifee/core/NotificationManager.java +21 -8
- package/android/src/main/java/app/notifee/core/RebootBroadcastReceiver.java +16 -0
- package/android/src/main/java/app/notifee/core/ReceiverService.java +18 -13
- package/android/src/main/java/app/notifee/core/model/NotificationAndroidActionModel.java +1 -2
- package/android/src/main/java/app/notifee/core/model/NotificationAndroidPressActionModel.java +3 -9
- package/android/src/main/java/app/notifee/core/model/TimestampTriggerModel.java +42 -27
- package/android/src/main/java/app/notifee/core/utility/IntentUtils.java +0 -28
- package/android/src/main/java/app/notifee/core/utility/PowerManagerUtils.java +79 -41
- package/android/src/main/java/app/notifee/core/utility/ResourceUtils.java +5 -1
- package/android/src/main/kotlin/io/invertase/notifee/NotifeeApiModule.kt +6 -6
- package/android/src/main/kotlin/io/invertase/notifee/NotifeeReactUtils.kt +1 -2
- package/android/src/test/java/app/notifee/core/model/TimestampTriggerModelTest.java +150 -0
- package/cli/dist/lib/patchPodfile.d.ts +3 -1
- package/cli/dist/lib/patchPodfile.js +125 -33
- package/cli/dist/lib/patchPodfile.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/types/Module.d.ts +27 -13
- package/dist/types/Notification.d.ts +1 -1
- package/dist/types/NotificationIOS.d.ts +44 -21
- package/dist/types/NotificationIOS.js +15 -1
- package/dist/types/NotificationIOS.js.map +1 -1
- package/dist/types/PowerManagerInfo.d.ts +9 -4
- package/dist/types/Trigger.d.ts +45 -2
- package/dist/types/Trigger.js +22 -0
- package/dist/types/Trigger.js.map +1 -1
- package/dist/validators/validateIOSCategory.js +2 -2
- package/dist/validators/validateIOSCategory.js.map +1 -1
- package/dist/validators/validateTrigger.js +26 -1
- package/dist/validators/validateTrigger.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/ios/NotifeeCore/NotifeeCore+NSNotificationCenter.m +20 -10
- package/ios/NotifeeCore/NotifeeCore+UNUserNotificationCenter.h +1 -2
- package/ios/NotifeeCore/NotifeeCore+UNUserNotificationCenter.m +44 -35
- package/ios/NotifeeCore/NotifeeCore.m +1042 -119
- package/ios/NotifeeCore/NotifeeCoreUtil.h +36 -1
- package/ios/NotifeeCore/NotifeeCoreUtil.m +533 -9
- package/ios/RNNotifee/NotifeeApiModule.mm +2 -2
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/types/Module.ts +27 -13
- package/src/types/Notification.ts +1 -1
- package/src/types/NotificationIOS.ts +43 -28
- package/src/types/PowerManagerInfo.ts +9 -4
- package/src/types/Trigger.ts +45 -1
- package/src/validators/validateIOSCategory.ts +4 -2
- package/src/validators/validateTrigger.ts +38 -0
- package/src/version.ts +1 -1
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
#import <UIKit/UIKit.h>
|
|
19
19
|
#import <dispatch/dispatch.h>
|
|
20
|
+
#include <math.h>
|
|
20
21
|
|
|
21
22
|
#import "Intents/Intents.h"
|
|
22
23
|
#import "NotifeeCore+UNUserNotificationCenter.h"
|
|
@@ -25,8 +26,935 @@
|
|
|
25
26
|
#import "NotifeeCoreExtensionHelper.h"
|
|
26
27
|
#import "NotifeeCoreUtil.h"
|
|
27
28
|
|
|
29
|
+
static NSString *const kNotifeeRollingPublicId = @"notifee_rolling_public_id";
|
|
30
|
+
static NSString *const kNotifeeRollingOccurrenceMs = @"notifee_rolling_occurrence_ms";
|
|
31
|
+
static NSString *const kNotifeeRollingInternalId = @"notifee_rolling_internal_id";
|
|
32
|
+
static NSString *const kNotifeeRollingInternalIdPrefix = @"__notifee_rolling__";
|
|
33
|
+
static NSString *const kNotifeeCoreErrorDomain = @"app.notifee.core";
|
|
34
|
+
|
|
35
|
+
typedef NS_ENUM(NSInteger, NotifeeCoreRollingErrorCode) {
|
|
36
|
+
NotifeeCoreRollingErrorCodeInvalidTrigger = 1,
|
|
37
|
+
NotifeeCoreRollingErrorCodeBudgetExceeded = 2,
|
|
38
|
+
NotifeeCoreRollingErrorCodeStorageFailed = 3,
|
|
39
|
+
};
|
|
40
|
+
|
|
28
41
|
@implementation NotifeeCore
|
|
29
42
|
|
|
43
|
+
+ (dispatch_queue_t)rollingTimestampQueue {
|
|
44
|
+
static dispatch_queue_t queue;
|
|
45
|
+
static dispatch_once_t onceToken;
|
|
46
|
+
dispatch_once(&onceToken, ^{
|
|
47
|
+
queue = dispatch_queue_create("app.notifee.core.rollingTimestamp", DISPATCH_QUEUE_SERIAL);
|
|
48
|
+
});
|
|
49
|
+
return queue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
+ (NSError *)rollingTimestampErrorWithCode:(NotifeeCoreRollingErrorCode)code
|
|
53
|
+
message:(NSString *)message {
|
|
54
|
+
return [NSError errorWithDomain:kNotifeeCoreErrorDomain
|
|
55
|
+
code:code
|
|
56
|
+
userInfo:@{NSLocalizedDescriptionKey : message}];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
+ (NSNumber *)currentTimestampMs {
|
|
60
|
+
return @((long long)llround([[NSDate date] timeIntervalSince1970] * 1000.0));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
+ (void)resolveBlock:(notifeeMethodVoidBlock)block withError:(NSError *)error {
|
|
64
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
65
|
+
block(error);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
+ (NSArray<UNNotificationRequest *> *)pendingNotificationRequests:
|
|
70
|
+
(UNUserNotificationCenter *)center {
|
|
71
|
+
__block NSArray<UNNotificationRequest *> *pendingRequests = @[];
|
|
72
|
+
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
73
|
+
|
|
74
|
+
[center getPendingNotificationRequestsWithCompletionHandler:^(
|
|
75
|
+
NSArray<UNNotificationRequest *> *_Nonnull requests) {
|
|
76
|
+
pendingRequests = requests != nil ? requests : @[];
|
|
77
|
+
dispatch_semaphore_signal(semaphore);
|
|
78
|
+
}];
|
|
79
|
+
|
|
80
|
+
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
|
81
|
+
return pendingRequests;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
+ (NSArray<UNNotification *> *)deliveredNotifications:(UNUserNotificationCenter *)center {
|
|
85
|
+
__block NSArray<UNNotification *> *deliveredNotifications = @[];
|
|
86
|
+
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
87
|
+
|
|
88
|
+
[center getDeliveredNotificationsWithCompletionHandler:^(
|
|
89
|
+
NSArray<UNNotification *> *_Nonnull notifications) {
|
|
90
|
+
deliveredNotifications = notifications != nil ? notifications : @[];
|
|
91
|
+
dispatch_semaphore_signal(semaphore);
|
|
92
|
+
}];
|
|
93
|
+
|
|
94
|
+
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
|
95
|
+
return deliveredNotifications;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
+ (NSString *)rollingPublicIdForNotification:(NSDictionary *)notification {
|
|
99
|
+
NSString *publicId = notification[@"id"];
|
|
100
|
+
if (![publicId isKindOfClass:NSString.class] || [publicId length] == 0) {
|
|
101
|
+
return nil;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return publicId;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
+ (BOOL)isPotentialRollingInternalNotificationId:(NSString *)notificationId {
|
|
108
|
+
return [notificationId isKindOfClass:NSString.class] &&
|
|
109
|
+
[notificationId hasPrefix:kNotifeeRollingInternalIdPrefix];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
+ (NSString *)rollingPublicIdForRequest:(UNNotificationRequest *)request {
|
|
113
|
+
NSString *identifier = request.identifier;
|
|
114
|
+
NSString *mappedPublicId = [NotifeeCoreUtil rollingPublicIdFromInternalNotificationId:identifier];
|
|
115
|
+
if ([mappedPublicId isKindOfClass:NSString.class] && [mappedPublicId length] > 0) {
|
|
116
|
+
return mappedPublicId;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if ([self isPotentialRollingInternalNotificationId:identifier]) {
|
|
120
|
+
NSString *metadataPublicId = request.content.userInfo[kNotifeeRollingPublicId];
|
|
121
|
+
if ([metadataPublicId isKindOfClass:NSString.class] && [metadataPublicId length] > 0) {
|
|
122
|
+
return metadataPublicId;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
NSDictionary *notification = request.content.userInfo[kNotifeeUserInfoNotification];
|
|
126
|
+
if ([notification isKindOfClass:NSDictionary.class]) {
|
|
127
|
+
NSString *payloadPublicId = notification[@"id"];
|
|
128
|
+
if ([payloadPublicId isKindOfClass:NSString.class] && [payloadPublicId length] > 0) {
|
|
129
|
+
return payloadPublicId;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return nil;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
+ (NSString *)publicIdentifierForRequest:(UNNotificationRequest *)request {
|
|
138
|
+
NSString *rollingPublicId = [self rollingPublicIdForRequest:request];
|
|
139
|
+
if (rollingPublicId != nil) {
|
|
140
|
+
return rollingPublicId;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
NSString *identifier = request.identifier;
|
|
144
|
+
if ([self isPotentialRollingInternalNotificationId:identifier]) {
|
|
145
|
+
return nil;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return identifier;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
+ (void)addString:(NSString *)string toOrderedSet:(NSMutableOrderedSet<NSString *> *)orderedSet {
|
|
152
|
+
if ([string isKindOfClass:NSString.class] && [string length] > 0) {
|
|
153
|
+
[orderedSet addObject:string];
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
+ (NSMutableOrderedSet<NSString *> *)
|
|
158
|
+
rollingIdentifiersForPublicId:(NSString *)publicId
|
|
159
|
+
pendingRequests:(NSArray<UNNotificationRequest *> *)pendingRequests
|
|
160
|
+
record:(NSDictionary *)record {
|
|
161
|
+
NSMutableOrderedSet<NSString *> *identifiers = [NSMutableOrderedSet orderedSet];
|
|
162
|
+
|
|
163
|
+
NSArray *scheduledIds = record[@"scheduledIds"];
|
|
164
|
+
if ([scheduledIds isKindOfClass:NSArray.class]) {
|
|
165
|
+
for (id scheduledId in scheduledIds) {
|
|
166
|
+
[self addString:scheduledId toOrderedSet:identifiers];
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
for (UNNotificationRequest *request in pendingRequests) {
|
|
171
|
+
NSString *identifier = request.identifier;
|
|
172
|
+
if ([identifier isEqualToString:publicId]) {
|
|
173
|
+
[self addString:identifier toOrderedSet:identifiers];
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
NSString *mappedPublicId =
|
|
178
|
+
[NotifeeCoreUtil rollingPublicIdFromInternalNotificationId:identifier];
|
|
179
|
+
if ([mappedPublicId isEqualToString:publicId]) {
|
|
180
|
+
[self addString:identifier toOrderedSet:identifiers];
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return identifiers;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
+ (NSMutableOrderedSet<NSString *> *)
|
|
188
|
+
rollingDeliveredIdentifiersForPublicId:(NSString *)publicId
|
|
189
|
+
deliveredNotifications:(NSArray<UNNotification *> *)deliveredNotifications
|
|
190
|
+
record:(NSDictionary *)record {
|
|
191
|
+
NSMutableOrderedSet<NSString *> *identifiers = [NSMutableOrderedSet orderedSet];
|
|
192
|
+
|
|
193
|
+
NSArray *scheduledIds = record[@"scheduledIds"];
|
|
194
|
+
if ([scheduledIds isKindOfClass:NSArray.class]) {
|
|
195
|
+
for (id scheduledId in scheduledIds) {
|
|
196
|
+
[self addString:scheduledId toOrderedSet:identifiers];
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
for (UNNotification *notification in deliveredNotifications) {
|
|
201
|
+
UNNotificationRequest *request = notification.request;
|
|
202
|
+
NSString *identifier = request.identifier;
|
|
203
|
+
if ([identifier isEqualToString:publicId]) {
|
|
204
|
+
[self addString:identifier toOrderedSet:identifiers];
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
NSString *mappedPublicId = [self rollingPublicIdForRequest:request];
|
|
209
|
+
if ([mappedPublicId isEqualToString:publicId]) {
|
|
210
|
+
[self addString:identifier toOrderedSet:identifiers];
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return identifiers;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
+ (NSUInteger)pendingRequestCountForIdentifiers:(NSOrderedSet<NSString *> *)identifiers
|
|
218
|
+
pendingRequests:
|
|
219
|
+
(NSArray<UNNotificationRequest *> *)pendingRequests {
|
|
220
|
+
NSUInteger count = 0;
|
|
221
|
+
for (UNNotificationRequest *request in pendingRequests) {
|
|
222
|
+
if ([identifiers containsObject:request.identifier]) {
|
|
223
|
+
count += 1;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return count;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
+ (UNCalendarNotificationTrigger *)rollingOneShotTriggerForOccurrenceMs:(NSNumber *)occurrenceMs {
|
|
230
|
+
NSDate *date = [NSDate dateWithTimeIntervalSince1970:([occurrenceMs doubleValue] / 1000.0)];
|
|
231
|
+
NSDateComponents *components = [[NSCalendar currentCalendar]
|
|
232
|
+
components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour |
|
|
233
|
+
NSCalendarUnitMinute | NSCalendarUnitSecond
|
|
234
|
+
fromDate:date];
|
|
235
|
+
|
|
236
|
+
return [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:NO];
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
+ (UNMutableNotificationContent *)rollingContentFromContent:(UNMutableNotificationContent *)content
|
|
240
|
+
publicId:(NSString *)publicId
|
|
241
|
+
occurrenceMs:(NSNumber *)occurrenceMs
|
|
242
|
+
internalId:(NSString *)internalId {
|
|
243
|
+
UNMutableNotificationContent *rollingContent = [content mutableCopy];
|
|
244
|
+
NSMutableDictionary *userInfo = [rollingContent.userInfo mutableCopy];
|
|
245
|
+
userInfo[kNotifeeRollingPublicId] = publicId;
|
|
246
|
+
userInfo[kNotifeeRollingOccurrenceMs] = occurrenceMs;
|
|
247
|
+
userInfo[kNotifeeRollingInternalId] = internalId;
|
|
248
|
+
rollingContent.userInfo = userInfo;
|
|
249
|
+
|
|
250
|
+
return rollingContent;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
+ (UNMutableNotificationContent *)
|
|
254
|
+
triggerNotificationContentForNotification:(NSDictionary *)notification
|
|
255
|
+
trigger:(NSDictionary *)trigger {
|
|
256
|
+
UNMutableNotificationContent *content = [self buildNotificationContent:notification
|
|
257
|
+
withTrigger:trigger];
|
|
258
|
+
|
|
259
|
+
if (@available(iOS 15.0, *)) {
|
|
260
|
+
if (notification[@"ios"][@"communicationInfo"] != nil) {
|
|
261
|
+
INSendMessageIntent *intent = [NotifeeCoreUtil
|
|
262
|
+
generateSenderIntentForCommunicationNotification:notification[@"ios"]
|
|
263
|
+
[@"communicationInfo"]];
|
|
264
|
+
|
|
265
|
+
INInteraction *interaction = [[INInteraction alloc] initWithIntent:intent response:nil];
|
|
266
|
+
interaction.direction = INInteractionDirectionIncoming;
|
|
267
|
+
[interaction donateInteractionWithCompletion:^(NSError *donateError) {
|
|
268
|
+
if (donateError)
|
|
269
|
+
NSLog(@"NotifeeCore: Could not donate interaction for communication notification: %@",
|
|
270
|
+
donateError);
|
|
271
|
+
}];
|
|
272
|
+
|
|
273
|
+
NSError *contentUpdateError = nil;
|
|
274
|
+
UNNotificationContent *updatedContent =
|
|
275
|
+
[content contentByUpdatingWithProvider:intent error:&contentUpdateError];
|
|
276
|
+
if (contentUpdateError) {
|
|
277
|
+
NSLog(@"NotifeeCore: Could not update notification content with communication intent: %@",
|
|
278
|
+
contentUpdateError);
|
|
279
|
+
} else if (updatedContent != nil) {
|
|
280
|
+
content = [updatedContent mutableCopy];
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return content;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
+ (UNNotificationRequest *)rollingNotificationRequestForPublicId:(NSString *)publicId
|
|
289
|
+
occurrenceMs:(NSNumber *)occurrenceMs
|
|
290
|
+
content:
|
|
291
|
+
(UNMutableNotificationContent *)content
|
|
292
|
+
error:(NSError **)error {
|
|
293
|
+
NSString *internalId = [NotifeeCoreUtil rollingInternalNotificationIdForPublicId:publicId
|
|
294
|
+
occurrenceMs:occurrenceMs];
|
|
295
|
+
if (internalId == nil) {
|
|
296
|
+
if (error != nil) {
|
|
297
|
+
*error =
|
|
298
|
+
[self rollingTimestampErrorWithCode:NotifeeCoreRollingErrorCodeInvalidTrigger
|
|
299
|
+
message:@"NotifeeCore: Failed to create rolling timestamp "
|
|
300
|
+
@"notification identifier."];
|
|
301
|
+
}
|
|
302
|
+
return nil;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
UNMutableNotificationContent *rollingContent = [self rollingContentFromContent:content
|
|
306
|
+
publicId:publicId
|
|
307
|
+
occurrenceMs:occurrenceMs
|
|
308
|
+
internalId:internalId];
|
|
309
|
+
return [UNNotificationRequest
|
|
310
|
+
requestWithIdentifier:internalId
|
|
311
|
+
content:rollingContent
|
|
312
|
+
trigger:[self rollingOneShotTriggerForOccurrenceMs:occurrenceMs]];
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
+ (void)removeRollingPendingRequestsForIds:(NSArray<NSString *> *)identifiers
|
|
316
|
+
center:(UNUserNotificationCenter *)center {
|
|
317
|
+
if ([identifiers count] > 0) {
|
|
318
|
+
[center removePendingNotificationRequestsWithIdentifiers:identifiers];
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
+ (NSMutableSet<NSString *> *)pendingIdentifierSetFromRequests:
|
|
323
|
+
(NSArray<UNNotificationRequest *> *)pendingRequests {
|
|
324
|
+
NSMutableSet<NSString *> *identifiers = [NSMutableSet set];
|
|
325
|
+
for (UNNotificationRequest *request in pendingRequests) {
|
|
326
|
+
NSString *identifier = request.identifier;
|
|
327
|
+
if ([identifier isKindOfClass:NSString.class] && [identifier length] > 0) {
|
|
328
|
+
[identifiers addObject:identifier];
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return identifiers;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
+ (NSComparisonResult)compareRollingRebalanceState:(NSDictionary *)firstState
|
|
335
|
+
otherState:(NSDictionary *)secondState {
|
|
336
|
+
return [firstState[@"publicId"] compare:secondState[@"publicId"]];
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
+ (NSError *)scheduleRollingNotificationRequests:(NSArray<UNNotificationRequest *> *)requests
|
|
340
|
+
center:(UNUserNotificationCenter *)center
|
|
341
|
+
successfulIdentifiers:(NSMutableSet<NSString *> *)successfulIdentifiers {
|
|
342
|
+
if ([requests count] == 0) {
|
|
343
|
+
return nil;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
dispatch_group_t group = dispatch_group_create();
|
|
347
|
+
NSObject *scheduleLock = [[NSObject alloc] init];
|
|
348
|
+
__block NSError *scheduleError = nil;
|
|
349
|
+
|
|
350
|
+
for (__unused UNNotificationRequest *request in requests) {
|
|
351
|
+
dispatch_group_enter(group);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
355
|
+
for (UNNotificationRequest *request in requests) {
|
|
356
|
+
[center addNotificationRequest:request
|
|
357
|
+
withCompletionHandler:^(NSError *_Nullable error) {
|
|
358
|
+
@synchronized(scheduleLock) {
|
|
359
|
+
if (error != nil && scheduleError == nil) {
|
|
360
|
+
scheduleError = error;
|
|
361
|
+
} else if (error == nil && successfulIdentifiers != nil) {
|
|
362
|
+
[successfulIdentifiers addObject:request.identifier];
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
dispatch_group_leave(group);
|
|
366
|
+
}];
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
|
|
371
|
+
return scheduleError;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
+ (BOOL)persistedRollingRecords:(NSDictionary *)persistedRecords
|
|
375
|
+
matchUpdatedRecords:(NSDictionary *)updatedRecords {
|
|
376
|
+
if ([persistedRecords count] != [updatedRecords count]) {
|
|
377
|
+
return NO;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
for (id publicId in updatedRecords) {
|
|
381
|
+
if (persistedRecords[publicId] == nil) {
|
|
382
|
+
return NO;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return YES;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
+ (NSArray<NSMutableDictionary *> *)rollingRebalanceStatesFromRecords:(NSDictionary *)records
|
|
390
|
+
nowMs:(NSNumber *)nowMs
|
|
391
|
+
requiredPublicId:(NSString *)requiredPublicId
|
|
392
|
+
error:(NSError **)error {
|
|
393
|
+
NSMutableArray<NSMutableDictionary *> *states = [NSMutableArray array];
|
|
394
|
+
BOOL foundRequiredPublicId = requiredPublicId == nil;
|
|
395
|
+
|
|
396
|
+
for (id key in records) {
|
|
397
|
+
if (![key isKindOfClass:NSString.class] || [key length] == 0) {
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
NSString *publicId = key;
|
|
402
|
+
BOOL isRequiredPublicId = [publicId isEqualToString:requiredPublicId];
|
|
403
|
+
if (isRequiredPublicId) {
|
|
404
|
+
foundRequiredPublicId = YES;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
NSDictionary *record = records[publicId];
|
|
408
|
+
NSDictionary *notification = record[@"notification"];
|
|
409
|
+
NSDictionary *trigger = record[@"trigger"];
|
|
410
|
+
if (![notification isKindOfClass:NSDictionary.class] ||
|
|
411
|
+
![trigger isKindOfClass:NSDictionary.class] ||
|
|
412
|
+
![NotifeeCoreUtil isRollingTimestampTrigger:trigger]) {
|
|
413
|
+
if (isRequiredPublicId && error != nil) {
|
|
414
|
+
*error = [self
|
|
415
|
+
rollingTimestampErrorWithCode:NotifeeCoreRollingErrorCodeInvalidTrigger
|
|
416
|
+
message:@"NotifeeCore: Rolling timestamp trigger requires a "
|
|
417
|
+
@"valid notification and trigger record."];
|
|
418
|
+
return nil;
|
|
419
|
+
}
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
NSArray<NSNumber *> *firstOccurrence =
|
|
424
|
+
[NotifeeCoreUtil rollingTimestampOccurrencesFromTrigger:trigger nowMs:nowMs maxCount:1];
|
|
425
|
+
NSNumber *firstOccurrenceMs = [firstOccurrence firstObject];
|
|
426
|
+
NSString *firstInternalId =
|
|
427
|
+
[NotifeeCoreUtil rollingInternalNotificationIdForPublicId:publicId
|
|
428
|
+
occurrenceMs:firstOccurrenceMs];
|
|
429
|
+
if (firstOccurrenceMs == nil || firstInternalId == nil) {
|
|
430
|
+
if (isRequiredPublicId && error != nil) {
|
|
431
|
+
*error =
|
|
432
|
+
[self rollingTimestampErrorWithCode:NotifeeCoreRollingErrorCodeInvalidTrigger
|
|
433
|
+
message:@"NotifeeCore: Rolling timestamp trigger did not "
|
|
434
|
+
@"produce any future occurrences."];
|
|
435
|
+
return nil;
|
|
436
|
+
}
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
NSNumber *createdAt = record[@"createdAtMs"];
|
|
441
|
+
if (![createdAt isKindOfClass:NSNumber.class]) {
|
|
442
|
+
createdAt = nowMs;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
NSMutableDictionary *state = [NSMutableDictionary dictionary];
|
|
446
|
+
state[@"publicId"] = publicId;
|
|
447
|
+
state[@"notification"] = notification;
|
|
448
|
+
state[@"trigger"] = trigger;
|
|
449
|
+
state[@"createdAtMs"] = createdAt;
|
|
450
|
+
state[@"quota"] = @0;
|
|
451
|
+
[states addObject:state];
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (!foundRequiredPublicId) {
|
|
455
|
+
if (error != nil) {
|
|
456
|
+
*error = [self rollingTimestampErrorWithCode:NotifeeCoreRollingErrorCodeInvalidTrigger
|
|
457
|
+
message:@"NotifeeCore: Rolling timestamp trigger "
|
|
458
|
+
@"record was not found for rebalance."];
|
|
459
|
+
}
|
|
460
|
+
return nil;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
[states
|
|
464
|
+
sortUsingComparator:^NSComparisonResult(NSDictionary *firstState, NSDictionary *secondState) {
|
|
465
|
+
return [self compareRollingRebalanceState:firstState otherState:secondState];
|
|
466
|
+
}];
|
|
467
|
+
|
|
468
|
+
return states;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
+ (BOOL)prepareRollingRebalanceDesiredSchedulesForStates:(NSArray<NSMutableDictionary *> *)states
|
|
472
|
+
nowMs:(NSNumber *)nowMs
|
|
473
|
+
error:(NSError **)error {
|
|
474
|
+
for (NSMutableDictionary *state in states) {
|
|
475
|
+
NSInteger quota = [state[@"quota"] integerValue];
|
|
476
|
+
if (quota <= 0) {
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
NSString *publicId = state[@"publicId"];
|
|
481
|
+
NSDictionary *notification = state[@"notification"];
|
|
482
|
+
NSDictionary *trigger = state[@"trigger"];
|
|
483
|
+
NSArray<NSNumber *> *occurrences =
|
|
484
|
+
[NotifeeCoreUtil rollingTimestampOccurrencesFromTrigger:trigger nowMs:nowMs maxCount:quota];
|
|
485
|
+
if ([occurrences count] == 0) {
|
|
486
|
+
if (error != nil) {
|
|
487
|
+
*error =
|
|
488
|
+
[self rollingTimestampErrorWithCode:NotifeeCoreRollingErrorCodeInvalidTrigger
|
|
489
|
+
message:@"NotifeeCore: Rolling timestamp trigger did not "
|
|
490
|
+
@"produce any future occurrences."];
|
|
491
|
+
}
|
|
492
|
+
return NO;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
UNMutableNotificationContent *content =
|
|
496
|
+
[self triggerNotificationContentForNotification:notification trigger:trigger];
|
|
497
|
+
NSMutableOrderedSet<NSString *> *desiredIds = [NSMutableOrderedSet orderedSet];
|
|
498
|
+
NSMutableDictionary<NSString *, UNNotificationRequest *> *desiredRequests =
|
|
499
|
+
[NSMutableDictionary dictionary];
|
|
500
|
+
NSNumber *lastScheduledOccurrence = nil;
|
|
501
|
+
|
|
502
|
+
for (NSNumber *occurrenceMs in occurrences) {
|
|
503
|
+
if ([desiredIds count] >= (NSUInteger)quota) {
|
|
504
|
+
break;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
NSError *requestError = nil;
|
|
508
|
+
UNNotificationRequest *request = [self rollingNotificationRequestForPublicId:publicId
|
|
509
|
+
occurrenceMs:occurrenceMs
|
|
510
|
+
content:content
|
|
511
|
+
error:&requestError];
|
|
512
|
+
if (request == nil) {
|
|
513
|
+
if (error != nil) {
|
|
514
|
+
*error = requestError;
|
|
515
|
+
}
|
|
516
|
+
return NO;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if ([desiredIds containsObject:request.identifier]) {
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
[desiredIds addObject:request.identifier];
|
|
524
|
+
desiredRequests[request.identifier] = request;
|
|
525
|
+
lastScheduledOccurrence = occurrenceMs;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if ([desiredIds count] == 0 || lastScheduledOccurrence == nil) {
|
|
529
|
+
if (error != nil) {
|
|
530
|
+
*error =
|
|
531
|
+
[self rollingTimestampErrorWithCode:NotifeeCoreRollingErrorCodeInvalidTrigger
|
|
532
|
+
message:@"NotifeeCore: Rolling timestamp trigger did not "
|
|
533
|
+
@"produce any future occurrences."];
|
|
534
|
+
}
|
|
535
|
+
return NO;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
NSMutableDictionary *updatedRecord = [NSMutableDictionary dictionary];
|
|
539
|
+
updatedRecord[@"publicId"] = publicId;
|
|
540
|
+
updatedRecord[@"notification"] = notification;
|
|
541
|
+
updatedRecord[@"trigger"] = trigger;
|
|
542
|
+
updatedRecord[@"scheduledIds"] = [desiredIds array];
|
|
543
|
+
updatedRecord[@"lastScheduledOccurrenceMs"] = lastScheduledOccurrence;
|
|
544
|
+
updatedRecord[@"createdAtMs"] = state[@"createdAtMs"];
|
|
545
|
+
|
|
546
|
+
state[@"desiredIds"] = desiredIds;
|
|
547
|
+
state[@"desiredRequests"] = desiredRequests;
|
|
548
|
+
state[@"updatedRecord"] = updatedRecord;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
return YES;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
+ (void)rollbackRollingRebalanceRemovedRequests:(NSArray<UNNotificationRequest *> *)removedRequests
|
|
555
|
+
successfulNewIdentifiers:(NSSet<NSString *> *)successfulNewIdentifiers
|
|
556
|
+
center:(UNUserNotificationCenter *)center {
|
|
557
|
+
if ([successfulNewIdentifiers count] > 0) {
|
|
558
|
+
[self removeRollingPendingRequestsForIds:[successfulNewIdentifiers allObjects] center:center];
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
if ([removedRequests count] > 0) {
|
|
562
|
+
[self scheduleRollingNotificationRequests:removedRequests
|
|
563
|
+
center:center
|
|
564
|
+
successfulIdentifiers:nil];
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
+ (BOOL)rebalanceRollingTimestampTriggerRecords:(NSDictionary *)records
|
|
569
|
+
center:(UNUserNotificationCenter *)center
|
|
570
|
+
pendingRequests:(NSArray<UNNotificationRequest *> *)pendingRequests
|
|
571
|
+
nowMs:(NSNumber *)nowMs
|
|
572
|
+
refreshPublicId:(NSString *)refreshPublicId
|
|
573
|
+
requiredPublicId:(NSString *)requiredPublicId
|
|
574
|
+
error:(NSError **)error {
|
|
575
|
+
NSError *stateError = nil;
|
|
576
|
+
NSArray<NSMutableDictionary *> *states = [self rollingRebalanceStatesFromRecords:records
|
|
577
|
+
nowMs:nowMs
|
|
578
|
+
requiredPublicId:requiredPublicId
|
|
579
|
+
error:&stateError];
|
|
580
|
+
if (states == nil) {
|
|
581
|
+
if (error != nil) {
|
|
582
|
+
*error = stateError;
|
|
583
|
+
}
|
|
584
|
+
return NO;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
NSMutableSet<NSString *> *pendingIdentifierSet =
|
|
588
|
+
[self pendingIdentifierSetFromRequests:pendingRequests];
|
|
589
|
+
NSMutableDictionary<NSString *, UNNotificationRequest *> *pendingRequestByIdentifier =
|
|
590
|
+
[NSMutableDictionary dictionary];
|
|
591
|
+
NSMutableOrderedSet<NSString *> *rollingPendingIdentifiers = [NSMutableOrderedSet orderedSet];
|
|
592
|
+
NSMutableOrderedSet<NSString *> *replacementPendingIdentifiers = [NSMutableOrderedSet orderedSet];
|
|
593
|
+
NSInteger nonRollingPendingCount = 0;
|
|
594
|
+
|
|
595
|
+
for (UNNotificationRequest *request in pendingRequests) {
|
|
596
|
+
NSString *identifier = request.identifier;
|
|
597
|
+
if (![identifier isKindOfClass:NSString.class] || [identifier length] == 0) {
|
|
598
|
+
continue;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
pendingRequestByIdentifier[identifier] = request;
|
|
602
|
+
if ([self isPotentialRollingInternalNotificationId:identifier]) {
|
|
603
|
+
[rollingPendingIdentifiers addObject:identifier];
|
|
604
|
+
} else if ([identifier isEqualToString:refreshPublicId]) {
|
|
605
|
+
[replacementPendingIdentifiers addObject:identifier];
|
|
606
|
+
} else {
|
|
607
|
+
nonRollingPendingCount += 1;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
NSInteger rollingBudget = [NotifeeCoreUtil rollingPendingBudget] - nonRollingPendingCount;
|
|
612
|
+
if (rollingBudget < 0) {
|
|
613
|
+
rollingBudget = 0;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
if ((NSInteger)[states count] > rollingBudget) {
|
|
617
|
+
if (error != nil) {
|
|
618
|
+
*error = [self
|
|
619
|
+
rollingTimestampErrorWithCode:NotifeeCoreRollingErrorCodeBudgetExceeded
|
|
620
|
+
message:@"NotifeeCore: iOS rolling timestamp trigger budget "
|
|
621
|
+
@"cannot allocate one occurrence per active trigger."];
|
|
622
|
+
}
|
|
623
|
+
return NO;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
NSInteger targetPerTrigger = [NotifeeCoreUtil rollingTargetPerTrigger];
|
|
627
|
+
NSInteger remainingBudget = rollingBudget;
|
|
628
|
+
for (NSMutableDictionary *state in states) {
|
|
629
|
+
state[@"quota"] = @1;
|
|
630
|
+
remainingBudget -= 1;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
BOOL allocatedAdditionalSlot = YES;
|
|
634
|
+
while (remainingBudget > 0 && allocatedAdditionalSlot) {
|
|
635
|
+
allocatedAdditionalSlot = NO;
|
|
636
|
+
for (NSMutableDictionary *state in states) {
|
|
637
|
+
if (remainingBudget <= 0) {
|
|
638
|
+
break;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
NSInteger quota = [state[@"quota"] integerValue];
|
|
642
|
+
if (quota >= targetPerTrigger) {
|
|
643
|
+
continue;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
state[@"quota"] = @(quota + 1);
|
|
647
|
+
remainingBudget -= 1;
|
|
648
|
+
allocatedAdditionalSlot = YES;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
NSError *planError = nil;
|
|
653
|
+
if (![self prepareRollingRebalanceDesiredSchedulesForStates:states
|
|
654
|
+
nowMs:nowMs
|
|
655
|
+
error:&planError]) {
|
|
656
|
+
if (error != nil) {
|
|
657
|
+
*error = planError;
|
|
658
|
+
}
|
|
659
|
+
return NO;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
NSMutableOrderedSet<NSString *> *desiredIdentifiers = [NSMutableOrderedSet orderedSet];
|
|
663
|
+
NSMutableDictionary *updatedRecords = [NSMutableDictionary dictionary];
|
|
664
|
+
for (NSMutableDictionary *state in states) {
|
|
665
|
+
NSOrderedSet<NSString *> *stateDesiredIds = state[@"desiredIds"];
|
|
666
|
+
[desiredIdentifiers unionOrderedSet:stateDesiredIds];
|
|
667
|
+
|
|
668
|
+
NSString *publicId = state[@"publicId"];
|
|
669
|
+
NSDictionary *updatedRecord = state[@"updatedRecord"];
|
|
670
|
+
if (publicId != nil && updatedRecord != nil) {
|
|
671
|
+
updatedRecords[publicId] = updatedRecord;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
if (requiredPublicId != nil && updatedRecords[requiredPublicId] == nil) {
|
|
676
|
+
if (error != nil) {
|
|
677
|
+
*error = [self
|
|
678
|
+
rollingTimestampErrorWithCode:NotifeeCoreRollingErrorCodeInvalidTrigger
|
|
679
|
+
message:@"NotifeeCore: Rolling timestamp trigger did not produce "
|
|
680
|
+
@"any future occurrences."];
|
|
681
|
+
}
|
|
682
|
+
return NO;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
NSMutableOrderedSet<NSString *> *identifiersToRemove = [NSMutableOrderedSet orderedSet];
|
|
686
|
+
for (NSString *identifier in rollingPendingIdentifiers) {
|
|
687
|
+
if (![desiredIdentifiers containsObject:identifier]) {
|
|
688
|
+
[identifiersToRemove addObject:identifier];
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
[identifiersToRemove unionOrderedSet:replacementPendingIdentifiers];
|
|
692
|
+
|
|
693
|
+
NSMutableArray<UNNotificationRequest *> *removedRequests = [NSMutableArray array];
|
|
694
|
+
for (NSString *identifier in identifiersToRemove) {
|
|
695
|
+
UNNotificationRequest *request = pendingRequestByIdentifier[identifier];
|
|
696
|
+
if (request != nil) {
|
|
697
|
+
[removedRequests addObject:request];
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
NSMutableArray<UNNotificationRequest *> *requestsToSchedule = [NSMutableArray array];
|
|
702
|
+
NSMutableSet<NSString *> *newRequestIdentifiers = [NSMutableSet set];
|
|
703
|
+
for (NSMutableDictionary *state in states) {
|
|
704
|
+
NSString *publicId = state[@"publicId"];
|
|
705
|
+
NSOrderedSet<NSString *> *stateDesiredIds = state[@"desiredIds"];
|
|
706
|
+
NSDictionary<NSString *, UNNotificationRequest *> *desiredRequests = state[@"desiredRequests"];
|
|
707
|
+
BOOL shouldRefresh = refreshPublicId != nil && [publicId isEqualToString:refreshPublicId];
|
|
708
|
+
|
|
709
|
+
for (NSString *identifier in stateDesiredIds) {
|
|
710
|
+
UNNotificationRequest *request = desiredRequests[identifier];
|
|
711
|
+
if (request == nil) {
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
BOOL isAlreadyPending = [pendingIdentifierSet containsObject:identifier];
|
|
716
|
+
if (!isAlreadyPending || shouldRefresh) {
|
|
717
|
+
[requestsToSchedule addObject:request];
|
|
718
|
+
}
|
|
719
|
+
if (!isAlreadyPending) {
|
|
720
|
+
[newRequestIdentifiers addObject:identifier];
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
[self removeRollingPendingRequestsForIds:[identifiersToRemove array] center:center];
|
|
726
|
+
|
|
727
|
+
NSMutableSet<NSString *> *successfulScheduledIdentifiers = [NSMutableSet set];
|
|
728
|
+
NSError *scheduleError =
|
|
729
|
+
[self scheduleRollingNotificationRequests:requestsToSchedule
|
|
730
|
+
center:center
|
|
731
|
+
successfulIdentifiers:successfulScheduledIdentifiers];
|
|
732
|
+
if (scheduleError != nil) {
|
|
733
|
+
NSMutableSet<NSString *> *successfulNewIdentifiers = [NSMutableSet set];
|
|
734
|
+
for (NSString *identifier in successfulScheduledIdentifiers) {
|
|
735
|
+
if ([newRequestIdentifiers containsObject:identifier]) {
|
|
736
|
+
[successfulNewIdentifiers addObject:identifier];
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
[self rollbackRollingRebalanceRemovedRequests:removedRequests
|
|
741
|
+
successfulNewIdentifiers:successfulNewIdentifiers
|
|
742
|
+
center:center];
|
|
743
|
+
if (error != nil) {
|
|
744
|
+
*error = scheduleError;
|
|
745
|
+
}
|
|
746
|
+
return NO;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
[NotifeeCoreUtil setRollingTimestampTriggers:updatedRecords];
|
|
750
|
+
NSDictionary *persistedRecords = [NotifeeCoreUtil getRollingTimestampTriggers];
|
|
751
|
+
if (![self persistedRollingRecords:persistedRecords matchUpdatedRecords:updatedRecords]) {
|
|
752
|
+
NSMutableSet<NSString *> *successfulNewIdentifiers = [NSMutableSet set];
|
|
753
|
+
for (NSString *identifier in successfulScheduledIdentifiers) {
|
|
754
|
+
if ([newRequestIdentifiers containsObject:identifier]) {
|
|
755
|
+
[successfulNewIdentifiers addObject:identifier];
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
[self removeRollingPendingRequestsForIds:[successfulNewIdentifiers allObjects] center:center];
|
|
759
|
+
|
|
760
|
+
if (error != nil) {
|
|
761
|
+
*error =
|
|
762
|
+
[self rollingTimestampErrorWithCode:NotifeeCoreRollingErrorCodeStorageFailed
|
|
763
|
+
message:@"NotifeeCore: Failed to persist rolling timestamp "
|
|
764
|
+
@"trigger records after rebalance."];
|
|
765
|
+
}
|
|
766
|
+
return NO;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
return YES;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
+ (void)topUpRollingTimestampTriggersWithCompletion:(void (^)(NSError *error))completion {
|
|
773
|
+
dispatch_async([self rollingTimestampQueue], ^{
|
|
774
|
+
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
|
|
775
|
+
NSNumber *nowMs = [self currentTimestampMs];
|
|
776
|
+
NSArray<UNNotificationRequest *> *pendingRequests = [self pendingNotificationRequests:center];
|
|
777
|
+
NSMutableDictionary *records = [NotifeeCoreUtil getRollingTimestampTriggers];
|
|
778
|
+
NSError *topUpError = nil;
|
|
779
|
+
|
|
780
|
+
[self rebalanceRollingTimestampTriggerRecords:records
|
|
781
|
+
center:center
|
|
782
|
+
pendingRequests:pendingRequests
|
|
783
|
+
nowMs:nowMs
|
|
784
|
+
refreshPublicId:nil
|
|
785
|
+
requiredPublicId:nil
|
|
786
|
+
error:&topUpError];
|
|
787
|
+
|
|
788
|
+
if (completion != nil) {
|
|
789
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
790
|
+
completion(topUpError);
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
+ (void)createRollingTriggerNotification:(NSDictionary *)notification
|
|
797
|
+
withTrigger:(NSDictionary *)trigger
|
|
798
|
+
withNotificationDetail:(NSDictionary *)notificationDetail
|
|
799
|
+
center:(UNUserNotificationCenter *)center
|
|
800
|
+
block:(notifeeMethodVoidBlock)block {
|
|
801
|
+
dispatch_async([self rollingTimestampQueue], ^{
|
|
802
|
+
NSString *publicId = [self rollingPublicIdForNotification:notification];
|
|
803
|
+
if (publicId == nil) {
|
|
804
|
+
NSError *error =
|
|
805
|
+
[self rollingTimestampErrorWithCode:NotifeeCoreRollingErrorCodeInvalidTrigger
|
|
806
|
+
message:@"NotifeeCore: Rolling timestamp trigger requires a "
|
|
807
|
+
@"notification id."];
|
|
808
|
+
[self resolveBlock:block withError:error];
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
NSArray<UNNotificationRequest *> *pendingRequests = [self pendingNotificationRequests:center];
|
|
813
|
+
NSMutableDictionary *records = [NotifeeCoreUtil getRollingTimestampTriggers];
|
|
814
|
+
NSNumber *nowMs = [self currentTimestampMs];
|
|
815
|
+
NSDictionary *record = @{
|
|
816
|
+
@"publicId" : publicId,
|
|
817
|
+
@"notification" : notification,
|
|
818
|
+
@"trigger" : trigger,
|
|
819
|
+
@"scheduledIds" : @[],
|
|
820
|
+
@"createdAtMs" : nowMs
|
|
821
|
+
};
|
|
822
|
+
records[publicId] = record;
|
|
823
|
+
|
|
824
|
+
NSError *rebalanceError = nil;
|
|
825
|
+
if (![self rebalanceRollingTimestampTriggerRecords:records
|
|
826
|
+
center:center
|
|
827
|
+
pendingRequests:pendingRequests
|
|
828
|
+
nowMs:nowMs
|
|
829
|
+
refreshPublicId:publicId
|
|
830
|
+
requiredPublicId:publicId
|
|
831
|
+
error:&rebalanceError]) {
|
|
832
|
+
[self resolveBlock:block withError:rebalanceError];
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
837
|
+
[[NotifeeCoreDelegateHolder instance] didReceiveNotifeeCoreEvent:@{
|
|
838
|
+
@"type" : @(NotifeeCoreEventTypeTriggerNotificationCreated),
|
|
839
|
+
@"detail" : @{
|
|
840
|
+
@"notification" : notificationDetail,
|
|
841
|
+
}
|
|
842
|
+
}];
|
|
843
|
+
block(nil);
|
|
844
|
+
});
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
+ (void)cancelRollingNotification:(NSString *)notificationId
|
|
849
|
+
withNotificationType:(NSInteger)notificationType
|
|
850
|
+
block:(notifeeMethodVoidBlock)block {
|
|
851
|
+
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
|
|
852
|
+
BOOL cancelDisplayed = notificationType == NotifeeCoreNotificationTypeDisplayed ||
|
|
853
|
+
notificationType == NotifeeCoreNotificationTypeAll;
|
|
854
|
+
BOOL cancelTrigger = notificationType == NotifeeCoreNotificationTypeTrigger ||
|
|
855
|
+
notificationType == NotifeeCoreNotificationTypeAll;
|
|
856
|
+
|
|
857
|
+
if (!cancelDisplayed && !cancelTrigger) {
|
|
858
|
+
block(nil);
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
dispatch_async([self rollingTimestampQueue], ^{
|
|
863
|
+
NSDictionary *records = [NotifeeCoreUtil getRollingTimestampTriggers];
|
|
864
|
+
NSDictionary *record = records[notificationId];
|
|
865
|
+
|
|
866
|
+
if (cancelDisplayed) {
|
|
867
|
+
NSArray<UNNotification *> *deliveredNotifications = [self deliveredNotifications:center];
|
|
868
|
+
NSMutableOrderedSet<NSString *> *deliveredIdentifiersToRemove =
|
|
869
|
+
[self rollingDeliveredIdentifiersForPublicId:notificationId
|
|
870
|
+
deliveredNotifications:deliveredNotifications
|
|
871
|
+
record:record];
|
|
872
|
+
[self addString:notificationId toOrderedSet:deliveredIdentifiersToRemove];
|
|
873
|
+
if ([deliveredIdentifiersToRemove count] > 0) {
|
|
874
|
+
[center removeDeliveredNotificationsWithIdentifiers:[deliveredIdentifiersToRemove array]];
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
if (cancelTrigger) {
|
|
879
|
+
NSArray<UNNotificationRequest *> *pendingRequests = [self pendingNotificationRequests:center];
|
|
880
|
+
NSMutableOrderedSet<NSString *> *pendingIdentifiersToRemove =
|
|
881
|
+
[self rollingIdentifiersForPublicId:notificationId
|
|
882
|
+
pendingRequests:pendingRequests
|
|
883
|
+
record:record];
|
|
884
|
+
[self addString:notificationId toOrderedSet:pendingIdentifiersToRemove];
|
|
885
|
+
|
|
886
|
+
[self removeRollingPendingRequestsForIds:[pendingIdentifiersToRemove array] center:center];
|
|
887
|
+
if (record != nil) {
|
|
888
|
+
[NotifeeCoreUtil removeRollingTimestampTriggerRecordForPublicId:notificationId];
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
[self resolveBlock:block withError:nil];
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
+ (void)cancelRollingNotificationsWithIds:(NSArray<NSString *> *)ids
|
|
897
|
+
withNotificationType:(NSInteger)notificationType
|
|
898
|
+
block:(notifeeMethodVoidBlock)block {
|
|
899
|
+
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
|
|
900
|
+
BOOL cancelDisplayed = notificationType == NotifeeCoreNotificationTypeDisplayed ||
|
|
901
|
+
notificationType == NotifeeCoreNotificationTypeAll;
|
|
902
|
+
BOOL cancelTrigger = notificationType == NotifeeCoreNotificationTypeTrigger ||
|
|
903
|
+
notificationType == NotifeeCoreNotificationTypeAll;
|
|
904
|
+
|
|
905
|
+
NSMutableOrderedSet<NSString *> *publicIds = [NSMutableOrderedSet orderedSet];
|
|
906
|
+
for (id notificationId in ids) {
|
|
907
|
+
[self addString:notificationId toOrderedSet:publicIds];
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
if (!cancelDisplayed && !cancelTrigger) {
|
|
911
|
+
block(nil);
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
dispatch_async([self rollingTimestampQueue], ^{
|
|
916
|
+
NSDictionary *records = [NotifeeCoreUtil getRollingTimestampTriggers];
|
|
917
|
+
NSArray<UNNotification *> *deliveredNotifications =
|
|
918
|
+
cancelDisplayed ? [self deliveredNotifications:center] : @[];
|
|
919
|
+
NSArray<UNNotificationRequest *> *pendingRequests =
|
|
920
|
+
cancelTrigger ? [self pendingNotificationRequests:center] : @[];
|
|
921
|
+
NSMutableOrderedSet<NSString *> *deliveredIdentifiersToRemove =
|
|
922
|
+
[NSMutableOrderedSet orderedSet];
|
|
923
|
+
NSMutableOrderedSet<NSString *> *pendingIdentifiersToRemove = [NSMutableOrderedSet orderedSet];
|
|
924
|
+
|
|
925
|
+
for (NSString *publicId in publicIds) {
|
|
926
|
+
NSDictionary *record = records[publicId];
|
|
927
|
+
|
|
928
|
+
if (cancelDisplayed) {
|
|
929
|
+
NSMutableOrderedSet<NSString *> *rollingDeliveredIdentifiers =
|
|
930
|
+
[self rollingDeliveredIdentifiersForPublicId:publicId
|
|
931
|
+
deliveredNotifications:deliveredNotifications
|
|
932
|
+
record:record];
|
|
933
|
+
[deliveredIdentifiersToRemove unionOrderedSet:rollingDeliveredIdentifiers];
|
|
934
|
+
[self addString:publicId toOrderedSet:deliveredIdentifiersToRemove];
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
if (cancelTrigger) {
|
|
938
|
+
NSMutableOrderedSet<NSString *> *rollingPendingIdentifiers =
|
|
939
|
+
[self rollingIdentifiersForPublicId:publicId
|
|
940
|
+
pendingRequests:pendingRequests
|
|
941
|
+
record:record];
|
|
942
|
+
[pendingIdentifiersToRemove unionOrderedSet:rollingPendingIdentifiers];
|
|
943
|
+
[self addString:publicId toOrderedSet:pendingIdentifiersToRemove];
|
|
944
|
+
if (record != nil) {
|
|
945
|
+
[NotifeeCoreUtil removeRollingTimestampTriggerRecordForPublicId:publicId];
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
if ([deliveredIdentifiersToRemove count] > 0) {
|
|
951
|
+
[center removeDeliveredNotificationsWithIdentifiers:[deliveredIdentifiersToRemove array]];
|
|
952
|
+
}
|
|
953
|
+
[self removeRollingPendingRequestsForIds:[pendingIdentifiersToRemove array] center:center];
|
|
954
|
+
[self resolveBlock:block withError:nil];
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
|
|
30
958
|
#pragma mark - Library Methods
|
|
31
959
|
|
|
32
960
|
+ (void)setCoreDelegate:(id<NotifeeCoreDelegate>)coreDelegate {
|
|
@@ -42,17 +970,7 @@
|
|
|
42
970
|
+ (void)cancelNotification:(NSString *)notificationId
|
|
43
971
|
withNotificationType:(NSInteger)notificationType
|
|
44
972
|
withBlock:(notifeeMethodVoidBlock)block {
|
|
45
|
-
|
|
46
|
-
// cancel displayed notification
|
|
47
|
-
if (notificationType == NotifeeCoreNotificationTypeDisplayed ||
|
|
48
|
-
notificationType == NotifeeCoreNotificationTypeAll)
|
|
49
|
-
[center removeDeliveredNotificationsWithIdentifiers:@[ notificationId ]];
|
|
50
|
-
|
|
51
|
-
// cancel trigger notification
|
|
52
|
-
if (notificationType == NotifeeCoreNotificationTypeTrigger ||
|
|
53
|
-
notificationType == NotifeeCoreNotificationTypeAll)
|
|
54
|
-
[center removePendingNotificationRequestsWithIdentifiers:@[ notificationId ]];
|
|
55
|
-
block(nil);
|
|
973
|
+
[self cancelRollingNotification:notificationId withNotificationType:notificationType block:block];
|
|
56
974
|
}
|
|
57
975
|
|
|
58
976
|
/**
|
|
@@ -69,11 +987,17 @@
|
|
|
69
987
|
notificationType == NotifeeCoreNotificationTypeAll)
|
|
70
988
|
[center removeAllDeliveredNotifications];
|
|
71
989
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
990
|
+
if (notificationType != NotifeeCoreNotificationTypeTrigger &&
|
|
991
|
+
notificationType != NotifeeCoreNotificationTypeAll) {
|
|
992
|
+
block(nil);
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
dispatch_async([self rollingTimestampQueue], ^{
|
|
75
997
|
[center removeAllPendingNotificationRequests];
|
|
76
|
-
|
|
998
|
+
[NotifeeCoreUtil clearRollingTimestampTriggerRecords];
|
|
999
|
+
[self resolveBlock:block withError:nil];
|
|
1000
|
+
});
|
|
77
1001
|
}
|
|
78
1002
|
|
|
79
1003
|
/**
|
|
@@ -86,18 +1010,7 @@
|
|
|
86
1010
|
+ (void)cancelAllNotificationsWithIds:(NSInteger)notificationType
|
|
87
1011
|
withIds:(NSArray<NSString *> *)ids
|
|
88
1012
|
withBlock:(notifeeMethodVoidBlock)block {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
// cancel displayed notifications
|
|
92
|
-
if (notificationType == NotifeeCoreNotificationTypeDisplayed ||
|
|
93
|
-
notificationType == NotifeeCoreNotificationTypeAll)
|
|
94
|
-
[center removeDeliveredNotificationsWithIdentifiers:ids];
|
|
95
|
-
|
|
96
|
-
// cancel trigger notifications
|
|
97
|
-
if (notificationType == NotifeeCoreNotificationTypeTrigger ||
|
|
98
|
-
notificationType == NotifeeCoreNotificationTypeAll)
|
|
99
|
-
[center removePendingNotificationRequestsWithIdentifiers:ids];
|
|
100
|
-
block(nil);
|
|
1013
|
+
[self cancelRollingNotificationsWithIds:ids withNotificationType:notificationType block:block];
|
|
101
1014
|
}
|
|
102
1015
|
|
|
103
1016
|
+ (void)getDisplayedNotifications:(notifeeMethodNSArrayBlock)block {
|
|
@@ -106,20 +1019,31 @@
|
|
|
106
1019
|
[center getDeliveredNotificationsWithCompletionHandler:^(
|
|
107
1020
|
NSArray<UNNotification *> *_Nonnull deliveredNotifications) {
|
|
108
1021
|
for (UNNotification *deliveredNotification in deliveredNotifications) {
|
|
1022
|
+
UNNotificationRequest *request = deliveredNotification.request;
|
|
1023
|
+
NSString *notificationId = [self publicIdentifierForRequest:request];
|
|
1024
|
+
if (notificationId == nil) {
|
|
1025
|
+
continue;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
109
1028
|
NSMutableDictionary *triggerNotification = [NSMutableDictionary dictionary];
|
|
110
|
-
triggerNotification[@"id"] =
|
|
1029
|
+
triggerNotification[@"id"] = notificationId;
|
|
111
1030
|
|
|
112
1031
|
triggerNotification[@"date"] =
|
|
113
1032
|
[NotifeeCoreUtil convertToTimestamp:deliveredNotification.date];
|
|
114
|
-
triggerNotification[@"notification"] =
|
|
115
|
-
|
|
116
|
-
triggerNotification[@"trigger"] =
|
|
117
|
-
deliveredNotification.request.content.userInfo[kNotifeeUserInfoTrigger];
|
|
1033
|
+
triggerNotification[@"notification"] = request.content.userInfo[kNotifeeUserInfoNotification];
|
|
1034
|
+
triggerNotification[@"trigger"] = request.content.userInfo[kNotifeeUserInfoTrigger];
|
|
118
1035
|
|
|
119
1036
|
if (triggerNotification[@"notification"] == nil) {
|
|
120
1037
|
// parse remote notification
|
|
121
|
-
triggerNotification[@"notification"] =
|
|
122
|
-
|
|
1038
|
+
triggerNotification[@"notification"] = [NotifeeCoreUtil parseUNNotificationRequest:request];
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
NSString *rollingPublicId = [self rollingPublicIdForRequest:request];
|
|
1042
|
+
NSDictionary *notification = triggerNotification[@"notification"];
|
|
1043
|
+
if (rollingPublicId != nil && [notification isKindOfClass:NSDictionary.class]) {
|
|
1044
|
+
NSMutableDictionary *publicNotification = [notification mutableCopy];
|
|
1045
|
+
publicNotification[@"id"] = rollingPublicId;
|
|
1046
|
+
triggerNotification[@"notification"] = publicNotification;
|
|
123
1047
|
}
|
|
124
1048
|
|
|
125
1049
|
[triggerNotifications addObject:triggerNotification];
|
|
@@ -133,9 +1057,41 @@
|
|
|
133
1057
|
|
|
134
1058
|
[center getPendingNotificationRequestsWithCompletionHandler:^(
|
|
135
1059
|
NSArray<UNNotificationRequest *> *_Nonnull requests) {
|
|
1060
|
+
NSDictionary *rollingRecords = [NotifeeCoreUtil getRollingTimestampTriggers];
|
|
1061
|
+
NSMutableSet<NSString *> *rollingPublicIds = [NSMutableSet set];
|
|
136
1062
|
NSMutableArray *triggerNotifications = [[NSMutableArray alloc] init];
|
|
137
1063
|
|
|
1064
|
+
for (id publicId in rollingRecords) {
|
|
1065
|
+
if (![publicId isKindOfClass:NSString.class]) {
|
|
1066
|
+
continue;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
NSDictionary *record = rollingRecords[publicId];
|
|
1070
|
+
NSDictionary *notification = record[@"notification"];
|
|
1071
|
+
NSDictionary *trigger = record[@"trigger"];
|
|
1072
|
+
if (![notification isKindOfClass:NSDictionary.class] ||
|
|
1073
|
+
![trigger isKindOfClass:NSDictionary.class]) {
|
|
1074
|
+
continue;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
NSMutableDictionary *triggerNotification = [NSMutableDictionary dictionary];
|
|
1078
|
+
triggerNotification[@"notification"] = notification;
|
|
1079
|
+
triggerNotification[@"trigger"] = trigger;
|
|
1080
|
+
[triggerNotifications addObject:triggerNotification];
|
|
1081
|
+
[rollingPublicIds addObject:publicId];
|
|
1082
|
+
}
|
|
1083
|
+
|
|
138
1084
|
for (UNNotificationRequest *request in requests) {
|
|
1085
|
+
NSString *rollingPublicId =
|
|
1086
|
+
[NotifeeCoreUtil rollingPublicIdFromInternalNotificationId:request.identifier];
|
|
1087
|
+
if (rollingPublicId != nil) {
|
|
1088
|
+
continue;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
if ([rollingPublicIds containsObject:request.identifier]) {
|
|
1092
|
+
continue;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
139
1095
|
NSMutableDictionary *triggerNotification = [NSMutableDictionary dictionary];
|
|
140
1096
|
|
|
141
1097
|
triggerNotification[@"notification"] = request.content.userInfo[kNotifeeUserInfoNotification];
|
|
@@ -158,14 +1114,21 @@
|
|
|
158
1114
|
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
|
|
159
1115
|
[center getPendingNotificationRequestsWithCompletionHandler:^(
|
|
160
1116
|
NSArray<UNNotificationRequest *> *_Nonnull requests) {
|
|
161
|
-
|
|
1117
|
+
NSMutableOrderedSet<NSString *> *ids = [NSMutableOrderedSet orderedSet];
|
|
162
1118
|
|
|
163
1119
|
for (UNNotificationRequest *request in requests) {
|
|
164
1120
|
NSString *notificationId = request.identifier;
|
|
165
|
-
|
|
1121
|
+
NSString *rollingPublicId =
|
|
1122
|
+
[NotifeeCoreUtil rollingPublicIdFromInternalNotificationId:notificationId];
|
|
1123
|
+
[self addString:(rollingPublicId != nil ? rollingPublicId : notificationId) toOrderedSet:ids];
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
NSDictionary *rollingRecords = [NotifeeCoreUtil getRollingTimestampTriggers];
|
|
1127
|
+
for (id publicId in rollingRecords) {
|
|
1128
|
+
[self addString:publicId toOrderedSet:ids];
|
|
166
1129
|
}
|
|
167
1130
|
|
|
168
|
-
block(nil,
|
|
1131
|
+
block(nil, [ids array]);
|
|
169
1132
|
}];
|
|
170
1133
|
}
|
|
171
1134
|
|
|
@@ -219,26 +1182,33 @@
|
|
|
219
1182
|
trigger:nil];
|
|
220
1183
|
|
|
221
1184
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
222
|
-
[center
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
1185
|
+
[center addNotificationRequest:request
|
|
1186
|
+
withCompletionHandler:^(NSError *error) {
|
|
1187
|
+
if (error == nil) {
|
|
1188
|
+
// When the app is in foreground, willPresentNotification: emits
|
|
1189
|
+
// DELIVERED for all Notifee-owned notifications. Only emit here
|
|
1190
|
+
// when the app is NOT active to avoid duplicate events.
|
|
1191
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
1192
|
+
BOOL isApplicationActive = NO;
|
|
1193
|
+
if (![NotifeeCoreUtil isAppExtension]) {
|
|
1194
|
+
UIApplication *application = [NotifeeCoreUtil notifeeUIApplication];
|
|
1195
|
+
if (application != nil) {
|
|
1196
|
+
isApplicationActive =
|
|
1197
|
+
application.applicationState == UIApplicationStateActive;
|
|
1198
|
+
}
|
|
235
1199
|
}
|
|
236
|
-
|
|
1200
|
+
if (!isApplicationActive) {
|
|
1201
|
+
[[NotifeeCoreDelegateHolder instance] didReceiveNotifeeCoreEvent:@{
|
|
1202
|
+
@"type" : @(NotifeeCoreEventTypeDelivered),
|
|
1203
|
+
@"detail" : @{
|
|
1204
|
+
@"notification" : notificationDetail,
|
|
1205
|
+
}
|
|
1206
|
+
}];
|
|
1207
|
+
}
|
|
1208
|
+
});
|
|
237
1209
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
block(error);
|
|
241
|
-
}];
|
|
1210
|
+
block(error);
|
|
1211
|
+
}];
|
|
242
1212
|
});
|
|
243
1213
|
});
|
|
244
1214
|
}
|
|
@@ -253,47 +1223,29 @@
|
|
|
253
1223
|
withTrigger:(NSDictionary *)trigger
|
|
254
1224
|
withBlock:(notifeeMethodVoidBlock)block {
|
|
255
1225
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
|
256
|
-
UNMutableNotificationContent *content =
|
|
257
|
-
|
|
258
|
-
UNNotificationTrigger *unTrigger = [NotifeeCoreUtil triggerFromDictionary:trigger];
|
|
259
|
-
|
|
260
|
-
if (unTrigger == nil) {
|
|
261
|
-
// do nothing if trigger is null
|
|
262
|
-
return dispatch_async(dispatch_get_main_queue(), ^{
|
|
263
|
-
block(nil);
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
|
|
1226
|
+
UNMutableNotificationContent *content =
|
|
1227
|
+
[self triggerNotificationContentForNotification:notification trigger:trigger];
|
|
267
1228
|
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
|
|
268
1229
|
|
|
269
1230
|
NSMutableDictionary *notificationDetail = [notification mutableCopy];
|
|
270
1231
|
notificationDetail[@"remote"] = @NO;
|
|
271
1232
|
|
|
272
|
-
if (
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
1233
|
+
if ([NotifeeCoreUtil isRollingTimestampTrigger:trigger]) {
|
|
1234
|
+
[self createRollingTriggerNotification:notification
|
|
1235
|
+
withTrigger:trigger
|
|
1236
|
+
withNotificationDetail:notificationDetail
|
|
1237
|
+
center:center
|
|
1238
|
+
block:block];
|
|
1239
|
+
return;
|
|
1240
|
+
}
|
|
277
1241
|
|
|
278
|
-
|
|
279
|
-
INInteraction *interaction = [[INInteraction alloc] initWithIntent:intent response:nil];
|
|
280
|
-
interaction.direction = INInteractionDirectionIncoming;
|
|
281
|
-
[interaction donateInteractionWithCompletion:^(NSError *donateError) {
|
|
282
|
-
if (donateError)
|
|
283
|
-
NSLog(@"NotifeeCore: Could not donate interaction for communication notification: %@",
|
|
284
|
-
donateError);
|
|
285
|
-
}];
|
|
1242
|
+
UNNotificationTrigger *unTrigger = [NotifeeCoreUtil triggerFromDictionary:trigger];
|
|
286
1243
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
contentUpdateError);
|
|
293
|
-
} else if (updatedContent != nil) {
|
|
294
|
-
content = [updatedContent mutableCopy];
|
|
295
|
-
}
|
|
296
|
-
}
|
|
1244
|
+
if (unTrigger == nil) {
|
|
1245
|
+
// do nothing if trigger is null
|
|
1246
|
+
return dispatch_async(dispatch_get_main_queue(), ^{
|
|
1247
|
+
block(nil);
|
|
1248
|
+
});
|
|
297
1249
|
}
|
|
298
1250
|
|
|
299
1251
|
UNNotificationRequest *request =
|
|
@@ -447,18 +1399,6 @@
|
|
|
447
1399
|
content.threadIdentifier = iosDict[@"threadId"];
|
|
448
1400
|
}
|
|
449
1401
|
|
|
450
|
-
if (@available(iOS 12.0, *)) {
|
|
451
|
-
// summaryArgument
|
|
452
|
-
if (iosDict[@"summaryArgument"] != nil) {
|
|
453
|
-
content.summaryArgument = iosDict[@"summaryArgument"];
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// summaryArgumentCount
|
|
457
|
-
if (iosDict[@"summaryArgumentCount"] != nil) {
|
|
458
|
-
content.summaryArgumentCount = [iosDict[@"summaryArgumentCount"] unsignedIntValue];
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
|
|
462
1402
|
if (@available(iOS 13.0, *)) {
|
|
463
1403
|
// targetContentId
|
|
464
1404
|
if (iosDict[@"targetContentId"] != nil) {
|
|
@@ -512,12 +1452,7 @@
|
|
|
512
1452
|
}
|
|
513
1453
|
}
|
|
514
1454
|
|
|
515
|
-
|
|
516
|
-
categoryDictionary[@"allowAnnouncement"] = @(
|
|
517
|
-
((notificationCategory.options & UNNotificationCategoryOptionAllowAnnouncement) != 0));
|
|
518
|
-
} else {
|
|
519
|
-
categoryDictionary[@"allowAnnouncement"] = @(NO);
|
|
520
|
-
}
|
|
1455
|
+
categoryDictionary[@"allowAnnouncement"] = @(NO);
|
|
521
1456
|
|
|
522
1457
|
categoryDictionary[@"actions"] =
|
|
523
1458
|
[NotifeeCoreUtil notificationActionsToDictionaryArray:notificationCategory.actions];
|
|
@@ -570,12 +1505,6 @@
|
|
|
570
1505
|
}
|
|
571
1506
|
}
|
|
572
1507
|
|
|
573
|
-
if (@available(iOS 13.0, *)) {
|
|
574
|
-
if ([categoryDictionary[@"allowAnnouncement"] isEqual:@(YES)]) {
|
|
575
|
-
options |= UNNotificationCategoryOptionAllowAnnouncement;
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
|
|
579
1508
|
if (@available(iOS 12.0, *)) {
|
|
580
1509
|
category = [UNNotificationCategory categoryWithIdentifier:id
|
|
581
1510
|
actions:actions
|
|
@@ -641,12 +1570,6 @@
|
|
|
641
1570
|
}
|
|
642
1571
|
}
|
|
643
1572
|
|
|
644
|
-
if ([permissions[@"announcement"] isEqual:@(YES)]) {
|
|
645
|
-
if (@available(iOS 13.0, *)) {
|
|
646
|
-
options |= UNAuthorizationOptionAnnouncement;
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
|
|
650
1573
|
if ([permissions[@"carPlay"] isEqual:@(YES)]) {
|
|
651
1574
|
options |= UNAuthorizationOptionCarPlay;
|
|
652
1575
|
}
|