알림 뱃지를 수정하던 중 버그를 발견하였다. ios는 백그라운드 상태에서 알림 배너는 나타나지만 data 페이로드를 수신하지 못하였다.
깃 이슈를 찾아보니 나와 같은 문제가 많았는데, 대부분의 사람들이 페이로드만 수정하여 해결되었고.. 나는 content_available만 추가하는 것으로는 해결되지 않았다.
페이로드
기존에는 fcm 알림 전송 페이로드에서 data, notification을 모두 전송해주었는데, FCM 메시지 정보에 따르면, 알림과 데이터 페이로드가 모두 포함된 메시지를 수신한 경우의 앱 동작은 앱이 백그라운드 상태인지 아니면 포그라운드 상태인지에 따라 다르다고 한다. (공식 문서를 자세히 읽자👿)
- 백그라운드 상태: 알림 페이로드가 앱의 알림 목록에 수신되며 사용자가 알림을 탭한 경우에만 앱에서 데이터 페이로드를 처리
- 포그라운드 상태: 앱에서 페이로드가 둘 다 제공되는 메시지 객체를 수신
이것 때문에 백그라운드 상태에서 배너가 나타나고, 알림을 탭하면 앱이 실행되면서 foreground event가 찍히는 것이었다.
=> notification을 삭제하고 content_available true를 전달해주었다.
$notification = array(
'title'=>$sender,
'body'=>$message,
'badge'=>0,
'sound'=>'default',
);
$data = array(
'title'=>$sender,
'message'=>$message,
'body'=>$message,
'chat_id'=>$chat_id,
'topic_id'=>$topic_id,
'sound'=>'default',
);
$params = array(
// 'notification'=>$notification, => 삭제
'priority'=>'high',
'data'=>$data,
'to'=>$token,
'content_available'=>true // 추가 (메시지 수신 시 데이터 처리를 위한 앱 실행을 위해)
);
#import "AppDelegate.h"
#import <Firebase.h>
#import <React/RCTBundleURLProvider.h>
#import "RNSplashScreen.h"
#import <React/RCTLinkingManager.h>
#import <UserNotifications/UserNotifications.h>
// Implement UNUserNotificationCengerDelegate to receive display notification via APNS for devices
// running iOS 10 and above.
@interface AppDelegate () <UNUserNotificationCenterDelegate>
@end
@implementation AppDelegate
NSString *const kGCMMessageIdKey = @"gcm.message_id";
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
return [RCTLinkingManager application:application openURL:url options:options];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[FIRApp configure];
[FIRMessaging messaging].delegate = self;
self.moduleName = @"messenger";
// You can add your custom initial props in the dictionary below.
// They will be passed down to the ViewController used by React Native.
self.initialProps = @{};
// Define UNUserNotificationCenter
// UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
// center.delegate = self;
[application registerForRemoteNotifications];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
// return YES;
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
// If you are receivingh a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Anlytics
// [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
NSLog(@"didReceiveRemoteNotification userInfo ======================");
if (userInfo[kGCMMessageIdKey]) {
NSLog(@"Message ID: %@", userInfo[kGCMMessageIdKey]);
}
NSLog(@"%@", userInfo);
}
// Required for the notification event. You must call the completion handler after handling the remote notification.
// - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
// fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
// {
// // If you are receiving a notification message while your app is in the background,
// // this callback will not be fired till the user taps on the notification launching the application.
// // TODO: Handle data of notification
// // With swizzling disabled you must let Messaging know about the message, for Analytics
// // [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
// NSLog(@"didReceiveRemoteNotification fetchCompleteHandler ==========");
// if (userInfo[kGCMMessageIdKey]) {
// NSLog(@"Message ID: %@", userInfo[kGCMMessageIdKey]);
// }
// NSLog(@"%@", userInfo);
// // Change this to your preferred presentation option
// completionHandler(UIBackgroundFetchResultNewData);
// }
// Receive displayed notifications for iOS 10 devices.
// Handle incoming notification messages while app is in the foreground.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
{
NSLog(@"WillPresentNotification =============================");
NSDictionary *userInfo = notification.request.content.userInfo;
// With swizzling disabled you must let Messaging know about the message, for Analytics
// [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
if (userInfo[kGCMMessageIdKey]) {
NSLog(@"Message ID: %@", userInfo[kGCMMessageIdKey]);
}
NSLog(@"%@", userInfo);
// Chagne this to your preferred presentation option
completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound);
}
// Handle notification message after display notification is tapped by the user.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler
{
NSDictionary *userInfo = response.notification.request.content.userInfo;
if (userInfo[kGCMMessageIdKey]) {
NSLog(@"Message ID: %@", userInfo[kGCMMessageIdKey]);
}
// With swizzling eisabled you must let Messaging know about the message, for Analytics
// [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
NSLog(@"%@", userInfo);
completionHandler();
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
NSLog(@"Unable to register for remote notifications: %@", error);
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
@end
#import <RCTAppDelegate.h>
#import <UIKit/UIKit.h>
#import <UserNotifications/UNUserNotificationCenter.h>
#import <Firebase/Firebase.h>
@interface AppDelegate : RCTAppDelegate <UNUserNotificationCenterDelegate, FIRMessagingDelegate>
@end
target 'messenger' do
...
#pod 'Firebase/Core' => 삭제
...
end
Info.plist
<key>FirebaseMessagingAutoInitEnabled</key>
<false/>
ios/<프로젝트명>/<프로젝트명>.entitlements
<key>aps-environment</key>
<string>production</string><!-- <string>development</string> -->
> LOG setBackgroundMessageHandler=========
> LOG {"contentAvailable": true, "data": {"body": "안녕?", "chat_id": "", "message": "안녕?", "sound": "default", "title": "TEST", "topic_id": "_"}, "from": "", "messageId": ""}