react-native-notify-kit 10.3.1 → 10.3.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.
@@ -23,13 +23,21 @@ private func requestedAttachmentURLs(from userInfo: [AnyHashable: Any]) -> [Stri
23
23
  class NotificationService: UNNotificationServiceExtension {
24
24
  var contentHandler: ((UNNotificationContent) -> Void)?
25
25
  var bestAttemptContent: UNMutableNotificationContent?
26
+ private let deliveryLock = NSLock()
27
+ private var didDeliver = false
26
28
 
27
29
  override func didReceive(
28
30
  _ request: UNNotificationRequest,
29
31
  withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
30
32
  ) {
33
+ let mutableContent = request.content.mutableCopy() as? UNMutableNotificationContent
34
+
35
+ deliveryLock.lock()
36
+ didDeliver = false
31
37
  self.contentHandler = contentHandler
32
- self.bestAttemptContent = request.content.mutableCopy() as? UNMutableNotificationContent
38
+ self.bestAttemptContent = mutableContent
39
+ deliveryLock.unlock()
40
+
33
41
  let requestedAttachmentUrls = requestedAttachmentURLs(from: request.content.userInfo)
34
42
 
35
43
  nseLog(
@@ -39,9 +47,9 @@ class NotificationService: UNNotificationServiceExtension {
39
47
  "urls=\(requestedAttachmentUrls.joined(separator: ","))"
40
48
  )
41
49
 
42
- guard let bestAttemptContent = bestAttemptContent else {
50
+ guard let bestAttemptContent = mutableContent else {
43
51
  nseLog("mutableCopy failed for id=\(request.identifier); delivering original content")
44
- contentHandler(request.content)
52
+ deliverOnce(request.content)
45
53
  return
46
54
  }
47
55
 
@@ -55,19 +63,38 @@ class NotificationService: UNNotificationServiceExtension {
55
63
  "deliveredAttachments=\(content.attachments.count) " +
56
64
  "identifiers=\(deliveredAttachmentIds)"
57
65
  )
58
- self?.contentHandler?(content)
66
+ self?.deliverOnce(content)
59
67
  }
60
68
  )
61
69
  }
62
70
 
71
+ private func deliverOnce(_ content: UNNotificationContent) {
72
+ var handler: ((UNNotificationContent) -> Void)?
73
+
74
+ deliveryLock.lock()
75
+ if !didDeliver {
76
+ didDeliver = true
77
+ handler = contentHandler
78
+ contentHandler = nil
79
+ bestAttemptContent = nil
80
+ }
81
+ deliveryLock.unlock()
82
+
83
+ handler?(content)
84
+ }
85
+
63
86
  override func serviceExtensionTimeWillExpire() {
64
- if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
87
+ deliveryLock.lock()
88
+ let content = bestAttemptContent
89
+ deliveryLock.unlock()
90
+
91
+ if let bestAttemptContent = content {
65
92
  nseLog(
66
93
  "serviceExtensionTimeWillExpire id=\(bestAttemptContent.userInfo["gcm.message_id"] ?? "n/a") " +
67
94
  "title=\(bestAttemptContent.title) " +
68
95
  "deliveredAttachments=\(bestAttemptContent.attachments.count)"
69
96
  )
70
- contentHandler(bestAttemptContent)
97
+ deliverOnce(bestAttemptContent)
71
98
  }
72
99
  }
73
100
  }
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "10.3.1";
1
+ export declare const version = "10.3.2";
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  // Generated by genversion.
2
- export const version = '10.3.1';
2
+ export const version = '10.3.2';
3
3
  //# sourceMappingURL=version.js.map
@@ -18,18 +18,35 @@
18
18
  #import "NotifeeCore+NSURLSession.h"
19
19
  #import "NotifeeCoreDownloadDelegate.h"
20
20
 
21
+ static NSTimeInterval const kNotifeeAttachmentDownloadTimeoutInterval = 25.0;
22
+
21
23
  @implementation NotifeeCoreNSURLSession
22
24
 
25
+ + (NSURLSessionConfiguration *)attachmentDownloadSessionConfiguration {
26
+ NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
27
+ config.timeoutIntervalForRequest = kNotifeeAttachmentDownloadTimeoutInterval;
28
+ config.timeoutIntervalForResource = kNotifeeAttachmentDownloadTimeoutInterval;
29
+ return config;
30
+ }
31
+
32
+ + (nullable NSString *)fileExtensionFromSuggestedFilename:(nullable NSString *)suggestedFilename {
33
+ NSString *suggestedPathExtension = [suggestedFilename pathExtension];
34
+ if (suggestedPathExtension.length == 0) {
35
+ return nil;
36
+ }
37
+
38
+ return [NSString stringWithFormat:@".%@", suggestedPathExtension];
39
+ }
40
+
23
41
  + (NSString *)downloadItemAtURL:(NSURL *)url toFile:(NSString *)localPath error:(NSError **)error {
24
42
  NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
43
+ request.timeoutInterval = kNotifeeAttachmentDownloadTimeoutInterval;
25
44
 
26
45
  NotifeeCoreDownloadDelegate *delegate =
27
46
  [[NotifeeCoreDownloadDelegate alloc] initWithFilePath:localPath];
28
47
 
29
- // The session is created with the defaultSessionConfiguration
30
- // default timeoutIntervalForRequest is 60 seconds.
31
48
  NSURLSession *session =
32
- [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
49
+ [NSURLSession sessionWithConfiguration:[self attachmentDownloadSessionConfiguration]
33
50
  delegate:delegate
34
51
  delegateQueue:nil];
35
52
 
@@ -1191,7 +1191,8 @@ typedef NS_ENUM(NSInteger, NotifeeCoreRollingErrorCode) {
1191
1191
  dispatch_async(dispatch_get_main_queue(), ^{
1192
1192
  BOOL isApplicationActive = NO;
1193
1193
  if (![NotifeeCoreUtil isAppExtension]) {
1194
- UIApplication *application = [NotifeeCoreUtil notifeeUIApplication];
1194
+ UIApplication *application =
1195
+ (UIApplication *)[NotifeeCoreUtil notifeeUIApplication];
1195
1196
  if (application != nil) {
1196
1197
  isApplicationActive =
1197
1198
  application.applicationState == UIApplicationStateActive;
@@ -24,8 +24,8 @@ static NSString *const kPayloadOptionsName = @"notifee_options";
24
24
  static NSString *const kPayloadOptionsImageURLName = @"image";
25
25
 
26
26
  @interface NotifeeCoreExtensionHelper : NSObject
27
- @property(nonatomic, strong) void (^contentHandler)(UNNotificationContent *c);
28
- @property(nonatomic, strong) UNMutableNotificationContent *modifiedContent;
27
+ @property(nonatomic, copy, nullable) void (^contentHandler)(UNNotificationContent *c);
28
+ @property(nonatomic, strong, nullable) UNMutableNotificationContent *modifiedContent;
29
29
 
30
30
  + (NotifeeCoreExtensionHelper *)instance NS_SWIFT_NAME(serviceExtension());
31
31
 
@@ -23,30 +23,56 @@
23
23
  static NSString *const kNoExtension = @"";
24
24
  static NSString *const kImagePathPrefix = @"image/";
25
25
 
26
- @implementation NotifeeCoreExtensionHelper
27
- + (NotifeeCoreExtensionHelper *)instance {
28
- static dispatch_once_t once;
29
- static NotifeeCoreExtensionHelper *instance;
30
- dispatch_once(&once, ^{
31
- instance = [[self alloc] init];
32
- });
26
+ @interface NotifeeCoreExtensionHelper ()
27
+ - (NSMutableDictionary *)parseNotifeeOptions:(id)payload;
28
+ - (void)loadAttachment:(NSDictionary *)attachmentDict
29
+ completionHandler:(void (^)(UNNotificationAttachment *))completionHandler;
30
+ @end
33
31
 
34
- return instance;
35
- }
32
+ @interface NotifeeCoreExtensionRequestContext : NSObject
33
+ @property(nonatomic, strong) NotifeeCoreExtensionHelper *helper;
34
+ @property(nonatomic, copy) void (^contentHandler)(UNNotificationContent *content);
35
+ @property(nonatomic, strong) UNMutableNotificationContent *modifiedContent;
36
+ @property(nonatomic, assign) BOOL notificationDelivered;
36
37
 
37
- - (void)populateNotificationContent:(UNNotificationRequest *_Nullable)request
38
- withContent:(UNMutableNotificationContent *)content
39
- withContentHandler:(void (^)(UNNotificationContent *_Nonnull))contentHandler {
40
- self.contentHandler = [contentHandler copy];
41
- self.modifiedContent = content;
38
+ - (instancetype)initWithHelper:(NotifeeCoreExtensionHelper *)helper
39
+ content:(UNMutableNotificationContent *)content
40
+ contentHandler:(void (^)(UNNotificationContent *content))contentHandler;
41
+ - (void)populateNotificationContentWithRequest:(UNNotificationRequest *_Nullable)request;
42
+ - (void)processCommunicationData:(NSMutableDictionary *)options;
43
+ - (void)handleAttachmentsAndDeliverNotificaiton:(NSMutableDictionary *)options;
44
+ - (void)deliverNotification;
45
+ @end
46
+
47
+ @implementation NotifeeCoreExtensionRequestContext
48
+
49
+ - (instancetype)initWithHelper:(NotifeeCoreExtensionHelper *)helper
50
+ content:(UNMutableNotificationContent *)content
51
+ contentHandler:(void (^)(UNNotificationContent *content))contentHandler {
52
+ self = [super init];
53
+ if (self != nil) {
54
+ self.helper = helper;
55
+ self.contentHandler = [contentHandler copy];
56
+ self.modifiedContent = content;
57
+ self.notificationDelivered = NO;
58
+ }
42
59
 
43
- if (!content.userInfo[@"notifee_options"]) {
60
+ return self;
61
+ }
62
+
63
+ - (void)populateNotificationContentWithRequest:(UNNotificationRequest *_Nullable)request {
64
+ id notifeeOptionsPayload = self.modifiedContent.userInfo[kPayloadOptionsName];
65
+ if (!notifeeOptionsPayload) {
44
66
  [self deliverNotification];
45
67
  return;
46
68
  }
47
69
 
48
- // fcm: apns: { payload: {notifee_options: {} } }
49
- NSMutableDictionary *options = [self.modifiedContent.userInfo[@"notifee_options"] mutableCopy];
70
+ // fcm: apns: { payload: {notifee_options: "{}" } }
71
+ NSMutableDictionary *options = [self.helper parseNotifeeOptions:notifeeOptionsPayload];
72
+ if (options == nil) {
73
+ [self deliverNotification];
74
+ return;
75
+ }
50
76
 
51
77
  options[@"remote"] = @YES;
52
78
 
@@ -60,7 +86,7 @@ static NSString *const kImagePathPrefix = @"image/";
60
86
  options[@"id"] = request.identifier;
61
87
  }
62
88
 
63
- if (options[@"title"] == nil && content.title != nil) {
89
+ if (options[@"title"] == nil && self.modifiedContent.title != nil) {
64
90
  options[@"title"] = self.modifiedContent.title;
65
91
  }
66
92
 
@@ -135,14 +161,100 @@ static NSString *const kImagePathPrefix = @"image/";
135
161
  }
136
162
 
137
163
  // Attempt to download attachment
138
- [self loadAttachment:attachmentDict
139
- completionHandler:^(UNNotificationAttachment *attachment) {
140
- if (attachment != nil) {
141
- self.modifiedContent.attachments = @[ attachment ];
142
- }
143
-
144
- [self deliverNotification];
145
- }];
164
+ [self.helper loadAttachment:attachmentDict
165
+ completionHandler:^(UNNotificationAttachment *attachment) {
166
+ if (attachment != nil) {
167
+ @synchronized(self) {
168
+ if (!self.notificationDelivered && self.modifiedContent != nil) {
169
+ self.modifiedContent.attachments = @[ attachment ];
170
+ }
171
+ }
172
+ }
173
+
174
+ [self deliverNotification];
175
+ }];
176
+ }
177
+
178
+ - (void)deliverNotification {
179
+ void (^contentHandler)(UNNotificationContent *) = nil;
180
+ UNNotificationContent *modifiedContent = nil;
181
+
182
+ @synchronized(self) {
183
+ if (self.notificationDelivered || self.contentHandler == nil) {
184
+ return;
185
+ }
186
+
187
+ contentHandler = [self.contentHandler copy];
188
+ modifiedContent = self.modifiedContent;
189
+ self.notificationDelivered = YES;
190
+ self.contentHandler = nil;
191
+ self.modifiedContent = nil;
192
+ }
193
+
194
+ if (contentHandler != nil && modifiedContent != nil) {
195
+ contentHandler(modifiedContent);
196
+ }
197
+ }
198
+
199
+ @end
200
+
201
+ @implementation NotifeeCoreExtensionHelper
202
+ + (NotifeeCoreExtensionHelper *)instance {
203
+ static dispatch_once_t once;
204
+ static NotifeeCoreExtensionHelper *instance;
205
+ dispatch_once(&once, ^{
206
+ instance = [[self alloc] init];
207
+ });
208
+
209
+ return instance;
210
+ }
211
+
212
+ - (NSMutableDictionary *)parseNotifeeOptions:(id)payload {
213
+ if ([payload isKindOfClass:[NSDictionary class]]) {
214
+ return [payload mutableCopy];
215
+ }
216
+
217
+ if ([payload isKindOfClass:[NSString class]]) {
218
+ NSData *optionsData = [payload dataUsingEncoding:NSUTF8StringEncoding];
219
+ if (optionsData == nil) {
220
+ NSLog(@"NotifeeCoreExtensionHelper: Could not decode notifee_options string as UTF-8");
221
+ return nil;
222
+ }
223
+
224
+ NSError *error = nil;
225
+ id jsonObject = [NSJSONSerialization JSONObjectWithData:optionsData
226
+ options:NSJSONReadingFragmentsAllowed
227
+ error:&error];
228
+
229
+ if (error != nil) {
230
+ NSLog(@"NotifeeCoreExtensionHelper: Could not parse notifee_options JSON: %@", error);
231
+ return nil;
232
+ }
233
+
234
+ if (![jsonObject isKindOfClass:[NSDictionary class]]) {
235
+ NSLog(@"NotifeeCoreExtensionHelper: Ignoring notifee_options JSON because it is not a "
236
+ @"dictionary: %@",
237
+ NSStringFromClass([jsonObject class]));
238
+ return nil;
239
+ }
240
+
241
+ return [jsonObject mutableCopy];
242
+ }
243
+
244
+ NSLog(@"NotifeeCoreExtensionHelper: Ignoring notifee_options because it is not a dictionary "
245
+ @"or JSON string: %@",
246
+ NSStringFromClass([payload class]));
247
+ return nil;
248
+ }
249
+
250
+ - (void)populateNotificationContent:(UNNotificationRequest *_Nullable)request
251
+ withContent:(UNMutableNotificationContent *)content
252
+ withContentHandler:(void (^)(UNNotificationContent *_Nonnull))contentHandler {
253
+ NotifeeCoreExtensionRequestContext *context =
254
+ [[NotifeeCoreExtensionRequestContext alloc] initWithHelper:self
255
+ content:content
256
+ contentHandler:contentHandler];
257
+ [context populateNotificationContentWithRequest:request];
146
258
  }
147
259
 
148
260
  - (NSString *)fileExtensionForResponse:(NSURLResponse *)response {
@@ -220,10 +332,4 @@ static NSString *const kImagePathPrefix = @"image/";
220
332
  }
221
333
  }
222
334
 
223
- - (void)deliverNotification {
224
- if (self.contentHandler) {
225
- self.contentHandler(self.modifiedContent);
226
- }
227
- }
228
-
229
335
  @end
@@ -23,6 +23,12 @@
23
23
  #include <math.h>
24
24
  #import "NotifeeCore+NSURLSession.h"
25
25
 
26
+ @interface NotifeeCoreNSURLSession (NotifeeCoreUtil)
27
+
28
+ + (nullable NSString *)fileExtensionFromSuggestedFilename:(nullable NSString *)suggestedFilename;
29
+
30
+ @end
31
+
26
32
  static NSString *const kNotifeeRollingTimestampTriggersStorageKey =
27
33
  @"app.notifee.core.rollingTimestampTriggers.v1";
28
34
  static NSString *const kNotifeeRollingInternalIdPrefix = @"__notifee_rolling__";
@@ -83,7 +89,7 @@ static NSInteger const kNotifeeRollingTargetPerTrigger = 32;
83
89
  notificationActionDict[@"authenticationRequired"] =
84
90
  @(((notificationAction.options & UNNotificationActionOptionAuthenticationRequired) != 0));
85
91
 
86
- if ([[notificationAction class] isKindOfClass:[UNTextInputNotificationAction class]]) {
92
+ if ([notificationAction isKindOfClass:[UNTextInputNotificationAction class]]) {
87
93
  UNTextInputNotificationAction *notificationInputAction =
88
94
  (UNTextInputNotificationAction *)notificationAction;
89
95
  if ([notificationInputAction textInputButtonTitle] == nil &&
@@ -266,12 +272,14 @@ static NSInteger const kNotifeeRollingTargetPerTrigger = 32;
266
272
  // Rename the recently downloaded file to include its file extension
267
273
  NSFileManager *fileManager = [NSFileManager defaultManager];
268
274
 
269
- NSString *fileExtension = [NSString stringWithFormat:@".%@", [suggestedFilename pathExtension]];
275
+ NSString *fileExtension =
276
+ [NotifeeCoreNSURLSession fileExtensionFromSuggestedFilename:suggestedFilename];
270
277
 
271
- if (!fileExtension || [fileExtension isEqualToString:@""]) {
278
+ if (fileExtension.length == 0) {
272
279
  NSLog(@"NotifeeCore: Failed to determine file extension for attachment "
273
- @"with URL %@: %@",
274
- urlString, error);
280
+ @"with URL %@ and suggested filename %@",
281
+ urlString, suggestedFilename);
282
+ [fileManager removeItemAtPath:tempDestination error:nil];
275
283
  return nil;
276
284
  }
277
285
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-notify-kit",
3
- "version": "10.3.1",
3
+ "version": "10.3.2",
4
4
  "author": "Marco Crupi",
5
5
  "description": "Maintained Notifee-compatible fork for React Native — advanced local notifications for Android & iOS.",
6
6
  "main": "dist/index.js",
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- export const version = '10.3.1';
2
+ export const version = '10.3.2';