Skip to content

Commit 71dee2b

Browse files
authored
feat(ios, messaging): Allow notifications in foreground on iOS, configure in firebase.json (#6407)
1 parent d9d01d0 commit 71dee2b

File tree

6 files changed

+101
-31
lines changed

6 files changed

+101
-31
lines changed

.spellcheck.dict.txt

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@
22
64k
33
Ad
44
AdMob
5-
Analytics
5+
AirPods
66
analytics
7+
Analytics
78
ANR
89
APIs
910
APIs.
11+
APNs
1012
AppAttest
1113
AppCheck
1214
AppDelegate.m
13-
APNs
14-
AirPods
1515
async
1616
ATT
1717
ATT-compatible
@@ -22,16 +22,17 @@ AuthSettings
2222
autolinking
2323
Autolinking
2424
AVD
25-
Axios
2625
axios
26+
Axios
2727
backend
2828
backgrounded
2929
backoff
30-
Barcode
3130
barcode
31+
Barcode
3232
barcodes
3333
BUGFIX
3434
CarPlay
35+
CDN
3536
Changelog
3637
checkForUpdate
3738
CLI
@@ -40,16 +41,17 @@ codebase
4041
config
4142
Config
4243
config-plugin
44+
CP-User
4345
crashlytics
4446
Crashlytics
4547
datastore
4648
deprecations
4749
Deprecations
4850
Detox
4951
DEVEX
52+
DeviceCheck
5053
Diarmid
5154
Distribution
52-
DeviceCheck
5355
dropdown
5456
e2e
5557
EEA
@@ -61,47 +63,50 @@ Fastlane
6163
FCM
6264
firebase
6365
Firebase
64-
FirebaseApp
66+
firebase-admin
6567
firebase-ios-sdk
66-
Firestore
68+
FirebaseApp
6769
firestore
68-
getIdToken
70+
Firestore
6971
GDPR
7072
GDPR-compliant
73+
getIdToken
7174
github
7275
globals
73-
Gradle
7476
gradle
77+
Gradle
7578
Hesp
7679
Homebrew
7780
HTTP
7881
HTTPS
7982
IDFA
8083
installable
8184
integrations
85+
Intellisense
8286
IntelliSense
83-
Interstitials
8487
interstitials
85-
Invertase
88+
Interstitials
8689
invertase
90+
Invertase
8791
iOS
8892
iOS13
8993
IPs
9094
isTesterSignedIn
91-
Javascript
9295
javascript
96+
Javascript
9397
JS
9498
JSON
9599
lastDocument
96100
launchProperties
97101
learnt
98102
Lerna
103+
lifecycle
99104
MDX
100-
MLKit
101105
mlkit
106+
MLKit
102107
mono-repo
103-
Multidex
104108
multidex
109+
Multidex
105110
namespace
106111
namespaced
107112
natively
@@ -119,8 +124,8 @@ OpenID
119124
perf
120125
performant
121126
personalization
122-
Podfile
123127
plist
128+
Podfile
124129
pre-fetched
125130
pre-release
126131
pre-rendered
@@ -151,14 +156,16 @@ SDKs
151156
SDKs.
152157
serverless
153158
setBackgroundMessageHandler
154-
SHA1
155159
SHA
156160
SHA-256
161+
SHA1
157162
SIGABRT
158163
signInTester
159164
Siri
160165
SMS
166+
SNS
161167
src
168+
SSV
162169
stacktrace
163170
SVG
164171
TestLab
@@ -169,30 +176,24 @@ timezones
169176
triaging
170177
TypeDoc
171178
UI
172-
UIViewController
173179
uid
180+
UIViewController
174181
uncomment
175182
unhandled
183+
UNNotificationPresentationOptions
176184
unsubscriber
177185
untampered
178186
userData
179187
utils
180188
Utils
189+
v15
181190
v5
182191
v6
183192
v9
184-
v15
185193
VPN
186194
VSCode
187195
Wix
188196
Xcode
189197
Xcode.
190-
lifecycle
191-
SNS
192-
XMPP
193198
XCS
194-
firebase-admin
195-
SSV
196-
CP-User
197-
Intellisense
198-
CDN
199+
XMPP

docs/messaging/usage/index.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,20 @@ async function registerAppWithFCM() {
386386
}
387387
```
388388

389+
## Foreground Presentation Options (iOS)
390+
391+
React Native Firebase Messaging configures how to present a notification in a foreground app.
392+
Refer to [UNNotificationPresentationOptions](https://developer.apple.com/documentation/usernotifications/unnotificationpresentationoptions) for the details.
393+
394+
```json
395+
// <projectRoot>/firebase.json
396+
{
397+
"react-native": {
398+
"messaging_ios_foreground_presentation_options": ["badge", "sound", "list", "banner"]
399+
}
400+
}
401+
```
402+
389403
## Auto initialization
390404

391405
Firebase generates an Instance ID, which FCM uses to generate a registration token and which Analytics uses for data collection.

packages/app/firebase-schema.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@
9494
"description": "Whether RNFirebase Messaging automatically calls `[[UIApplication sharedApplication] registerForRemoteNotifications];`\nautomatically on app launch (recommended) - defaults to true.\n If set to false; make sure to call `firebase.messaging().registerDeviceForRemoteMessages()`\nearly on in your app startup - otherwise you will NOT receive remote messages/notifications\nin your app.\n",
9595
"type": "boolean"
9696
},
97+
"messaging_ios_foreground_presentation_options": {
98+
"description": "On iOS, indicating how to present a notification in a foreground app.",
99+
"type": "array"
100+
},
97101
"perf_auto_collection_enabled": {
98102
"description": "Disable or enable auto collection of performance monitoring data collection.\n This is useful for opt-in-first data flows, for example when dealing with GDPR compliance.\nThis can be overridden in JavaScript.",
99103
"type": "boolean"

packages/app/ios/RNFBApp/RNFBJSON.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
- (NSString *)getStringValue:(NSString *)key defaultValue:(NSString *)defaultValue;
2727

28+
- (NSArray *)getArrayValue:(NSString *)key defaultValue:(NSArray *)defaultValue;
29+
2830
- (NSDictionary *)getAll;
2931

3032
- (NSString *)getRawJSON;

packages/app/ios/RNFBApp/RNFBJSON.m

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ - (NSString *)getStringValue:(NSString *)key defaultValue:(NSString *)defaultVal
7575
return string;
7676
}
7777

78+
- (NSArray *)getArrayValue:(NSString *)key defaultValue:(NSArray *)defaultValue {
79+
if ([_firebaseJson valueForKey:key] == nil) return defaultValue;
80+
NSArray *array = [_firebaseJson valueForKey:key];
81+
return array;
82+
}
83+
7884
- (NSDictionary *)getAll {
7985
return [[NSDictionary alloc] initWithDictionary:_firebaseJson copyItems:YES];
8086
}

packages/messaging/ios/RNFBMessaging/RNFBMessaging+UNUserNotificationCenter.m

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#import <RNFBApp/RNFBRCTEventEmitter.h>
1919

20+
#import "RNFBJSON.h"
2021
#import "RNFBMessaging+UNUserNotificationCenter.h"
2122
#import "RNFBMessagingSerializer.h"
2223

@@ -82,6 +83,50 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center
8283
willPresentNotification:(UNNotification *)notification
8384
withCompletionHandler:
8485
(void (^)(UNNotificationPresentationOptions options))completionHandler {
86+
NSArray *presentationOptionsConfig =
87+
[[RNFBJSON shared] getArrayValue:@"messaging_ios_foreground_presentation_options"
88+
defaultValue:@[]];
89+
90+
UNNotificationPresentationOptions presentationOptions = UNNotificationPresentationOptionNone;
91+
92+
BOOL badge = [presentationOptionsConfig containsObject:@"badge"];
93+
BOOL sound = [presentationOptionsConfig containsObject:@"sound"];
94+
BOOL alert = [presentationOptionsConfig containsObject:@"alert"];
95+
BOOL list = [presentationOptionsConfig containsObject:@"list"];
96+
BOOL banner = [presentationOptionsConfig containsObject:@"banner"];
97+
98+
if (badge) {
99+
presentationOptions |= UNNotificationPresentationOptionBadge;
100+
}
101+
102+
if (sound) {
103+
presentationOptions |= UNNotificationPresentationOptionSound;
104+
}
105+
106+
// if list or banner is true, ignore `alert` property
107+
if (banner || list) {
108+
if (banner) {
109+
if (@available(iOS 14, *)) {
110+
presentationOptions |= UNNotificationPresentationOptionBanner;
111+
} else {
112+
// for iOS 13 we need to set `alert`
113+
presentationOptions |= UNNotificationPresentationOptionAlert;
114+
}
115+
}
116+
117+
if (list) {
118+
if (@available(iOS 14, *)) {
119+
presentationOptions |= UNNotificationPresentationOptionList;
120+
} else {
121+
// for iOS 13 we need to set `alert`
122+
presentationOptions |= UNNotificationPresentationOptionAlert;
123+
}
124+
}
125+
} else if (alert) {
126+
// TODO: Remove `alert` once iOS 14 becomes the minimum deployment target
127+
presentationOptions |= UNNotificationPresentationOptionAlert;
128+
}
129+
85130
if (notification.request.content.userInfo[@"gcm.message_id"]) {
86131
NSDictionary *notificationDict = [RNFBMessagingSerializer notificationToDict:notification];
87132

@@ -91,17 +136,15 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center
91136
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_message_received"
92137
body:notificationDict];
93138
}
94-
95-
// TODO in a later version allow customising completion options in JS code
96-
completionHandler(UNNotificationPresentationOptionNone);
139+
completionHandler(presentationOptions);
97140
}
98141

99142
if (_originalDelegate != nil && originalDelegateRespondsTo.willPresentNotification) {
100143
[_originalDelegate userNotificationCenter:center
101144
willPresentNotification:notification
102145
withCompletionHandler:completionHandler];
103146
} else {
104-
completionHandler(UNNotificationPresentationOptionNone);
147+
completionHandler(presentationOptions);
105148
}
106149
}
107150

0 commit comments

Comments
 (0)