invertase / react-native-notifee

Moved to https://github.com/invertase/notifee
https://invertase.io/blog/open-sourcing-notifee
Other
466 stars 31 forks source link

[iOS] NotifeeNotificationService causing NSCocoaErrorDomain and getting invalidated #346

Closed meenie closed 3 years ago

meenie commented 3 years ago

Greetings,

Using:

@notifee/react-native@1.10.0
@react-native-firebase/app@12.3.0
@react-native-firebase/messaging@12.3.0

iOS Version: 14

FCM Url: https://fcm.googleapis.com/v1/projects/<project_id>/messages:send

When the application is in a kill state and a it receives the following publish notification from FCM

{
  android: {
    priority: 'high',
    data: {
      notifee_options: notifee_options.to_json,
    },
  },
  apns: {
    headers: {
      'apns-push-type': 'alert',
      'apns-priority': '10',
    },
    payload: {
      aps: {
        'content-available': 1,
        'mutable-content': 1,
        alert: {
          title: 'Not',
          body: 'Working',
        },
        sound: 'defaut',
      },
      notifee_options: notifee_options,
    },
  },
}

The notifee_options look like this:

{
  title: 'My Cool Alert',
  body: 'With a nifty body',
  image: 'https://placeimg.com/640/480/any',
  android: {
    channelId: 'alert',
    smallIcon: 'fireball',
    category: 'event',
    importance: 4,
    pressAction: {
      id: 'open-visitor-info',
      launchActivity: 'default',
    },
  },
  ios: {
    categoryId: 'alert',
    sound: 'default',
    attachments: [{url: 'https://placeimg.com/640/480/any'}]
  },
}

The NotifeeNotificationService does get called but the logs produce the following:

[<redacted>.NotifeeNotificationService] Service extension connection encountered an error: sessionUUID=68DBF02D-15AC-4011-952D-D2D8BC1E2922, error=Error Domain=NSCocoaErrorDomain Code=4099 "The connection on anonymousListener or serviceListener from pid 91202 was invalidated." UserInfo={NSDebugDescription=The connection on anonymousListener or serviceListener from pid 91202 was invalidated.}

And then then the next log says:

[<redacted>] Did not mutate content for notification request, will deliver original content; notificationRequest=C9DB-0669, error=Error Domain=NSCocoaErrorDomain Code=4099 "The connection on anonymousListener or serviceListener from pid 91202 was invalidated." UserInfo={NSDebugDescription=The connection on anonymousListener or serviceListener from pid 91202 was invalidated.}, runtime: 0.008673

And then it just shows the original push notification message which is Not as the title and Working as the body.

I removed the Notifee code and went back to the original default code where it adds a [modified] suffix to the notification title and that works just fine. So I'm pretty sure there is something wrong with inside Notifee. I am not an iOS developer so I'm not sure how much else I can provide without some guidance.

I'm not sure if it matters, but we are a paying customer of Notifee.

meenie commented 3 years ago

Found some more logs:

-[__NSDictionaryI setObject:forKeyedSubscript:]: unrecognized selector sent to instance 0x105014820
<NSXPCConnection: 0x1047169b0> connection to service on pid 65 created from an endpoint: Warning: Exception caught during invocation of selector didReceiveNotificationRequest:withCompletionHandler:, dropping incoming message and invalidating the connection.
Exception: -[__NSDictionaryI setObject:forKeyedSubscript:]: unrecognized selector sent to instance 0x105014820
-[__NSDictionaryI setObject:forKeyedSubscript:]: unrecognized selector sent to instance 0x105014820
(
    0   CoreFoundation                      0x000000018ee62768 4FBDF167-161A-324C-A233-D516922C67E5 + 1218408
    1   libobjc.A.dylib                     0x00000001a39297a8 objc_exception_throw + 60
    2   CoreFoundation                      0x000000018ed65c3c 4FBDF167-161A-324C-A233-D516922C67E5 + 183356
    3   CoreFoundation                      0x000000018ee652ac 4FBDF167-161A-324C-A233-D516922C67E5 + 1229484
    4   CoreFoundation                      0x000000018ee675b0 _CF_forwarding_prep_0 + 96
    5   NotifeeNotificationService          0x00000001044d3668 -[NotifeeCoreExtensionHelper populateNotificationContent:withContentHandler:] + 612
    6   NotifeeNotificationService          0x00000001044d30a8 +[NotifeeCore populateNotificationContent:withContentHandler:] + 104
    7   NotifeeNotificationService          0x00000001044cba78 +[NotifeeExtensionHelper populateNotificationContent:withContentHandler:] + 108
    8   NotifeeNotificationService          0x00000001044cb834 -[NotificationService didReceiveNotificationRequest:withContentHandler:] + 368
    9   UserNotifications                   0x000000019e3bd094 C16A26EC-816F-364C-ADF5-107D1538FF10 + 20628
    10  Foundation                          0x00000001902eb024 0D9893A4-5804-3F0D-BB3F-73989EA36AD3 + 2293796
    11  Foundation                          0x0000000190109c34 0D9893A4-5804-3F0D-BB3F-73989EA36AD3 + 322612
    12  Foundation                          0x00000001902eb148 0D9893A4-5804-3F0D-BB3F-73989EA36AD3 + 2294088
    13  libxpc.dylib                        0x00000001da9ed0bc B2470104-2400-3575-A30A-563C5D057B4A + 61628
    14  libxpc.dylib                        0x00000001da9ed480 B2470104-2400-3575-A30A-563C5D057B4A + 62592
    15  libdispatch.dylib                   0x000000018ea4f8e8 DAF30062-4C85-3B92-B159-50602A0C9D97 + 18664
    16  libdispatch.dylib                   0x000000018ea6a7ec DAF30062-4C85-3B92-B159-50602A0C9D97 + 129004
    17  libdispatch.dylib                   0x000000018ea56ecc DAF30062-4C85-3B92-B159-50602A0C9D97 + 48844
    18  libdispatch.dylib                   0x000000018ea6b550 DAF30062-4C85-3B92-B159-50602A0C9D97 + 132432
    19  libdispatch.dylib                   0x000000018ea56ecc DAF30062-4C85-3B92-B159-50602A0C9D97 + 48844
    20  libdispatch.dylib                   0x000000018ea57c34 DAF30062-4C85-3B92-B159-50602A0C9D97 + 52276
    21  libdispatch.dylib                   0x000000018ea624bc DAF30062-4C85-3B92-B159-50602A0C9D97 + 95420
    22  libsystem_pthread.dylib             0x00000001da9c67a4 _pthread_wqthread + 276
    23  libsystem_pthread.dylib             0x00000001da9cd74c start_wqthread + 8
)
meenie commented 3 years ago

