Skip to content

Commit 3379bbf

Browse files
authored
Using UNUserNotification instead of deprecated UILocalNotification class (#411)
* Using UNUserNotification instead of deprecated UILocalNotification class * handle cancel action add semaphore for to wait for blocks to finish * change wait time to be max 5 seconds
1 parent 6bc4a69 commit 3379bbf

File tree

1 file changed

+169
-63
lines changed

1 file changed

+169
-63
lines changed

Leanplum-SDK/Classes/Notifications/Local/LPLocalNotificationsManager.m

Lines changed: 169 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#import "LeanplumInternal.h"
1111
#import "LPNotificationsConstants.h"
1212
#import "LPNotificationsManager.h"
13+
#import <UserNotifications/UNUserNotificationCenter.h>
1314

1415
@implementation LPLocalNotificationsManager
1516

@@ -41,15 +42,9 @@ - (void)listenForLocalNotifications
4142
BOOL contentAvailable = [context boolNamed:@"iOS options.Preload content"];
4243
NSString *message = [context stringNamed:@"Message"];
4344

44-
// Don't send notification if the user doesn't have the permission enabled.
45-
if ([app respondsToSelector:@selector(currentUserNotificationSettings)]) {
46-
BOOL isSilentNotification = message.length == 0 && contentAvailable;
47-
if (!isSilentNotification) {
48-
UIUserNotificationSettings *currentSettings = [app currentUserNotificationSettings];
49-
if ([currentSettings types] == UIUserNotificationTypeNone) {
50-
return NO;
51-
}
52-
}
45+
if (![self shouldSendNotificationForMessage:message contentAvailable:contentAvailable])
46+
{
47+
return NO;
5348
}
5449

5550
NSString *messageId = context.messageId;
@@ -67,53 +62,17 @@ - (void)listenForLocalNotifications
6762
int countdownSeconds = [countdown intValue];
6863
NSDate *eta = [[NSDate date] dateByAddingTimeInterval:countdownSeconds];
6964

70-
// If there's already one scheduled before the eta, discard this.
71-
// Otherwise, discard the scheduled one.
72-
NSArray *notifications = [app scheduledLocalNotifications];
73-
for (UILocalNotification *notification in notifications) {
74-
NSString *messageId = [[LPNotificationsManager shared] messageIdFromUserInfo:[notification userInfo]];
75-
if ([messageId isEqualToString:context.messageId]) {
76-
NSComparisonResult comparison = [notification.fireDate compare:eta];
77-
if (comparison == NSOrderedAscending) {
78-
return NO;
79-
} else {
80-
[app cancelLocalNotification:notification];
81-
}
82-
}
83-
}
84-
85-
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
86-
localNotif.fireDate = eta;
87-
localNotif.timeZone = [NSTimeZone defaultTimeZone];
88-
if (message) {
89-
localNotif.alertBody = message;
90-
} else {
91-
localNotif.alertBody = LP_VALUE_DEFAULT_PUSH_MESSAGE;
92-
}
93-
localNotif.alertAction = @"View";
94-
95-
if ([localNotif respondsToSelector:@selector(setCategory:)]) {
96-
NSString *category = [context stringNamed:@"iOS options.Category"];
97-
if (category) {
98-
localNotif.category = category;
99-
}
100-
}
101-
102-
NSString *sound = [context stringNamed:@"iOS options.Sound"];
103-
if (sound) {
104-
localNotif.soundName = sound;
105-
} else {
106-
localNotif.soundName = UILocalNotificationDefaultSoundName;
107-
}
108-
109-
NSString *badge = [context stringNamed:@"iOS options.Badge"];
110-
if (badge) {
111-
localNotif.applicationIconBadgeNumber = [badge intValue];
65+
if ([self shouldDiscard:eta context:context])
66+
{
67+
return NO;
11268
}
113-
69+
11470
NSDictionary *userInfo = [context dictionaryNamed:@"Advanced options.Data"];
11571
NSString *openAction = [context stringNamed:LP_VALUE_DEFAULT_PUSH_ACTION];
11672
BOOL muteInsideApp = [context boolNamed:@"Advanced options.Mute inside app"];
73+
NSString *sound = [context stringNamed:@"iOS options.Sound"];
74+
NSString *badge = [context stringNamed:@"iOS options.Badge"];
75+
NSString *category = [context stringNamed:@"iOS options.Category"];
11776

11877
// Specify custom data for the notification
11978
NSMutableDictionary *mutableInfo;
@@ -140,11 +99,76 @@ - (void)listenForLocalNotifications
14099
mutableInfo[LP_KEY_PUSH_NO_ACTION] = messageId;
141100
}
142101
}
102+
103+
if (@available(iOS 10.0, *)) {
104+
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
105+
106+
if (message) {
107+
content.body = message;
108+
} else {
109+
content.body = LP_VALUE_DEFAULT_PUSH_MESSAGE;
110+
}
111+
112+
if (category) {
113+
content.categoryIdentifier = category;
114+
}
115+
116+
if (sound) {
117+
content.sound = [UNNotificationSound soundNamed:sound];
118+
} else {
119+
content.sound = [UNNotificationSound defaultSound];
120+
}
143121

144-
localNotif.userInfo = mutableInfo;
122+
if (badge) {
123+
content.badge = [NSNumber numberWithInt:[badge intValue]];
124+
}
145125

146-
// Schedule the notification
147-
[app scheduleLocalNotification:localNotif];
126+
content.userInfo = mutableInfo;
127+
128+
NSDateComponents *dateComponenets = [[NSDateComponents alloc] init];
129+
[dateComponenets setSecond:countdownSeconds];
130+
UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:dateComponenets repeats:NO];
131+
132+
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:messageId content:content trigger:trigger];
133+
134+
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
135+
if (error) {
136+
LPLog(LPError, error.localizedDescription);
137+
}
138+
}];
139+
140+
} else {
141+
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
142+
localNotif.fireDate = eta;
143+
localNotif.timeZone = [NSTimeZone defaultTimeZone];
144+
if (message) {
145+
localNotif.alertBody = message;
146+
} else {
147+
localNotif.alertBody = LP_VALUE_DEFAULT_PUSH_MESSAGE;
148+
}
149+
localNotif.alertAction = @"View";
150+
151+
if ([localNotif respondsToSelector:@selector(setCategory:)]) {
152+
if (category) {
153+
localNotif.category = category;
154+
}
155+
}
156+
157+
if (sound) {
158+
localNotif.soundName = sound;
159+
} else {
160+
localNotif.soundName = UILocalNotificationDefaultSoundName;
161+
}
162+
163+
if (badge) {
164+
localNotif.applicationIconBadgeNumber = [badge intValue];
165+
}
166+
167+
localNotif.userInfo = mutableInfo;
168+
169+
// Schedule the notification
170+
[app scheduleLocalNotification:localNotif];
171+
}
148172

