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.
Files changed (52) hide show
  1. package/README.md +99 -96
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/AndroidManifest.xml +0 -1
  4. package/android/src/main/java/app/notifee/core/ForegroundService.java +1 -0
  5. package/android/src/main/java/app/notifee/core/NotificationManager.java +21 -8
  6. package/android/src/main/java/app/notifee/core/RebootBroadcastReceiver.java +16 -0
  7. package/android/src/main/java/app/notifee/core/ReceiverService.java +18 -13
  8. package/android/src/main/java/app/notifee/core/model/NotificationAndroidActionModel.java +1 -2
  9. package/android/src/main/java/app/notifee/core/model/NotificationAndroidPressActionModel.java +3 -9
  10. package/android/src/main/java/app/notifee/core/model/TimestampTriggerModel.java +42 -27
  11. package/android/src/main/java/app/notifee/core/utility/IntentUtils.java +0 -28
  12. package/android/src/main/java/app/notifee/core/utility/PowerManagerUtils.java +79 -41
  13. package/android/src/main/java/app/notifee/core/utility/ResourceUtils.java +5 -1
  14. package/android/src/main/kotlin/io/invertase/notifee/NotifeeApiModule.kt +6 -6
  15. package/android/src/main/kotlin/io/invertase/notifee/NotifeeReactUtils.kt +1 -2
  16. package/android/src/test/java/app/notifee/core/model/TimestampTriggerModelTest.java +150 -0
  17. package/cli/dist/lib/patchPodfile.d.ts +3 -1
  18. package/cli/dist/lib/patchPodfile.js +125 -33
  19. package/cli/dist/lib/patchPodfile.js.map +1 -1
  20. package/dist/index.d.ts +2 -0
  21. package/dist/types/Module.d.ts +27 -13
  22. package/dist/types/Notification.d.ts +1 -1
  23. package/dist/types/NotificationIOS.d.ts +44 -21
  24. package/dist/types/NotificationIOS.js +15 -1
  25. package/dist/types/NotificationIOS.js.map +1 -1
  26. package/dist/types/PowerManagerInfo.d.ts +9 -4
  27. package/dist/types/Trigger.d.ts +45 -2
  28. package/dist/types/Trigger.js +22 -0
  29. package/dist/types/Trigger.js.map +1 -1
  30. package/dist/validators/validateIOSCategory.js +2 -2
  31. package/dist/validators/validateIOSCategory.js.map +1 -1
  32. package/dist/validators/validateTrigger.js +26 -1
  33. package/dist/validators/validateTrigger.js.map +1 -1
  34. package/dist/version.d.ts +1 -1
  35. package/dist/version.js +1 -1
  36. package/ios/NotifeeCore/NotifeeCore+NSNotificationCenter.m +20 -10
  37. package/ios/NotifeeCore/NotifeeCore+UNUserNotificationCenter.h +1 -2
  38. package/ios/NotifeeCore/NotifeeCore+UNUserNotificationCenter.m +44 -35
  39. package/ios/NotifeeCore/NotifeeCore.m +1042 -119
  40. package/ios/NotifeeCore/NotifeeCoreUtil.h +36 -1
  41. package/ios/NotifeeCore/NotifeeCoreUtil.m +533 -9
  42. package/ios/RNNotifee/NotifeeApiModule.mm +2 -2
  43. package/package.json +1 -1
  44. package/src/index.ts +2 -0
  45. package/src/types/Module.ts +27 -13
  46. package/src/types/Notification.ts +1 -1
  47. package/src/types/NotificationIOS.ts +43 -28
  48. package/src/types/PowerManagerInfo.ts +9 -4
  49. package/src/types/Trigger.ts +45 -1
  50. package/src/validators/validateIOSCategory.ts +4 -2
  51. package/src/validators/validateTrigger.ts +38 -0
  52. package/src/version.ts +1 -1