Here is the code in the NotificationService.m file:

//
//  NotificationService.m
//  NotifeeNotificationService
//
//  Created by Cody Lundquist on 5/19/21.
//

#import "NotificationService.h"
#import "NotifeeExtensionHelper.h"

@interface NotificationService ()

@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;

@end

@implementation NotificationService

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];

    [NotifeeExtensionHelper populateNotificationContent:self.bestAttemptContent withContentHandler:contentHandler];
}

- (void)serviceExtensionTimeWillExpire {
    // Called just before the extension will be terminated by the system.
    // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
    self.contentHandler(self.bestAttemptContent);
}

@end
meenie commented 3 years ago

Oh man, so I figured it out. I was using attachments: [{url: 'https://placeimg.com/640/480/any'}] on the ios object and that was the thing causing errors 🤦🏻. Once I removed that property, it all started working fine. From what I saw in the documentation for this feature, it did say that that property would be ignored in favor of the image property. It looks like that property makes it blow up 😭.

meenie commented 3 years ago

I'm reopening this issue because not being able to send down the attachments property is breaking functionality. It means I can't put any images on my iOS notifications when the app is in the foreground.

Anyway around this? I think what I might do for now is in the NotificationService is just delete that property out of notifee_options if it's there before sending it to the NotifeeExtensionHelper.

helenaford commented 3 years ago

hey, thanks for the report and info. Sorry it's caused some issues for you. How are you using the attachments property in the foreground? Could you put the attachments outside of notifee_options or notifee_options.data? Not sure why it would cause this issue however, I'll look into it. Looks like we need some stronger validation around parsing attachments

meenie commented 3 years ago

Hi @helenaford,

Thanks for getting back to me :). So I'm having to send down the notifee_options in two different places as shown in the original issue body. For android I need them to be in a JSON string because FCM will not accept a JSON object for that param. And then for apns I need them to be an object so they can be passed to the NotifeeExtensionHelper to display the push notification properly. The image property doesn't exist within the Notifee Options type, as you know, but it's needed to get the NotifeeExtensionHelper to display the image for iOS. I use the same message handler for both background and foreground events. I check to see which Platform.OS has come through and for which type to specifically skip iOS on background events because the NotifeeExtensionHelper already shows the Notifee notification. The @react-native-firebase/messaging library does that 8 second delay to let the iOS app bootup React and then sends the message through to React which would cause a double message in iOS. I would love to know how to get around that without have to skip it as well :). Here's what the message handler code looks:

  async messageHandler(which: string, message: FirebaseMessagingTypes.RemoteMessage) {
    // Background notifications are already taken care of by
    // the NotifeeNotificationService within the native iOS app.
    if (which === 'background' && Platform.OS === 'ios') {
      return;
    }

    if (message.data?.notifee_options) {
      const notifeeOptions = typeof message.data.notifee_options === 'string'
        ? JSON.parse(message.data.notifee_options)
        : message.data.notifee_options;

      if (notifeeOptions.image) {
        notifeeOptions.ios.attachments = [{ url: notifeeOptions.image }];
        notifeeOptions.android.largeIcon = notifeeOptions.image;
      }

      notifee.displayNotification(notifeeOptions);
    }
  }

Let me know if you need any other info!

helenaford commented 3 years ago

Thanks. Interesting to see how you've used the notifeeOptions payload and I can see how that makes sense. I guess for that, the ideal fix would be to allow attachments to work on notifeeOptions in the NotifeeExtensionHelper. I'll mark this as under review and will report back to you on what we can do.

meenie commented 3 years ago

Thank you!

meenie commented 3 years ago

Another bug I just ran across is if you pass null to image, it will crash the NotifeeExtensionHelper as well. I'm now just passing an empty string when I don't have an image to display, but just thought you should know.

mikehardy commented 3 years ago

Oh my! Thank you for reporting that

helenaford commented 3 years ago

@meenie please find the fix in the latest release v1.11.0 where you can pass in attachments and it will also handle null values. See docs for more information.