Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ios, messaging): Allow notifications in foreground on iOS, configure in firebase.json #6407

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 28 additions & 27 deletions .spellcheck.dict.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
64k
Ad
AdMob
Analytics
AirPods
mikehardy marked this conversation as resolved.
Show resolved Hide resolved
analytics
Analytics
ANR
APIs
APIs.
APNs
AppAttest
AppCheck
AppDelegate.m
APNs
AirPods
async
ATT
ATT-compatible
Expand All @@ -22,16 +22,17 @@ AuthSettings
autolinking
Autolinking
AVD
Axios
axios
Axios
backend
backgrounded
backoff
Barcode
barcode
Barcode
barcodes
BUGFIX
CarPlay
CDN
Changelog
checkForUpdate
CLI
Expand All @@ -40,16 +41,17 @@ codebase
config
Config
config-plugin
CP-User
crashlytics
Crashlytics
datastore
deprecations
Deprecations
Detox
DEVEX
DeviceCheck
Diarmid
Distribution
DeviceCheck
dropdown
e2e
EEA
Expand All @@ -61,47 +63,50 @@ Fastlane
FCM
firebase
Firebase
FirebaseApp
firebase-admin
firebase-ios-sdk
Firestore
FirebaseApp
firestore
getIdToken
Firestore
GDPR
GDPR-compliant
getIdToken
github
globals
Gradle
gradle
Gradle
Hesp
Homebrew
HTTP
HTTPS
IDFA
installable
integrations
Intellisense
IntelliSense
Interstitials
interstitials
Invertase
Interstitials
invertase
Invertase
iOS
iOS13
IPs
isTesterSignedIn
Javascript
javascript
Javascript
JS
JSON
lastDocument
launchProperties
learnt
Lerna
lifecycle
MDX
MLKit
mlkit
MLKit
mono-repo
Multidex
multidex
Multidex
namespace
namespaced
natively
Expand All @@ -119,8 +124,8 @@ OpenID
perf
performant
personalization
Podfile
plist
Podfile
pre-fetched
pre-release
pre-rendered
Expand Down Expand Up @@ -151,14 +156,16 @@ SDKs
SDKs.
serverless
setBackgroundMessageHandler
SHA1
SHA
SHA-256
SHA1
SIGABRT
signInTester
Siri
SMS
SNS
src
SSV
stacktrace
SVG
TestLab
Expand All @@ -169,30 +176,24 @@ timezones
triaging
TypeDoc
UI
UIViewController
uid
UIViewController
uncomment
unhandled
UNNotificationPresentationOptions
mikehardy marked this conversation as resolved.
Show resolved Hide resolved
unsubscriber
untampered
userData
utils
Utils
v15
v5
v6
v9
v15
VPN
VSCode
Wix
Xcode
Xcode.
lifecycle
SNS
XMPP
XCS
firebase-admin
SSV
CP-User
Intellisense
CDN
XMPP
14 changes: 14 additions & 0 deletions docs/messaging/usage/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,20 @@ async function registerAppWithFCM() {
}
```

## Foreground Presentation Options (iOS)

React Native Firebase Messaging configures how to present a notification in a foreground app.
Refer to [UNNotificationPresentationOptions](https://developer.apple.com/documentation/usernotifications/unnotificationpresentationoptions) for the details.

```json
// <projectRoot>/firebase.json
{
"react-native": {
"messaging_ios_foreground_presentation_options": ["badge", "sound", "list", "banner"]
}
}
```

## Auto initialization

Firebase generates an Instance ID, which FCM uses to generate a registration token and which Analytics uses for data collection.
Expand Down
4 changes: 4 additions & 0 deletions packages/app/firebase-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@
"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",
"type": "boolean"
},
"messaging_ios_foreground_presentation_options": {
"description": "On iOS, indicating how to present a notification in a foreground app.",
"type": "array"
},
"perf_auto_collection_enabled": {
"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.",
"type": "boolean"
Expand Down
2 changes: 2 additions & 0 deletions packages/app/ios/RNFBApp/RNFBJSON.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

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

- (NSArray *)getArrayValue:(NSString *)key defaultValue:(NSArray *)defaultValue;

- (NSDictionary *)getAll;

- (NSString *)getRawJSON;
Expand Down
6 changes: 6 additions & 0 deletions packages/app/ios/RNFBApp/RNFBJSON.m
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ - (NSString *)getStringValue:(NSString *)key defaultValue:(NSString *)defaultVal
return string;
}

- (NSArray *)getArrayValue:(NSString *)key defaultValue:(NSArray *)defaultValue {
if ([_firebaseJson valueForKey:key] == nil) return defaultValue;
NSArray *array = [_firebaseJson valueForKey:key];
return array;
}

- (NSDictionary *)getAll {
return [[NSDictionary alloc] initWithDictionary:_firebaseJson copyItems:YES];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#import <RNFBApp/RNFBRCTEventEmitter.h>

#import "RNFBJSON.h"
#import "RNFBMessaging+UNUserNotificationCenter.h"
#import "RNFBMessagingSerializer.h"

Expand Down Expand Up @@ -82,6 +83,50 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:
(void (^)(UNNotificationPresentationOptions options))completionHandler {
NSArray *presentationOptionsConfig =
[[RNFBJSON shared] getArrayValue:@"messaging_ios_foreground_presentation_options"
defaultValue:@[]];

UNNotificationPresentationOptions presentationOptions = UNNotificationPresentationOptionNone;

BOOL badge = [presentationOptionsConfig containsObject:@"badge"];
BOOL sound = [presentationOptionsConfig containsObject:@"sound"];
BOOL alert = [presentationOptionsConfig containsObject:@"alert"];
BOOL list = [presentationOptionsConfig containsObject:@"list"];
BOOL banner = [presentationOptionsConfig containsObject:@"banner"];

if (badge) {
presentationOptions |= UNNotificationPresentationOptionBadge;
}

if (sound) {
presentationOptions |= UNNotificationPresentationOptionSound;
}

// if list or banner is true, ignore `alert` property
if (banner || list) {
if (banner) {
if (@available(iOS 14, *)) {
presentationOptions |= UNNotificationPresentationOptionBanner;
} else {
// for iOS 13 we need to set `alert`
presentationOptions |= UNNotificationPresentationOptionAlert;
}
}

if (list) {
if (@available(iOS 14, *)) {
presentationOptions |= UNNotificationPresentationOptionList;
} else {
// for iOS 13 we need to set `alert`
presentationOptions |= UNNotificationPresentationOptionAlert;
}
}
} else if (alert) {
// TODO: Remove `alert` once iOS 14 becomes the minimum deployment target
presentationOptions |= UNNotificationPresentationOptionAlert;
}
Comment on lines +106 to +128
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same logic in notifee

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes - I was silently reading those as they went through, so I followed things as they went to the final solution, this looks good to me


if (notification.request.content.userInfo[@"gcm.message_id"]) {
NSDictionary *notificationDict = [RNFBMessagingSerializer notificationToDict:notification];

Expand All @@ -91,17 +136,15 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center
[[RNFBRCTEventEmitter shared] sendEventWithName:@"messaging_message_received"
body:notificationDict];
}

// TODO in a later version allow customising completion options in JS code
completionHandler(UNNotificationPresentationOptionNone);
completionHandler(presentationOptions);
}

if (_originalDelegate != nil && originalDelegateRespondsTo.willPresentNotification) {
[_originalDelegate userNotificationCenter:center
willPresentNotification:notification
withCompletionHandler:completionHandler];
} else {
completionHandler(UNNotificationPresentationOptionNone);
completionHandler(presentationOptions);
}
}

Expand Down