Skip to content

Commit 7865d58

Browse files
Nightsd01jkasten2
authored andcommitted
Switch to Completion Block Based Approach
• Instead of using a pointer based approach to setting the display type for a given notification, we are switching to using a completion block (callback) • This commit changes the OSNotificationDisplayTypeDelegate to accept the completion block. If the delegate has been set, the SDK will wait until the delegate calls the completion block to deliver a notification.
1 parent eb48492 commit 7865d58

File tree

4 files changed

+91
-63
lines changed

4 files changed

+91
-63
lines changed

iOS_SDK/OneSignalSDK/Source/OneSignal.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,10 +213,14 @@ typedef NS_ENUM(NSInteger, OSNotificationPermission) {
213213
OSNotificationPermissionProvisional
214214
};
215215

216+
typedef void (^OSNotificationDisplayTypeResponse)(OSNotificationDisplayType displayType);
217+
216218
// Notification Display Type Delegate
217219
// Allows apps to customize per-notification display-type
218220
@protocol OSNotificationDisplayTypeDelegate <NSObject>
219-
- (void)willPresentInFocusNotificationWithPayload:(OSNotificationPayload *)payload forDisplayType:(OSNotificationDisplayType *)type;
221+
- (void)willPresentInFocusNotificationWithPayload:(OSNotificationPayload *)payload
222+
withDefaultDisplayType:(OSNotificationDisplayType)displayType
223+
withCompletion:(OSNotificationDisplayTypeResponse)completion;
220224
@end
221225

222226

iOS_SDK/OneSignalSDK/Source/OneSignal.m

Lines changed: 62 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,7 @@ @implementation OneSignal
201201
// Display type is used in multiple areas of the SDK
202202
// To avoid calling the delegate multiple times, we store
203203
// the type and notification ID for each notification
204-
static NSString *_lastCustomDisplayTypeNotificationId;
205-
static OSNotificationDisplayType _lastCustomDisplayType;
204+
static NSMutableDictionary<NSString *, NSNumber *> *_displayTypeMap;
206205