149173
if ([LPConstantsState sharedState].isDevelopmentModeEnabled) {
150174
LPLog(LPInfo, @"Scheduled notification");
@@ -157,20 +181,102 @@ - (void)listenForLocalNotifications
157181
LP_END_USER_CODE
158182
UIApplication *app = [UIApplication sharedApplication];
159183
NSArray *notifications = [app scheduledLocalNotifications];
160-
BOOL didCancel = NO;
184+
if (@available(iOS 10.0, *)) {
185+
__block BOOL didCancel = NO;
186+
dispatch_semaphore_t semaphor = dispatch_semaphore_create(0);
187+
[UNUserNotificationCenter.currentNotificationCenter getPendingNotificationRequestsWithCompletionHandler:^(NSArray<UNNotificationRequest *> * _Nonnull requests) {
188+
for (UNNotificationRequest *request in requests) {
189+
NSString *messageId = [[LPNotificationsManager shared] messageIdFromUserInfo:[request.content userInfo]];
190+
if ([messageId isEqualToString:context.messageId]) {
191+
[UNUserNotificationCenter.currentNotificationCenter removeDeliveredNotificationsWithIdentifiers:@[request.identifier]];
192+
if ([LPConstantsState sharedState].isDevelopmentModeEnabled) {
193+
LPLog(LPInfo, @"Cancelled notification");
194+
}
195+
didCancel = YES;
196+
}
197+
}
198+
dispatch_semaphore_signal(semaphor);
199+
}];
200+
dispatch_time_t waitTime = dispatch_time(DISPATCH_TIME_NOW, 5.0 * NSEC_PER_SEC);
201+
dispatch_semaphore_wait(semaphor, waitTime);
202+
LP_BEGIN_USER_CODE
203+
return didCancel;
204+
} else {
205+
// Fallback on earlier versions
206+
BOOL didCancel = NO;
207+
for (UILocalNotification *notification in notifications) {
208+
NSString *messageId = [[LPNotificationsManager shared] messageIdFromUserInfo:[notification userInfo]];
209+
if ([messageId isEqualToString:context.messageId]) {
210+
[app cancelLocalNotification:notification];
211+
if ([LPConstantsState sharedState].isDevelopmentModeEnabled) {
212+
LPLog(LPInfo, @"Cancelled notification");
213+
}
214+
didCancel = YES;
215+
}
216+
}
217+
LP_BEGIN_USER_CODE
218+
return didCancel;
219+
}
220+
}];
221+
}
222+
223+
- (BOOL)shouldSendNotificationForMessage:(NSString *)message contentAvailable:(BOOL)contentAvailable
224+
{
225+
// Don't send notification if the user doesn't have the permission enabled.
226+
if ([[UIApplication sharedApplication] respondsToSelector:@selector(currentUserNotificationSettings)]) {
227+
BOOL isSilentNotification = message.length == 0 && contentAvailable;
228+
if (!isSilentNotification) {
229+
UIUserNotificationSettings *currentSettings = [[UIApplication sharedApplication] currentUserNotificationSettings];
230+
if ([currentSettings types] == UIUserNotificationTypeNone) {
231+
return NO;
232+
}
233+
}
234+
}
235+
return YES;
236+
}
237+
238+
- (BOOL)shouldDiscard:(NSDate *)eta context:(LPActionContext *)context
239+
{
240+
// If there's already one scheduled before the eta, discard this.
241+
// Otherwise, discard the scheduled one.
242+
if (@available(iOS 10.0, *)) {
243+
__block BOOL shouldDiscard = NO;
244+
dispatch_semaphore_t semaphor = dispatch_semaphore_create(0);
245+
[UNUserNotificationCenter.currentNotificationCenter getPendingNotificationRequestsWithCompletionHandler:^(NSArray<UNNotificationRequest *> * _Nonnull requests) {
246+
for (UNNotificationRequest *request in requests) {
247+
NSString *messageId = [[LPNotificationsManager shared] messageIdFromUserInfo:[request.content userInfo]];
248+
if ([messageId isEqualToString:context.messageId]) {
249+
UNCalendarNotificationTrigger *trigger = (UNCalendarNotificationTrigger *)request.trigger;
250+
NSComparisonResult comparison = [trigger.nextTriggerDate compare:eta];
251+
if (comparison == NSOrderedAscending) {
252+
shouldDiscard = YES;
253+
break;
254+
} else {
255+
[UNUserNotificationCenter.currentNotificationCenter removeDeliveredNotificationsWithIdentifiers:@[request.identifier]];
256+
}
257+
}
258+
}
259+
dispatch_semaphore_signal(semaphor);
260+
}];
261+
dispatch_time_t waitTime = dispatch_time(DISPATCH_TIME_NOW, 5.0 * NSEC_PER_SEC);
262+
dispatch_semaphore_wait(semaphor, waitTime);
263+
return shouldDiscard;
264+
} else {
265+
// Fallback on earlier versions
266+
NSArray *notifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
161267
for (UILocalNotification *notification in notifications) {
162268
NSString *messageId = [[LPNotificationsManager shared] messageIdFromUserInfo:[notification userInfo]];
163269
if ([messageId isEqualToString:context.messageId]) {
164-
[app cancelLocalNotification:notification];
165-
if ([LPConstantsState sharedState].isDevelopmentModeEnabled) {
166-
LPLog(LPInfo, @"Cancelled notification");
270+
NSComparisonResult comparison = [notification.fireDate compare:eta];
271+
if (comparison == NSOrderedAscending) {
272+
return YES;
273+
} else {
274+
[[UIApplication sharedApplication] cancelLocalNotification:notification];
167275
}
168-
didCancel = YES;
169276
}
170277
}
171-
LP_BEGIN_USER_CODE
172-
return didCancel;
173-
}];
278+
return NO;
279+
}
174280
}
175281

176282
@end

0 commit comments

Comments
 (0)