@@ -39,9 +39,11 @@ typedef NS_ENUM(NSInteger, NotifeeCoreTriggerType) {
39
39
 
40
40
  // Enum representing repeat frequency for TimestampTrigger
41
41
  typedef NS_ENUM(NSInteger, NotifeeCoreRepeatFrequency) {
42
+ NotifeeCoreRepeatFrequencyNone = -1,
42
43
  NotifeeCoreRepeatFrequencyHourly = 0,
43
44
  NotifeeCoreRepeatFrequencyDaily = 1,
44
- NotifeeCoreRepeatFrequencyWeekly = 2
45
+ NotifeeCoreRepeatFrequencyWeekly = 2,
46
+ NotifeeCoreRepeatFrequencyMonthly = 3
45
47
  };
46
48
 
47
49
  @interface NotifeeCoreUtil : NSObject
@@ -65,6 +67,39 @@ typedef NS_ENUM(NSInteger, NotifeeCoreRepeatFrequency) {
65
67
 
66
68
  + (UNNotificationTrigger *)triggerFromDictionary:(NSDictionary *)triggerDict;
67
69
 
70
+ + (BOOL)isRollingTimestampTrigger:(nullable NSDictionary *)triggerDict;
71
+
72
+ + (NSArray<NSNumber *> *)rollingTimestampOccurrencesFromTrigger:(nullable NSDictionary *)triggerDict
73
+ nowMs:(nullable NSNumber *)nowMs
74
+ maxCount:(NSInteger)maxCount;
75
+
76
+ + (nullable NSString *)rollingInternalNotificationIdForPublicId:(nullable NSString *)publicId
77
+ occurrenceMs:(nullable NSNumber *)occurrenceMs;
78
+
79
+ + (nullable NSString *)rollingPublicIdFromInternalNotificationId:(nullable NSString *)internalId;
80
+
81
+ + (nullable NSNumber *)rollingOccurrenceMsFromInternalNotificationId:
82
+ (nullable NSString *)internalId;
83
+
84
+ + (BOOL)isRollingInternalNotificationId:(nullable NSString *)notificationId;
85
+
86
+ + (NSInteger)rollingPendingBudget;
87
+
88
+ + (NSInteger)rollingTargetPerTrigger;
89
+
90
+ + (NSMutableDictionary *)getRollingTimestampTriggers;
91
+
92
+ + (void)setRollingTimestampTriggers:(nullable NSDictionary *)records;
93
+
94
+ + (void)upsertRollingTimestampTriggerRecord:(nullable NSDictionary *)record
95
+ publicId:(nullable NSString *)publicId;
96
+
97
+ + (void)removeRollingTimestampTriggerRecordForPublicId:(nullable NSString *)publicId;
98
+
99
+ + (void)clearRollingTimestampTriggerRecords;
100
+
101
+ + (nullable NSNumber *)rollingLastScheduledOccurrenceMsForRecord:(nullable NSDictionary *)record;
102
+
68
103
  + (NSNumber *)convertToTimestamp:(NSDate *)date;
69
104
 
70
105
  + (NSDictionary *)parseUNNotificationRequest:(UNNotificationRequest *)request;
@@ -19,8 +19,39 @@
19
19
  #include <CoreGraphics/CGGeometry.h>
20
20
  #import <Intents/INIntentIdentifiers.h>
21
21
  #import <UIKit/UIKit.h>
22
+ #include <limits.h>
23
+ #include <math.h>
22
24
  #import "NotifeeCore+NSURLSession.h"
23
25
 
26
+ static NSString *const kNotifeeRollingTimestampTriggersStorageKey =
27
+ @"app.notifee.core.rollingTimestampTriggers.v1";
28
+ static NSString *const kNotifeeRollingInternalIdPrefix = @"__notifee_rolling__";
29
+ static NSString *const kNotifeeRollingInternalIdSeparator = @"__";
30
+ static NSInteger const kNotifeeRollingPendingBudget = 60;
31
+ static NSInteger const kNotifeeRollingTargetPerTrigger = 32;
32
+
33
+ @interface NotifeeCoreUtil ()
34
+
35
+ + (nullable NSNumber *)rollingIntegerNumberFromObject:(nullable id)value
36
+ allowNegative:(BOOL)allowNegative
37
+ allowZero:(BOOL)allowZero;
38
+ + (BOOL)isSupportedRollingRepeatFrequency:(NSInteger)repeatFrequency;
39
+ + (NSInteger)rollingRepeatIntervalFromTrigger:(NSDictionary *)triggerDict;
40
+ + (nullable NSDate *)rollingDateByAddingRepeatFrequency:(NSInteger)repeatFrequency
41
+ interval:(NSInteger)interval
42
+ toDate:(NSDate *)date;
43
+ + (nullable NSDictionary *)rollingPartsFromInternalNotificationId:(nullable NSString *)internalId;
44
+ + (nullable NSMutableDictionary *)
45
+ rollingSanitizedTimestampTriggerRecord:(nullable NSDictionary *)record
46
+ publicId:(nullable NSString *)publicId
47
+ defaultMissingCreatedAt:(BOOL)defaultMissingCreatedAt;
48
+ + (NSMutableDictionary *)rollingSanitizedTimestampTriggerRecords:(nullable NSDictionary *)records
49
+ defaultMissingCreatedAt:(BOOL)defaultMissingCreatedAt;
50
+ + (nullable id)rollingJSONObjectFromObject:(nullable id)object;
51
+ + (NSNumber *)rollingCurrentTimestampMs;
52
+
53
+ @end
54
+
24
55
  @implementation NotifeeCoreUtil
25
56
 
26
57
  + (NSNumber *)numberForUNNotificationSetting:(UNNotificationSetting)setting {
@@ -319,6 +350,499 @@
319
350
  return trigger;
320
351
  }
321
352
 
353
+ + (BOOL)isRollingTimestampTrigger:(NSDictionary *)triggerDict {
354
+ if (![triggerDict isKindOfClass:NSDictionary.class]) {
355
+ return NO;
356
+ }
357
+
358
+ NSNumber *triggerType = [self rollingIntegerNumberFromObject:triggerDict[@"type"]
359
+ allowNegative:NO
360
+ allowZero:YES];
361
+ if (triggerType == nil || [triggerType integerValue] != NotifeeCoreTriggerTypeTimestamp) {
362
+ return NO;
363
+ }
364
+
365
+ NSNumber *timestamp = [self rollingIntegerNumberFromObject:triggerDict[@"timestamp"]
366
+ allowNegative:NO
367
+ allowZero:NO];
368
+ if (timestamp == nil) {
369
+ return NO;
370
+ }
371
+
372
+ if (triggerDict[@"repeatFrequency"] == nil) {
373
+ return NO;
374
+ }
375
+
376
+ NSNumber *repeatFrequencyNumber =
377
+ [self rollingIntegerNumberFromObject:triggerDict[@"repeatFrequency"]
378
+ allowNegative:YES
379
+ allowZero:YES];
380
+ if (repeatFrequencyNumber == nil) {
381
+ return NO;
382
+ }
383
+
384
+ NSInteger repeatFrequency = [repeatFrequencyNumber integerValue];
385
+ if (repeatFrequency == NotifeeCoreRepeatFrequencyNone ||
386
+ ![self isSupportedRollingRepeatFrequency:repeatFrequency]) {
387
+ return NO;
388
+ }
389
+
390
+ if (triggerDict[@"repeatInterval"] != nil) {
391
+ NSNumber *repeatInterval = [self rollingIntegerNumberFromObject:triggerDict[@"repeatInterval"]
392
+ allowNegative:NO
393
+ allowZero:NO];
394
+ if (repeatInterval == nil || [repeatInterval doubleValue] > NSIntegerMax) {
395
+ return NO;
396
+ }
397
+ }
398
+
399
+ return YES;
400
+ }
401
+
402
+ + (NSArray<NSNumber *> *)rollingTimestampOccurrencesFromTrigger:(NSDictionary *)triggerDict
403
+ nowMs:(NSNumber *)nowMs
404
+ maxCount:(NSInteger)maxCount {
405
+ if (maxCount <= 0 || ![triggerDict isKindOfClass:NSDictionary.class]) {
406
+ return @[];
407
+ }
408
+
409
+ NSNumber *triggerType = [self rollingIntegerNumberFromObject:triggerDict[@"type"]
410
+ allowNegative:NO
411
+ allowZero:YES];
412
+ if (triggerType == nil || [triggerType integerValue] != NotifeeCoreTriggerTypeTimestamp) {
413
+ return @[];
414
+ }
415
+
416
+ NSNumber *timestampNumber = [self rollingIntegerNumberFromObject:triggerDict[@"timestamp"]
417
+ allowNegative:NO
418
+ allowZero:NO];
419
+ NSNumber *nowNumber = [self rollingIntegerNumberFromObject:nowMs allowNegative:NO allowZero:YES];
420
+ NSNumber *repeatFrequencyNumber =
421
+ [self rollingIntegerNumberFromObject:triggerDict[@"repeatFrequency"]
422
+ allowNegative:YES
423
+ allowZero:YES];
424
+ if (timestampNumber == nil || nowNumber == nil || repeatFrequencyNumber == nil) {
425
+ return @[];
426
+ }
427
+
428
+ NSInteger repeatFrequency = [repeatFrequencyNumber integerValue];
429
+ if (repeatFrequency == NotifeeCoreRepeatFrequencyNone ||
430
+ ![self isSupportedRollingRepeatFrequency:repeatFrequency]) {
431
+ return @[];
432
+ }
433
+
434
+ NSInteger repeatInterval = [self rollingRepeatIntervalFromTrigger:triggerDict];
435
+ long long nowMsValue = [nowNumber longLongValue];
436
+ NSDate *candidateDate =
437
+ [NSDate dateWithTimeIntervalSince1970:([timestampNumber doubleValue] / 1000.0)];
438
+ NSMutableArray<NSNumber *> *occurrences = [NSMutableArray array];
439
+
440
+ while (candidateDate != nil &&
441
+ (long long)llround([candidateDate timeIntervalSince1970] * 1000.0) <= nowMsValue) {
442
+ NSDate *nextDate = [self rollingDateByAddingRepeatFrequency:repeatFrequency
443
+ interval:repeatInterval
444
+ toDate:candidateDate];
445
+ if (nextDate == nil || [nextDate timeIntervalSinceDate:candidateDate] <= 0) {
446
+ return @[];
447
+ }
448
+ candidateDate = nextDate;
449
+ }
450
+
451
+ while (candidateDate != nil && [occurrences count] < (NSUInteger)maxCount) {
452
+ long long occurrenceMs = (long long)llround([candidateDate timeIntervalSince1970] * 1000.0);
453
+ if (occurrenceMs > nowMsValue) {
454
+ [occurrences addObject:@(occurrenceMs)];
455
+ }
456
+
457
+ NSDate *nextDate = [self rollingDateByAddingRepeatFrequency:repeatFrequency
458
+ interval:repeatInterval
459
+ toDate:candidateDate];
460
+ if (nextDate == nil || [nextDate timeIntervalSinceDate:candidateDate] <= 0) {
461
+ break;
462
+ }
463
+ candidateDate = nextDate;
464
+ }
465
+
466
+ return occurrences;
467
+ }
468
+
469
+ + (NSString *)rollingInternalNotificationIdForPublicId:(NSString *)publicId
470
+ occurrenceMs:(NSNumber *)occurrenceMs {
471
+ if (![publicId isKindOfClass:NSString.class] || [publicId length] == 0) {
472
+ return nil;
473
+ }
474
+
475
+ NSNumber *occurrenceNumber = [self rollingIntegerNumberFromObject:occurrenceMs
476
+ allowNegative:NO
477
+ allowZero:NO];
478
+ if (occurrenceNumber == nil) {
479
+ return nil;
480
+ }
481
+
482
+ NSMutableCharacterSet *allowedCharacters =
483
+ [NSMutableCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
484
+ @"abcdefghijklmnopqrstuvwxyz"
485
+ @"0123456789-._~"];
486
+ NSString *escapedPublicId =
487
+ [publicId stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];
488
+ if (escapedPublicId == nil || [escapedPublicId length] == 0) {
489
+ return nil;
490
+ }
491
+
492
+ return [NSString stringWithFormat:@"%@%@%@%lld", kNotifeeRollingInternalIdPrefix, escapedPublicId,
493
+ kNotifeeRollingInternalIdSeparator,
494
+ [occurrenceNumber longLongValue]];
495
+ }
496
+
497
+ + (NSString *)rollingPublicIdFromInternalNotificationId:(NSString *)internalId {
498
+ NSDictionary *parts = [self rollingPartsFromInternalNotificationId:internalId];
499
+ return parts[@"publicId"];
500
+ }
501
+
502
+ + (NSNumber *)rollingOccurrenceMsFromInternalNotificationId:(NSString *)internalId {
503
+ NSDictionary *parts = [self rollingPartsFromInternalNotificationId:internalId];
504
+ return parts[@"occurrenceMs"];
505
+ }
506
+
507
+ + (BOOL)isRollingInternalNotificationId:(NSString *)notificationId {
508
+ return [self rollingPartsFromInternalNotificationId:notificationId] != nil;
509
+ }
510
+
511
+ + (NSInteger)rollingPendingBudget {
512
+ return kNotifeeRollingPendingBudget;
513
+ }
514
+
515
+ + (NSInteger)rollingTargetPerTrigger {
516
+ return kNotifeeRollingTargetPerTrigger;
517
+ }
518
+
519
+ + (NSMutableDictionary *)getRollingTimestampTriggers {
520
+ id storedRecords = [[NSUserDefaults standardUserDefaults]
521
+ objectForKey:kNotifeeRollingTimestampTriggersStorageKey];
522
+ NSDictionary *records = nil;
523
+
524
+ if ([storedRecords isKindOfClass:NSData.class]) {
525
+ NSError *error = nil;
526
+ id jsonObject = [NSJSONSerialization JSONObjectWithData:storedRecords options:0 error:&error];
527
+ if (error != nil || ![jsonObject isKindOfClass:NSDictionary.class]) {
528
+ return [NSMutableDictionary dictionary];
529
+ }
530
+ records = jsonObject;
531
+ } else if ([storedRecords isKindOfClass:NSDictionary.class]) {
532
+ records = storedRecords;
533
+ } else {
534
+ return [NSMutableDictionary dictionary];
535
+ }
536
+
537
+ return [self rollingSanitizedTimestampTriggerRecords:records defaultMissingCreatedAt:YES];
538
+ }
539
+
540
+ + (void)setRollingTimestampTriggers:(NSDictionary *)records {
541
+ NSMutableDictionary *sanitizedRecords = [self rollingSanitizedTimestampTriggerRecords:records
542
+ defaultMissingCreatedAt:YES];
543
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
544
+
545
+ if ([sanitizedRecords count] == 0) {
546
+ [defaults removeObjectForKey:kNotifeeRollingTimestampTriggersStorageKey];
547
+ return;
548
+ }
549
+
550
+ NSError *error = nil;
551
+ NSData *jsonData = [NSJSONSerialization dataWithJSONObject:sanitizedRecords
552
+ options:0
553
+ error:&error];
554
+ if (error != nil || jsonData == nil) {
555
+ [defaults removeObjectForKey:kNotifeeRollingTimestampTriggersStorageKey];
556
+ return;
557
+ }
558
+
559
+ [defaults setObject:jsonData forKey:kNotifeeRollingTimestampTriggersStorageKey];
560
+ }
561
+
562
+ + (void)upsertRollingTimestampTriggerRecord:(NSDictionary *)record publicId:(NSString *)publicId {
563
+ NSMutableDictionary *sanitizedRecord = [self rollingSanitizedTimestampTriggerRecord:record
564
+ publicId:publicId
565
+ defaultMissingCreatedAt:YES];
566
+ if (sanitizedRecord == nil) {
567
+ return;
568
+ }
569
+
570
+ NSMutableDictionary *records = [self getRollingTimestampTriggers];
571
+ records[sanitizedRecord[@"publicId"]] = sanitizedRecord;
572
+ [self setRollingTimestampTriggers:records];
573
+ }
574
+
575
+ + (void)removeRollingTimestampTriggerRecordForPublicId:(NSString *)publicId {
576
+ if (![publicId isKindOfClass:NSString.class] || [publicId length] == 0) {
577
+ return;
578
+ }
579
+
580
+ NSMutableDictionary *records = [self getRollingTimestampTriggers];
581
+ [records removeObjectForKey:publicId];
582
+ [self setRollingTimestampTriggers:records];
583
+ }
584
+
585
+ + (void)clearRollingTimestampTriggerRecords {
586
+ [[NSUserDefaults standardUserDefaults]
587
+ removeObjectForKey:kNotifeeRollingTimestampTriggersStorageKey];
588
+ }
589
+
590
+ + (NSNumber *)rollingLastScheduledOccurrenceMsForRecord:(NSDictionary *)record {
591
+ if (![record isKindOfClass:NSDictionary.class]) {
592
+ return nil;
593
+ }
594
+
595
+ NSNumber *lastScheduledOccurrence =
596
+ [self rollingIntegerNumberFromObject:record[@"lastScheduledOccurrenceMs"]
597
+ allowNegative:NO
598
+ allowZero:NO];
599
+ if (lastScheduledOccurrence != nil) {
600
+ return lastScheduledOccurrence;
601
+ }
602
+
603
+ NSDictionary *trigger = record[@"trigger"];
604
+ if (![trigger isKindOfClass:NSDictionary.class]) {
605
+ return nil;
606
+ }
607
+
608
+ return [self rollingIntegerNumberFromObject:trigger[@"timestamp"] allowNegative:NO allowZero:NO];
609
+ }
610
+
611
+ + (NSNumber *)rollingIntegerNumberFromObject:(id)value
612
+ allowNegative:(BOOL)allowNegative
613
+ allowZero:(BOOL)allowZero {
614
+ if (![value isKindOfClass:NSNumber.class] ||
615
+ CFGetTypeID((__bridge CFTypeRef)value) == CFBooleanGetTypeID()) {
616
+ return nil;
617
+ }
618
+
619
+ double number = [value doubleValue];
620
+ if (!isfinite(number) || floor(number) != number || number > LLONG_MAX || number < LLONG_MIN) {
621
+ return nil;
622
+ }
623
+
624
+ if (!allowNegative && number < 0) {
625
+ return nil;
626
+ }
627
+
628
+ if (!allowZero && number == 0) {
629
+ return nil;
630
+ }
631
+
632
+ return @((long long)number);
633
+ }
634
+
635
+ + (BOOL)isSupportedRollingRepeatFrequency:(NSInteger)repeatFrequency {
636
+ return repeatFrequency == NotifeeCoreRepeatFrequencyHourly ||
637
+ repeatFrequency == NotifeeCoreRepeatFrequencyDaily ||
638
+ repeatFrequency == NotifeeCoreRepeatFrequencyWeekly ||
639
+ repeatFrequency == NotifeeCoreRepeatFrequencyMonthly;
640
+ }
641
+
642
+ + (NSInteger)rollingRepeatIntervalFromTrigger:(NSDictionary *)triggerDict {
643
+ NSNumber *repeatInterval = [self rollingIntegerNumberFromObject:triggerDict[@"repeatInterval"]
644
+ allowNegative:NO
645
+ allowZero:NO];
646
+ if (repeatInterval == nil || [repeatInterval doubleValue] > NSIntegerMax) {
647
+ return 1;
648
+ }
649
+
650
+ return [repeatInterval integerValue];
651
+ }
652
+
653
+ + (NSDate *)rollingDateByAddingRepeatFrequency:(NSInteger)repeatFrequency
654
+ interval:(NSInteger)interval
655
+ toDate:(NSDate *)date {
656
+ NSDateComponents *components = [[NSDateComponents alloc] init];
657
+
658
+ if (repeatFrequency == NotifeeCoreRepeatFrequencyHourly) {
659
+ components.hour = interval;
660
+ } else if (repeatFrequency == NotifeeCoreRepeatFrequencyDaily) {
661
+ components.day = interval;
662
+ } else if (repeatFrequency == NotifeeCoreRepeatFrequencyWeekly) {
663
+ components.weekOfYear = interval;
664
+ } else if (repeatFrequency == NotifeeCoreRepeatFrequencyMonthly) {
665
+ components.month = interval;
666
+ } else {
667
+ return nil;
668
+ }
669
+
670
+ return [[NSCalendar currentCalendar] dateByAddingComponents:components toDate:date options:0];
671
+ }
672
+
673
+ + (NSDictionary *)rollingPartsFromInternalNotificationId:(NSString *)internalId {
674
+ if (![internalId isKindOfClass:NSString.class] ||
675
+ ![internalId hasPrefix:kNotifeeRollingInternalIdPrefix]) {
676
+ return nil;
677
+ }
678
+
679
+ NSString *suffix = [internalId substringFromIndex:[kNotifeeRollingInternalIdPrefix length]];
680
+ NSRange separatorRange = [suffix rangeOfString:kNotifeeRollingInternalIdSeparator
681
+ options:NSBackwardsSearch];
682
+ if (separatorRange.location == NSNotFound || separatorRange.location == 0) {
683
+ return nil;
684
+ }
685
+
686
+ NSString *escapedPublicId = [suffix substringToIndex:separatorRange.location];
687
+ NSString *occurrenceString = [suffix substringFromIndex:NSMaxRange(separatorRange)];
688
+ if ([escapedPublicId length] == 0 || [occurrenceString length] == 0) {
689
+ return nil;
690
+ }
691
+
692
+ NSCharacterSet *nonDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
693
+ if ([occurrenceString rangeOfCharacterFromSet:nonDigits].location != NSNotFound) {
694
+ return nil;
695
+ }
696
+
697
+ long long occurrenceMs = [occurrenceString longLongValue];
698
+ if (occurrenceMs <= 0 ||
699
+ ![[NSString stringWithFormat:@"%lld", occurrenceMs] isEqualToString:occurrenceString]) {
700
+ return nil;
701
+ }
702
+
703
+ NSString *publicId = [escapedPublicId stringByRemovingPercentEncoding];
704
+ if (![publicId isKindOfClass:NSString.class] || [publicId length] == 0) {
705
+ return nil;
706
+ }
707
+
708
+ return @{@"publicId" : publicId, @"occurrenceMs" : @(occurrenceMs)};
709
+ }
710
+
711
+ + (NSMutableDictionary *)rollingSanitizedTimestampTriggerRecord:(NSDictionary *)record
712
+ publicId:(NSString *)publicId
713
+ defaultMissingCreatedAt:(BOOL)defaultMissingCreatedAt {
714
+ if (![record isKindOfClass:NSDictionary.class]) {
715
+ return nil;
716
+ }
717
+
718
+ NSString *resolvedPublicId = publicId;
719
+ if (![resolvedPublicId isKindOfClass:NSString.class] || [resolvedPublicId length] == 0) {
720
+ resolvedPublicId = record[@"publicId"];
721
+ }
722
+ if (![resolvedPublicId isKindOfClass:NSString.class] || [resolvedPublicId length] == 0) {
723
+ return nil;
724
+ }
725
+
726
+ id notification = [self rollingJSONObjectFromObject:record[@"notification"]];
727
+ id trigger = [self rollingJSONObjectFromObject:record[@"trigger"]];
728
+ if (![notification isKindOfClass:NSDictionary.class] ||
729
+ ![trigger isKindOfClass:NSDictionary.class]) {
730
+ return nil;
731
+ }
732
+ if (![self isRollingTimestampTrigger:trigger]) {
733
+ return nil;
734
+ }
735
+
736
+ NSMutableDictionary *sanitizedRecord = [NSMutableDictionary dictionary];
737
+ sanitizedRecord[@"publicId"] = resolvedPublicId;
738
+ sanitizedRecord[@"notification"] = notification;
739
+ sanitizedRecord[@"trigger"] = trigger;
740
+
741
+ NSNumber *lastScheduledOccurrence =
742
+ [self rollingIntegerNumberFromObject:record[@"lastScheduledOccurrenceMs"]
743
+ allowNegative:NO
744
+ allowZero:NO];
745
+ if (lastScheduledOccurrence != nil) {
746
+ sanitizedRecord[@"lastScheduledOccurrenceMs"] = lastScheduledOccurrence;
747
+ }
748
+
749
+ NSMutableArray<NSString *> *scheduledIds = [NSMutableArray array];
750
+ NSArray *rawScheduledIds = record[@"scheduledIds"];
751
+ if ([rawScheduledIds isKindOfClass:NSArray.class]) {
752
+ for (id scheduledId in rawScheduledIds) {
753
+ if ([scheduledId isKindOfClass:NSString.class] && [scheduledId length] > 0) {
754
+ [scheduledIds addObject:scheduledId];
755
+ }
756
+ }
757
+ }
758
+ sanitizedRecord[@"scheduledIds"] = scheduledIds;
759
+
760
+ NSNumber *createdAt = [self rollingIntegerNumberFromObject:record[@"createdAtMs"]
761
+ allowNegative:NO
762
+ allowZero:NO];
763
+ if (createdAt != nil) {
764
+ sanitizedRecord[@"createdAtMs"] = createdAt;
765
+ } else if (defaultMissingCreatedAt) {
766
+ sanitizedRecord[@"createdAtMs"] = [self rollingCurrentTimestampMs];
767
+ }
768
+
769
+ return sanitizedRecord;
770
+ }
771
+
772
+ + (NSMutableDictionary *)rollingSanitizedTimestampTriggerRecords:(NSDictionary *)records
773
+ defaultMissingCreatedAt:(BOOL)defaultMissingCreatedAt {
774
+ NSMutableDictionary *sanitizedRecords = [NSMutableDictionary dictionary];
775
+ if (![records isKindOfClass:NSDictionary.class]) {
776
+ return sanitizedRecords;
777
+ }
778
+
779
+ for (id key in records) {
780
+ if (![key isKindOfClass:NSString.class] || [key length] == 0) {
781
+ continue;
782
+ }
783
+
784
+ NSMutableDictionary *record =
785
+ [self rollingSanitizedTimestampTriggerRecord:records[key]
786
+ publicId:key
787
+ defaultMissingCreatedAt:defaultMissingCreatedAt];
788
+ if (record != nil) {
789
+ sanitizedRecords[key] = record;
790
+ }
791
+ }
792
+
793
+ return sanitizedRecords;
794
+ }
795
+
796
+ + (id)rollingJSONObjectFromObject:(id)object {
797
+ if (object == nil || object == [NSNull null]) {
798
+ return [NSNull null];
799
+ }
800
+
801
+ if ([object isKindOfClass:NSString.class]) {
802
+ return object;
803
+ }
804
+
805
+ if ([object isKindOfClass:NSNumber.class]) {
806
+ double number = [object doubleValue];
807
+ if (!isfinite(number)) {
808
+ return nil;
809
+ }
810
+ return object;
811
+ }
812
+
813
+ if ([object isKindOfClass:NSArray.class]) {
814
+ NSMutableArray *array = [NSMutableArray array];
815
+ for (id value in (NSArray *)object) {
816
+ id sanitizedValue = [self rollingJSONObjectFromObject:value];
817
+ if (sanitizedValue != nil) {
818
+ [array addObject:sanitizedValue];
819
+ }
820
+ }
821
+ return array;
822
+ }
823
+
824
+ if ([object isKindOfClass:NSDictionary.class]) {
825
+ NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
826
+ for (id key in (NSDictionary *)object) {
827
+ if (![key isKindOfClass:NSString.class]) {
828
+ continue;
829
+ }
830
+
831
+ id sanitizedValue = [self rollingJSONObjectFromObject:((NSDictionary *)object)[key]];
832
+ if (sanitizedValue != nil) {
833
+ dictionary[key] = sanitizedValue;
834
+ }
835
+ }
836
+ return dictionary;
837
+ }
838
+
839
+ return nil;
840
+ }
841
+
842
+ + (NSNumber *)rollingCurrentTimestampMs {
843
+ return @((long long)llround([[NSDate date] timeIntervalSince1970] * 1000.0));
844
+ }
845
+
322
846
  /**
323
847
  * Returns an UNNotificationTrigger from NSDictionary representing a
324
848
  * TimestampTrigger
@@ -408,12 +932,9 @@
408
932
  NSMutableArray<NSNumber *> *intentIdentifiers = [[NSMutableArray alloc] init];
409
933
 
410
934
  for (NSString *identifier in identifiers) {
411
- if ([identifier isEqualToString:INStartAudioCallIntentIdentifier]) {
412
- // IOSIntentIdentifier.START_AUDIO_CALL
413
- [intentIdentifiers addObject:@0];
414
- } else if ([identifier isEqualToString:INStartVideoCallIntentIdentifier]) {
415
- // IOSIntentIdentifier.START_VIDEO_CALL
416
- [intentIdentifiers addObject:@1];
935
+ if ([identifier isEqualToString:INStartCallIntentIdentifier]) {
936
+ // IOSIntentIdentifier.START_CALL
937
+ [intentIdentifiers addObject:@25];
417
938
  } else if ([identifier isEqualToString:INSearchCallHistoryIntentIdentifier]) {
418
939
  // IOSIntentIdentifier.SEARCH_CALL_HISTORY
419
940
  [intentIdentifiers addObject:@2];
@@ -494,12 +1015,15 @@
494
1015
  NSMutableArray<NSString *> *intentIdentifiers = [[NSMutableArray alloc] init];
495
1016
 
496
1017
  for (NSNumber *identifier in identifiers) {
497
- if ([identifier isEqualToNumber:@0]) {
1018
+ if ([identifier isEqualToNumber:@25]) {
1019
+ // IOSIntentIdentifier.START_CALL
1020
+ [intentIdentifiers addObject:INStartCallIntentIdentifier];
1021
+ } else if ([identifier isEqualToNumber:@0]) {
498
1022
  // IOSIntentIdentifier.START_AUDIO_CALL
499
- [intentIdentifiers addObject:INStartAudioCallIntentIdentifier];
1023
+ [intentIdentifiers addObject:INStartCallIntentIdentifier];
500
1024
  } else if ([identifier isEqualToNumber:@1]) {
501
1025
  // IOSIntentIdentifier.START_VIDEO_CALL
502
- [intentIdentifiers addObject:INStartVideoCallIntentIdentifier];
1026
+ [intentIdentifiers addObject:INStartCallIntentIdentifier];
503
1027
  } else if ([identifier isEqualToNumber:@2]) {
504
1028
  // IOSIntentIdentifier.SEARCH_CALL_HISTORY
505
1029
  [intentIdentifiers addObject:INSearchCallHistoryIntentIdentifier];
@@ -104,8 +104,8 @@ RCT_EXPORT_MODULE();
104
104
  - (void)sendNotifeeCoreEvent:(NSDictionary *_Nonnull)eventBody {
105
105
  dispatch_async(dispatch_get_main_queue(), ^{
106
106
  @synchronized(self) {
107
- if (!hasListeners) {
108
- [pendingCoreEvents addObject:eventBody];
107
+ if (!self->hasListeners) {
108
+ [self->pendingCoreEvents addObject:eventBody];
109
109
  return;
110
110
  }
111
111
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-notify-kit",
3
- "version": "10.1.0",
3
+ "version": "10.2.1",
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/index.ts CHANGED
@@ -33,3 +33,5 @@ export * from './types/NotificationIOS';
33
33
  export * from './types/NotificationAndroid';
34
34
  export * from './types/PowerManagerInfo';
35
35
  export type { FcmRemoteMessage, FcmConfig } from './fcm/types';
36
+ export type { ModuleWithStatics } from './types/Module';
37
+ export type { WebNotificationSettings } from './types/NotificationWeb';