Skip to content

Commit 679d712

Browse files
committed
Fixing preventDefault behavior
In order to get preventDefault() and display() to work the bridge layer listener needs to call preventDefault() so that the notification does not display before the flutter listeners have had a chance to call preventDefault(). Once all of the flutter listeners have responded to the event, if none of them have called preventDefault then the bridge layer will call display().
1 parent 4d8c48f commit 679d712

File tree

4 files changed

+58
-3
lines changed

4 files changed

+58
-3
lines changed

android/src/main/java/com/onesignal/flutter/OneSignalNotifications.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838

3939
public class OneSignalNotifications extends FlutterRegistrarResponder implements MethodCallHandler, INotificationClickListener, INotificationLifecycleListener, IPermissionObserver {
4040
private final HashMap<String, INotificationWillDisplayEvent> notificationOnWillDisplayEventCache = new HashMap<>();
41+
private final HashMap<String, INotificationWillDisplayEvent> preventedDefaultCache = new HashMap<>();
42+
4143

4244
static void registerWith(BinaryMessenger messenger) {
4345
OneSignalNotifications controller = new OneSignalNotifications();
@@ -64,14 +66,17 @@ else if (call.method.contentEquals("OneSignal#preventDefault"))
6466
this.preventDefault(call, result);
6567
else if (call.method.contentEquals("OneSignal#lifecycleInit"))
6668
this.lifecycleInit();
69+
else if (call.method.contentEquals("OneSignal#proceedWithWillDisplay"))
70+
this.proceedWithWillDisplay(call, result);
6771
else
6872
replyNotImplemented(result);
6973
}
7074

7175
private void requestPermission(MethodCall call, Result result) {
7276
boolean fallback = (boolean) call.argument("fallbackToSettings");
73-
OneSignal.getNotifications().requestPermission(fallback, Continue.none());
74-
replySuccess(result, null);
77+
OneSignal.getNotifications().requestPermission(fallback, Continue.with(permissionResult -> {
78+
replySuccess(result, permissionResult.getData());
79+
}));
7580
}
7681

7782
private void removeNotification(MethodCall call, Result result) {
@@ -93,6 +98,24 @@ private void clearAll(MethodCall call, Result result) {
9398
replySuccess(result, null);
9499
}
95100

101+
/// Our bridge layer needs to preventDefault() so that the Flutter listener has time to preventDefault() before the notification is displayed
102+
/// This function is called after all of the flutter listeners have responded to the willDisplay event.
103+
/// If any of them have called preventDefault() we will not call display(). Otherwise we will display.
104+
private void proceedWithWillDisplay(MethodCall call, Result result) {
105+
String notificationId = call.argument("notificationId");
106+
INotificationWillDisplayEvent event = notificationOnWillDisplayEventCache.get(notificationId);
107+
if (event == null) {
108+
Logging.error("Could not find onWillDisplayNotification event for notification with id: " + notificationId, null);
109+
return;
110+
}
111+
if (this.preventedDefaultCache.containsKey(notificationId)) {
112+
replySuccess(result, null);
113+
return;
114+
}
115+
event.getNotification().display();
116+
replySuccess(result, null);
117+
}
118+
96119
private void displayNotification(MethodCall call, Result result) {
97120
String notificationId = call.argument("notificationId");
98121
INotificationWillDisplayEvent event = notificationOnWillDisplayEventCache.get(notificationId);
@@ -112,6 +135,7 @@ private void preventDefault(MethodCall call, Result result) {
112135
return;
113136
}
114137
event.preventDefault();
138+
this.preventedDefaultCache.put(notificationId, event);
115139
replySuccess(result, null);
116140
}
117141

@@ -141,6 +165,8 @@ private JSONObject getJsonFromMap(Map<String, Object> map) throws JSONException
141165
public void onWillDisplay(INotificationWillDisplayEvent event) {
142166
INotification notification = event.getNotification();
143167
notificationOnWillDisplayEventCache.put(notification.getNotificationId(), event);
168+
/// Our bridge layer needs to preventDefault() so that the Flutter listener has time to preventDefault() before the notification is displayed
169+
event.preventDefault();
144170
try {
145171
invokeMethodOnUiThread("OneSignal#onWillDisplayNotification", OneSignalSerializer.convertNotificationWillDisplayEventToMap(event));
146172
} catch (JSONException e) {

ios/Classes/OSFlutterNotifications.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@
3535
@property (strong, nonatomic) FlutterMethodChannel *channel;
3636
+ (instancetype)sharedInstance;
3737
@property (strong, nonatomic) NSMutableDictionary* onWillDisplayEventCache;
38-
38+
@property (strong, nonatomic) NSMutableDictionary* preventedDefaultCache;
3939

4040
@end

ios/Classes/OSFlutterNotifications.m

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ + (instancetype)sharedInstance {
3838
dispatch_once(&onceToken, ^{
3939
sharedInstance = [OSFlutterNotifications new];
4040
sharedInstance.onWillDisplayEventCache = [NSMutableDictionary new];
41+
sharedInstance.preventedDefaultCache = [NSMutableDictionary new];
4142
});
4243
return sharedInstance;
4344
}
@@ -70,6 +71,8 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
7071
[self preventDefault:call withResult:result];
7172
else if ([@"OneSignal#lifecycleInit" isEqualToString:call.method])
7273
[self lifecycleInit:call withResult:result];
74+
else if ([@"OneSignal#proceedWithWillDisplay" isEqualToString:call.method])
75+
[self proceedWithWillDisplay:call withResult:result];
7376
else
7477
result(FlutterMethodNotImplemented);
7578
}
@@ -113,9 +116,28 @@ - (void)onNotificationPermissionDidChange:(BOOL)permission {
113116

114117
- (void)onWillDisplayNotification:(OSNotificationWillDisplayEvent *)event {
115118
self.onWillDisplayEventCache[event.notification.notificationId] = event;
119+
/// Our bridge layer needs to preventDefault so that the Flutter listener has time to preventDefault before the notification is displayed
120+
[event preventDefault];
116121
[self.channel invokeMethod:@"OneSignal#onWillDisplayNotification" arguments:event.toJson];
117122
}
118123

124+
/// Our bridge layer needs to preventDefault so that the Flutter listener has time to preventDefault before the notification is displayed
125+
/// This function is called after all of the flutter listeners have responded to the willDisplay event.
126+
/// If any of them have called preventDefault we will not call display(). Otherwise we will display.
127+
- (void)proceedWithWillDisplay:(FlutterMethodCall *)call withResult:(FlutterResult)result {
128+
NSString *notificationId = call.arguments[@"notificationId"];
129+
OSNotificationWillDisplayEvent *event = self.onWillDisplayEventCache[notificationId];
130+
if (!event) {
131+
[OneSignalLog onesignalLog:ONE_S_LL_ERROR message:[NSString stringWithFormat:@"OneSignal (objc): could not find notification will display event for notification with id: %@", notificationId]];
132+
return;
133+
}
134+
if (self.preventedDefaultCache[notificationId]) {
135+
return;
136+
}
137+
[event.notification display];
138+
result(nil);
139+
}
140+
119141
- (void)preventDefault:(FlutterMethodCall *)call withResult:(FlutterResult)result {
120142
NSString *notificationId = call.arguments[@"notificationId"];
121143
OSNotificationWillDisplayEvent *event = self.onWillDisplayEventCache[notificationId];
@@ -125,6 +147,8 @@ - (void)preventDefault:(FlutterMethodCall *)call withResult:(FlutterResult)resul
125147
return;
126148
}
127149
[event preventDefault];
150+
self.preventedDefaultCache[event.notification.notificationId] = event;
151+
result(nil);
128152
}
129153

130154
- (void)displayNotification:(FlutterMethodCall *)call withResult:(FlutterResult)result {
@@ -136,6 +160,7 @@ - (void)displayNotification:(FlutterMethodCall *)call withResult:(FlutterResult)
136160
return;
137161
}
138162
[event.notification display];
163+
result(nil);
139164
}
140165

141166
#pragma mark Notification Click

lib/src/notifications.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ class OneSignalNotifications {
133133
listener.onWillDisplayNotification(OSNotificationWillDisplayEvent(
134134
call.arguments.cast<String, dynamic>()));
135135
}
136+
var event = OSNotificationWillDisplayEvent(
137+
call.arguments.cast<String, dynamic>());
138+
_channel.invokeMethod("OneSignal#proceedWithWillDisplay",
139+
{'notificationId': event.notification.notificationId});
136140
} else if (call.method == 'OneSignal#onNotificationPermissionDidChange') {
137141
this.onNotificationPermissionDidChange(call.arguments["permission"]);
138142
}

0 commit comments

Comments
 (0)