207206
static OSNotificationDisplayType _inFocusDisplayType = OSNotificationDisplayTypeInAppAlert;
208207
+ (void)setInFocusDisplayType:(OSNotificationDisplayType)value {
@@ -403,7 +402,7 @@ + (void)clearStatics {
403402
pendingExternalUserId = nil;
404403

405404
_displayDelegate = nil;
406-
_lastCustomDisplayTypeNotificationId = nil;
405+
_displayTypeMap = [NSMutableDictionary new];
407406
}
408407

409408
// Set to false as soon as it's read.
@@ -1758,27 +1757,37 @@ + (void)setLastAppActiveMessageId:(NSString*)value { _lastAppActiveMessageId = v
17581757
static NSString *_lastnonActiveMessageId;
17591758
+ (void)setLastnonActiveMessageId:(NSString*)value { _lastnonActiveMessageId = value; }
17601759

1761-
+ (OSNotificationDisplayType)displayTypeForNotificationPayload:(NSDictionary *)payload {
1762-
var type = self.inFocusDisplayType;
1763-
1764-
// check to make sure the app is in focus and it's a OneSignal notification
1765-
if (![OneSignalHelper isOneSignalPayload:payload]
1766-
|| UIApplication.sharedApplication.applicationState != UIApplicationStateActive)
1767-
return type;
1768-
1769-
let osPayload = [OSNotificationPayload parseWithApns:payload];
1770-
1771-
// Prevent calling the delegate multiple times for the same payload
1772-
if (_lastCustomDisplayTypeNotificationId && [osPayload.notificationID isEqualToString:_lastCustomDisplayTypeNotificationId])
1773-
return _lastCustomDisplayType;
1774-
1775-
if (_displayDelegate) {
1776-
[_displayDelegate willPresentInFocusNotificationWithPayload:osPayload forDisplayType:&type];
1777-
_lastCustomDisplayType = type;
1778-
_lastCustomDisplayTypeNotificationId = osPayload.notificationID;
1779-
}
1780-
1781-
return type;
1760+
+ (void)displayTypeForNotificationPayload:(NSDictionary *)payload withCompletion:(OSNotificationDisplayTypeResponse)completion {
1761+
[OneSignalHelper runOnMainThread:^{
1762+
var type = self.inFocusDisplayType;
1763+
1764+
// check to make sure the app is in focus and it's a OneSignal notification
1765+
if (![OneSignalHelper isOneSignalPayload:payload]
1766+
|| UIApplication.sharedApplication.applicationState != UIApplicationStateActive) {
1767+
completion(type);
1768+
return;
1769+
}
1770+
1771+
let osPayload = [OSNotificationPayload parseWithApns:payload];
1772+
1773+
let notificationId = osPayload.notificationID;
1774+
1775+
// Prevent calling the delegate multiple times for the same payload
1776+
if (_displayTypeMap[osPayload.notificationID]) {
1777+
type = (OSNotificationDisplayType)[_displayTypeMap[osPayload.notificationID] intValue];
1778+
completion(type);
1779+
} else if (_displayDelegate) {
1780+
[_displayDelegate willPresentInFocusNotificationWithPayload:osPayload withDefaultDisplayType:type withCompletion:^(OSNotificationDisplayType displayType) {
1781+
[OneSignalHelper runOnMainThread:^{
1782+
_displayTypeMap[notificationId] = @((int)displayType);
1783+
completion(displayType);
1784+
}];
1785+
}];
1786+
} else {
1787+
_displayTypeMap[notificationId] = @((int)type);
1788+
completion(type);
1789+
}
1790+
}];
17821791
}
17831792

17841793
// Entry point for the following:
@@ -1812,40 +1821,46 @@ + (void)notificationReceived:(NSDictionary*)messageDict isActive:(BOOL)isActive
18121821
if (newId)
18131822
_lastAppActiveMessageId = newId;
18141823

1815-
let displayType = [self displayTypeForNotificationPayload:messageDict];
1816-
1817-
let inAppAlert = (displayType == OSNotificationDisplayTypeInAppAlert);
1818-
1819-
// Make sure it is not a silent one do display, if inAppAlerts are enabled
1820-
if (inAppAlert && ![OneSignalHelper isRemoteSilentNotification:messageDict]) {
1821-
[OneSignalAlertView showInAppAlert:messageDict];
1822-
return;
1823-
}
1824-
1825-
// App is active and a notification was received without inApp display. Display type is none or notification
1826-
// Call Received Block
1827-
[OneSignalHelper handleNotificationReceived:displayType];
1824+
[self displayTypeForNotificationPayload:messageDict withCompletion:^(OSNotificationDisplayType displayType) {
1825+
let inAppAlert = (displayType == OSNotificationDisplayTypeInAppAlert);
1826+
1827+
// Make sure it is not a silent one do display, if inAppAlerts are enabled
1828+
if (inAppAlert && ![OneSignalHelper isRemoteSilentNotification:messageDict]) {
1829+
[OneSignalAlertView showInAppAlert:messageDict];
1830+
return;
1831+
}
1832+
1833+
// App is active and a notification was received without inApp display. Display type is none or notification
1834+
// Call Received Block
1835+
[OneSignalHelper handleNotificationReceived:displayType];
1836+
1837+
if (opened)
1838+
[self openedNotificationWithDisplayType:displayType withPayload:messageDict isActive:isActive];
1839+
}];
18281840
} else {
18291841
// Prevent duplicate calls
18301842
let newId = [self checkForProcessedDups:customDict lastMessageId:_lastnonActiveMessageId];
18311843
if ([@"dup" isEqualToString:newId])
18321844
return;
18331845
if (newId)
18341846
_lastnonActiveMessageId = newId;
1835-
}
1836-
1837-
if (opened) {
1838-
//app was in background / not running and opened due to a tap on a notification or an action check what type
1839-
OSNotificationActionType type = OSNotificationActionTypeOpened;
1840-
1841-
if (messageDict[@"custom"][@"a"][@"actionSelected"] || messageDict[@"actionSelected"])
1842-
type = OSNotificationActionTypeActionTaken;
18431847

1844-
// Call Action Block
1845-
[OneSignal handleNotificationOpened:messageDict isActive:isActive actionType:type displayType:OneSignal.inFocusDisplayType];
1848+
if (opened)
1849+
[self openedNotificationWithDisplayType:OneSignal.inFocusDisplayType withPayload:messageDict isActive:isActive];
18461850
}
18471851
}
18481852

1853+
+ (void)openedNotificationWithDisplayType:(OSNotificationDisplayType)displayType withPayload:(NSDictionary *)payload isActive:(BOOL)isActive {
1854+
//app was in background / not running and opened due to a tap on a notification or an action check what type
1855+
OSNotificationActionType type = OSNotificationActionTypeOpened;
1856+
1857+
if (payload[@"custom"][@"a"][@"actionSelected"] || payload[@"actionSelected"])
1858+
type = OSNotificationActionTypeActionTaken;
1859+
1860+
// Call Action Block
1861+
[OneSignal handleNotificationOpened:payload isActive:isActive actionType:type displayType:displayType];
1862+
}
1863+
18491864
+ (NSString*) checkForProcessedDups:(NSDictionary*)customDict lastMessageId:(NSString*)lastMessageId {
18501865
if (customDict && customDict[@"i"]) {
18511866
NSString* currentNotificationId = customDict[@"i"];

iOS_SDK/OneSignalSDK/Source/UNUserNotificationCenter+OneSignal.m

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,12 @@
4646
#pragma clang diagnostic push
4747
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
4848

49+
typedef void (^OSUNNotificationCenterCompletionHandler)(UNNotificationPresentationOptions options);
50+
4951
@interface OneSignal (UN_extra)
5052
+ (void)notificationReceived:(NSDictionary*)messageDict isActive:(BOOL)isActive wasOpened:(BOOL)opened;
5153
+ (BOOL)shouldLogMissingPrivacyConsentErrorWithMethodName:(NSString *)methodName;
52-
+ (OSNotificationDisplayType)displayTypeForNotificationPayload:(NSDictionary *)payload;
54+
+ (void)displayTypeForNotificationPayload:(NSDictionary *)payload withCompletion:(OSNotificationDisplayTypeResponse)completion;
5355
@end
5456

5557
// This class hooks into the following iSO 10 UNUserNotificationCenterDelegate selectors:
@@ -176,12 +178,19 @@ - (void)onesignalUserNotificationCenter:(UNUserNotificationCenter *)center
176178

177179
[OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"onesignalUserNotificationCenter:willPresentNotification:withCompletionHandler: Fired!"];
178180

181+
[OneSignal displayTypeForNotificationPayload:notification.request.content.userInfo withCompletion:^(OSNotificationDisplayType displayType) {
182+
finishProcessingNotification(notification, center, displayType, completionHandler, self);
183+
}];
184+
}
185+
186+
// To avoid complications caused by swizzling, this is implemented as a C function
187+
void finishProcessingNotification(UNNotification *notification,
188+
UNUserNotificationCenter *center,
189+
OSNotificationDisplayType displayType,
190+
OSUNNotificationCenterCompletionHandler completionHandler,
191+
OneSignalUNUserNotificationCenter *instance) {
179192
NSUInteger completionHandlerOptions = 0;
180193

181-
let messagePayload = notification.request.content.userInfo;
182-
183-
let displayType = [OneSignal displayTypeForNotificationPayload:messagePayload];
184-
185194
switch (displayType) {
186195
case OSNotificationDisplayTypeNone: completionHandlerOptions = 0; break; // Nothing
187196
case OSNotificationDisplayTypeInAppAlert: completionHandlerOptions = 3; break; // Badge + Sound
@@ -192,19 +201,19 @@ - (void)onesignalUserNotificationCenter:(UNUserNotificationCenter *)center
192201
let notShown = displayType == OSNotificationDisplayTypeNone && notification.request.content.body != nil;
193202

194203
if ([OneSignal app_id])
195-
[OneSignal notificationReceived:messagePayload isActive:YES wasOpened:notShown];
204+
[OneSignal notificationReceived:notification.request.content.userInfo isActive:YES wasOpened:notShown];
196205

197206
// Call orginal selector if one was set.
198-
if ([self respondsToSelector:@selector(onesignalUserNotificationCenter:willPresentNotification:withCompletionHandler:)])
199-
[self onesignalUserNotificationCenter:center willPresentNotification:notification withCompletionHandler:completionHandler];
207+
if ([instance respondsToSelector:@selector(onesignalUserNotificationCenter:willPresentNotification:withCompletionHandler:)])
208+
[instance onesignalUserNotificationCenter:center willPresentNotification:notification withCompletionHandler:completionHandler];
200209
// Or call a legacy AppDelegate selector
201210
else {
202211
[OneSignalUNUserNotificationCenter callLegacyAppDeletegateSelector:notification
203-
isTextReply:false
204-
actionIdentifier:nil
205-
userText:nil
206-
fromPresentNotification:true
207-
withCompletionHandler:^() {}];
212+
isTextReply:false
213+
actionIdentifier:nil
214+
userText:nil
215+
fromPresentNotification:true
216+
withCompletionHandler:^() {}];
208217
}
209218

210219
// Calling completionHandler for the following reasons:

iOS_SDK/OneSignalSDK/UnitTests/DummyNotificationDisplayTypeDelegate.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ - (instancetype)init {
3737
return self;
3838
}
3939

40-
- (void)willPresentInFocusNotificationWithPayload:(OSNotificationPayload *)payload forDisplayType:(OSNotificationDisplayType *)type {
40+
- (void)willPresentInFocusNotificationWithPayload:(OSNotificationPayload *)payload withDefaultDisplayType:(OSNotificationDisplayType)displayType withCompletion:(OSNotificationDisplayTypeResponse)completion {
4141
_notificationId = payload.notificationID;
4242

43-
*type = _overrideDisplayType;
43+
completion(_overrideDisplayType);
4444

4545
_numberOfCalls += 1;
4646
}

0 commit comments

Comments
 (0)