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

expo-notifications FCM V1 Migration Tracking Issue #28656

Open
christopherwalter opened this issue May 7, 2024 · 189 comments
Open

expo-notifications FCM V1 Migration Tracking Issue #28656

christopherwalter opened this issue May 7, 2024 · 189 comments
Assignees

Comments

@christopherwalter
Copy link
Contributor

christopherwalter commented May 7, 2024

This is a tracking issue for user-reported issues related to the Spring 2024 migration of Expo Push Notifications from FCM Legacy to FCM V1 for Android devices. There have been reported instances of brokenness in production when moving from FCM Legacy to FCM V1, and this issue will serve as a central place to track our investigation and resolution of these issues.

The known issues are as follows:

Here is a table showing the overall state of these issues, as of 6/11. Package versions are expo@51.0.11 and expo-notifications@0.28.8:

App State Sound Banner Icon Data Badge Count
Foreground In Progress
Background In Progress
Killed In Progress

New issues filed in expo/expo will be merged into this tracking issue for easier management. The deadline for migrating to FCM V1 is June 20.

@fdelu
Copy link

fdelu commented May 7, 2024

Something else I noticed that might be worth noting is that notification images (not icons) don't seem to be working when the app is in the foreground.

Edit: Just to clarify, I tested this by sending the request to the FCM V1 api directly

@haplionheart
Copy link

To add on to "the notification icon is not working", on Android I'm finding that the icon displays when the app is in the foreground. But I get a blank circle as an icon when the app is in the background

This is happening with a development build

@jnoleau
Copy link

jnoleau commented May 8, 2024

No issue with the icon when we add the correct name/value pair on the Android manifest but it seems there is no "plugin" on the package expo-notification or this one is not working as expected.

But this issue can be fixed "simply" by adding a manual plugin specified here #24844 (comment) in addition to the config.notification.icon in the app.config

@zandvakiliramin
Copy link

Hi,
I am facing the same issue,
I am using expo-server-sdk: 3.10.0 to send notifications. When I change the useFcmV1 to true on Android, my app does not get the data from the notification, and the icon shows a blue circle with thick borders. When I set it to false, everything works. On iOS, everything works fine.

I am using Expo SDK 49.

@krazykriskomar
Copy link

#24844 (comment)

For me, the plugin here is unnecessary because the AndroidManifest that's created seems fine. I have 2 notification_icon additions.
<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notification_icon"/>
and
<meta-data android:name="expo.modules.notifications.default_notification_icon" android:resource="@drawable/notification_icon"/>
I also see mapping files declaring the png and naming it to the correct asset name.
I am on expo 51.0.2 and expo-notifications 0.28.1 (both latest).
On prebuild, the png file is processed and correctly placed into all the xdpi drawable asset out put folders.
I've also triple checked with our UX designer that the requirements are met: it's a white-only transparent PNG at 72 dpi at 96x96 pixels exactly.
Hopefully this info helps someone. I think there's been a mismatch of actual problems going on between expo 49, 50, and 51, because the manifest is now correct and I no longer need the withFirebaseMessagingNotificationIcon plugin.

@NickTillinghastKrazy
Copy link

Something else I noticed that might be worth noting is that notification images (not icons) don't seem to be working when the app is in the foreground.

Edit: Just to clarify, I tested this by sending the request to the FCM V1 api directly

I have the same issue on IOS.

@douglowder
Copy link
Contributor

PR #28883 has been submitted to fix the Android notification response issues when app is in background or not running.

@briazzi64
Copy link

PR #28883 has been submitted to fix the Android notification response issues when app is in background or not running.

Awesome. thank you so much for tracking this down for all of us. Any idea when it will be available?

@krazykriskomar
Copy link

PR #28883 has been submitted to fix the Android notification response issues when app is in background or not running.

Awesome. thank you so much for tracking this down for all of us. Any idea when it will be available?

Second that! Really need it :)

@krazykriskomar
Copy link

0.28.2 didn't fix anything :(

@fdelu
Copy link

fdelu commented May 16, 2024

In my case I can confirm that with the new version, useLastNotificationResponse now does get notifications received when the app is in the background (sent with FCM v1)
However in that same scenario I'm not getting the full request payload, the data is missing. Trying to debug if it's something I can change on my end to fix it

@douglowder
Copy link
Contributor

@fdelu see the fix that was just added in #28883 , specifically the new method in NotificationSerializer.java, toResponseBundleFromExtras():

https://github.com/expo/expo/pull/28883/files#diff-385373049872662646fd4faf3b47aea7c97480a25b6de9a96259bef1e856d790

That is the method that takes the bundle passed into onNewIntent() when the notification is opened while the app is in the background, and constructs the notification response object.

If you are missing part of the payload, you should have a look to see if there are parts of the bundle that are not being mapped by NotificationSerializer.java. The payload is being logged to logcat in ExpoNotificationsLifecycleListener.java:

https://github.com/expo/expo/pull/28883/files#diff-f558167185b0f06ac4e093b7f22c59f01ca8096f127a1605245962f0927ed7e1

@douglowder
Copy link
Contributor

@fdelu in looking at this further, it may be that you rebuilt your Android app with the new expo-notifications package, but did not rebuild your JS bundle to pick up the required changes on the JS side: https://github.com/expo/expo/pull/28883/files#diff-37b24aeb2e0d5d7c4365c987c51f03db4b6d20a0927f3eefe0d9e0a35b2c4df7

The data is passed as a string from Android native to the JS code, and is unpacked there, so if you did not rebuild your bundle with the new library, the data would indeed be missing.

@fdelu
Copy link

fdelu commented May 16, 2024

@fdelu in looking at this further, it may be that you rebuilt your Android app with the new expo-notifications package, but did not rebuild your JS bundle to pick up the required changes on the JS side: https://github.com/expo/expo/pull/28883/files#diff-37b24aeb2e0d5d7c4365c987c51f03db4b6d20a0927f3eefe0d9e0a35b2c4df7

The data is passed as a string from Android native to the JS code, and is unpacked there, so if you did not rebuild your bundle with the new library, the data would indeed be missing.

Yes, that seems like it. I noticed later that I had "dataString" but not "data" so I'm probably missing that. Not sure how that happened though. Thanks for your help!

@deivijt
Copy link

deivijt commented May 16, 2024

After updating to expo-notifications@0.28.2 and building, this works 🎉. Thanks, @douglowder. Great work! 👏

... the only minor issue is that the notification icon is not displaying correctly with FCM V1.

@douglowder
Copy link
Contributor

Fix for #28883 has been published. Pick up latest expo package (51.0.7) and do npx expo install --fix to pick up expo-notifications 0.28.2. You will also get a new version of expo-dev-client that fixes an unnecessary reload issue on Android (see #28893).

@fdelu
Copy link

fdelu commented May 16, 2024

@fdelu in looking at this further, it may be that you rebuilt your Android app with the new expo-notifications package, but did not rebuild your JS bundle to pick up the required changes on the JS side: https://github.com/expo/expo/pull/28883/files#diff-37b24aeb2e0d5d7c4365c987c51f03db4b6d20a0927f3eefe0d9e0a35b2c4df7
The data is passed as a string from Android native to the JS code, and is unpacked there, so if you did not rebuild your bundle with the new library, the data would indeed be missing.

Yes, that seems like it. I noticed later that I had "dataString" but not "data" so I'm probably missing that. Not sure how that happened though. Thanks for your help!

An update on this @douglowder: I verified and it is using the latest version.

When my app is in the foreground, I get a notificationd and click on it, I see the "response received" log and everything works fine. However, when my app is closed (fully), I get a notification and click on it to open the app, then I don't see that "response received" log, the "data" field is missing and the request content contains the "dataString" field.

Looking at the code for useLastNotificationResponse, I believe this happens because in the first scenario, the notification comes from the response received listener, which does parse the "dataString" (that's the change from the link you sent me). In the second scenario though, the notification seems to be coming from getLastNotificationResponseAsync which does not parse the "dataString".

Another issue I've been having is that if I get a notification when the app is open, I fully close it and then I reopen the app by clicking the notification, useLastNotificationResponse returns an almost empty notification. My code:

  const notification = useLastNotificationResponse();

  console.log("LAST RESPONSE", notification);
  console.log(
    "LAST RESPONSE CONTENT",
    notification?.notification?.request?.content
  );
  console.log(
    "LAST RESPONSE TRIGGER",
    notification?.notification?.request?.trigger
  );

The logs:

 LOG  response received: {
  "notification": {
    "request": {
      "trigger": {
        "channelId": null,
        "type": "push"
      },
      "content": {
        "title": null,
        "dataString": null,
        "body": null
      },
      "identifier": null
    },
    "date": 0
  },
  "actionIdentifier": "expo.modules.notifications.actions.DEFAULT"
}
 LOG  LAST RESPONSE {"actionIdentifier": "expo.modules.notifications.actions.DEFAULT", "notification": {"date": 0, "request": {"content": [Object], "identifier": null, "trigger": [Object]}}}
 LOG  LAST RESPONSE CONTENT {"body": null, "dataString": null, "title": null}
 LOG  LAST RESPONSE TRIGGER {"channelId": null, "type": "push"}

@douglowder
Copy link
Contributor

@fdelu yes indeed that is a bug! I think cutting and pasting the new code from NotificationEmitter should fix it... I really appreciate you taking the time to track that down.

@christopherwalter
Copy link
Contributor Author

Hi folks, if you're in this thread due to icon-related issues (@deivijt @zandvakiliramin @haplionheart):

Can you try using a config plugin like in this comment to ensure the correct fields are in your manifest? And let me know if that changes anything?

@krazykriskomar re: your comment here, I wasn't sure if you have it working or not? Can you confirm if icon behavior is correct for you when sending notifs using FCM V1?

@douglowder
Copy link
Contributor

@appsgenie you should definitely move to SDK 51. We do plan to backport the FCMv1 fixes to SDK 50, but not 49.

@appsgenie
Copy link

@appsgenie you should definitely move to SDK 51. We do plan to backport the FCMv1 fixes to SDK 50, but not 49.

got it. thank you. and the existing clients will just work like it does now with useFcmV1=true? where the notification comes but with the few known issues (no banner, no icon, no data..)?

@mgscreativa
Copy link

Hi! @douglowder, will let @ctwillie (developer of one of the PHP SDKs available here https://github.com/ctwillie/expo-server-sdk-php) know that it might be some changes in the payload to expo notifications API.

I also point that the expo tool and the expo notifications API differs in the API endpoint. Docs: https://exp.host/--/api/v2/push/send Expo tool: https://api.expo.dev/v2/push/send

And if you can, please let @christopherwalter know that is needed to clarify the use of contentAvailable undocumented payload param for IOS, that at least is a little bit confusing, because some developers say you must send "contentAvailable": 1, another says "_contentAvailable": 1 and in the docs here says "content-available": 1. Reference https://github.com/expo/expo/tree/main/packages/expo-notifications#handling-incoming-notifications-when-the-app-is-not-in-the-foreground-not-supported-in-expo-go

@mgscreativa
Copy link

mgscreativa commented Jun 11, 2024

@nakedgun can you please tell me if you can capture the payload sent through node SDK to the notifications API, so I can compare it with mine and the PHP SDK, thanks a lot!

@mgscreativa
Copy link

@nakedgun just created a test project to use the node SDK expo-server-sdk@3.9.0 with this simple payload and updated my notifications test project with expo-notifications 0.28.8 (without patches) and the app in first background doesn't gets the notification processed at all.

messages.push({
    to: pushToken,
    title: '\ud83d\udcf1 Test Background',
    body: 'Test for app in Background state',
    data: {
        msgId: '0db795c654e9e79cfdd751e633ff9416',
        link: 'https:\/\/www.google.com.ar\/',
    },
    sound: 'default',
})

The code for implementing the node SDK is the very same that available in the project readme like this:


import { Expo } from 'expo-server-sdk';

// Create a new Expo SDK client
// optionally providing an access token if you have enabled push security
let expo = new Expo({
    accessToken: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    useFcmV1: true // this can be set to true in order to use the FCM v1 API
});

// Create the messages that you want to send to clients
let messages = [];

// Each push token looks like ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]
const pushToken = 'ExponentPushToken[XXXXXXXXXXXXXXXXXXXXXX]';

// Check that all your push tokens appear to be valid Expo push tokens
if (!Expo.isExpoPushToken(pushToken)) {
    console.error(`Push token ${pushToken} is not a valid Expo push token`);
    process.exit(1);
}

// Construct a message (see https://docs.expo.io/push-notifications/sending-notifications/)
messages.push({
    to: pushToken,
    title: '\ud83d\udcf1 Test Background',
    body: 'Test for app in Background state',
    data: {
        msgId: '0db795c654e9e79cfdd751e633ff9416',
        link: 'https:\/\/www.google.com.ar\/',
    },
    sound: 'default',
})

// The Expo push notification service accepts batches of notifications so
// that you don't need to send 1000 requests to send 1000 notifications. We
// recommend you batch your notifications to reduce the number of requests
// and to compress them (notifications with similar content will get
// compressed).
let chunks = expo.chunkPushNotifications(messages);
let tickets = [];
(async () => {
    // Send the chunks to the Expo push notification service. There are
    // different strategies you could use. A simple one is to send one chunk at a
    // time, which nicely spreads the load out over time:
    for (let chunk of chunks) {
        try {
            let ticketChunk = await expo.sendPushNotificationsAsync(chunk);
            console.log(`Got ticketChunk ${ticketChunk}`);
            tickets.push(...ticketChunk);
            // NOTE: If a ticket contains an error code in ticket.details.error, you
            // must handle it appropriately. The error codes are listed in the Expo
            // documentation:
            // https://docs.expo.io/push-notifications/sending-notifications/#individual-errors
        } catch (error) {
            console.error(error);
        }
    }
})();

// Later, after the Expo push notification service has delivered the
// notifications to Apple or Google (usually quickly, but allow the service
// up to 30 minutes when under load), a "receipt" for each notification is
// created. The receipts will be available for at least a day; stale receipts
// are deleted.
//
// The ID of each receipt is sent back in the response "ticket" for each
// notification. In summary, sending a notification produces a ticket, which
// contains a receipt ID you later use to get the receipt.
//
// The receipts may contain error codes to which you must respond. In
// particular, Apple or Google may block apps that continue to send
// notifications to devices that have blocked notifications or have uninstalled
// your app. Expo does not control this policy and sends back the feedback from
// Apple and Google so you can handle it appropriately.
let receiptIds = [];
for (let ticket of tickets) {
    // NOTE: Not all tickets have IDs; for example, tickets for notifications
    // that could not be enqueued will have error information and no receipt ID.
    if (ticket.status === 'ok') {
        receiptIds.push(ticket.id);
    }
}

let receiptIdChunks = expo.chunkPushNotificationReceiptIds(receiptIds);
(async () => {
    // Like sending notifications, there are different strategies you could use
    // to retrieve batches of receipts from the Expo service.
    for (let chunk of receiptIdChunks) {
        try {
            let receipts = await expo.getPushNotificationReceiptsAsync(chunk);
            console.log(receipts);

            // The receipts specify whether Apple or Google successfully received the
            // notification and information about an error, if one occurred.
            for (let receiptId in receipts) {
                let { status, message, details } = receipts[receiptId];
                if (status === 'ok') {
                    continue;
                } else if (status === 'error') {
                    console.error(
                        `There was an error sending a notification: ${message}`
                    );
                    if (details && details.error) {
                        // The error codes are listed in the Expo documentation:
                        // https://docs.expo.io/push-notifications/sending-notifications/#individual-errors
                        // You must handle the errors appropriately.
                        console.error(`The error code is ${details.error}`);
                    }
                }
            }
        } catch (error) {
            console.error(error);
        }
    }
})();

@jludwiggreenaction
Copy link
Contributor

jludwiggreenaction commented Jun 11, 2024

you should definitely move to SDK 51. We do plan to backport the FCMv1 fixes to SDK 50, but not 49.

@douglowder Would you be able to confirm if the fixes are expected to be on SDK50 before the deadline at this point? Since we also have to account for a little bit of app store review time, I'm trying to figure out the safest option to ensure android notifications can keep working (upgrade to 51 vs wait for backport).

I see you mention upgrading to 51, but I have some concerns about that since it is still in beta phase.

Thanks for your continued effort in investigating this issue.

@mgscreativa
Copy link

@jludwiggreenaction I think SDK 51 is in production at the moment

@jludwiggreenaction
Copy link
Contributor

@jludwiggreenaction I think SDK 51 is in production at the moment

Oh yea you're right. Guess I'm living under a rock. Rest of my question still stands though 🤦

@Codelica
Copy link

Also @Codelica, sounds like your plan is to do latest SDK and latest expo-notifications before next Thursday? What's your plan with existing clients?

@appsgenie our plan is to do what we can. :) Basically our current production app is on Expo v49 and we're currently sending out alerts via the "legacy" API (useFcmV1: false) which works for us in all states on iOS and Android (via workaround) currently.

So our plan is to fast-track a new v51 build so users can update before we are forced to move to useFcmV1: true next Thursday -- which will require these updates for Android to continue to work properly. We do normal OTA updates, but also have our own check on startup that verifies the user is on the latest "build" version in the store. If they aren't running the latest, then there is a popup with an option to update (linked to our app in the store) or ignore. So they will all be notified at least.

Our situation does make it a little easier also, as our app is basically a business-line alerting app that's coupled to our main server products (facial rec/LPR, id verification, loss prevention, etc). So most of our users are security teams, which we can notify and will likely update in bulk during a morning meeting, etc -- assuming we can get it in the store quickly of course. 😅

@nakedgun
Copy link

nakedgun commented Jun 11, 2024

@mgscreativa the nodejs code looks fine - I'm afraid I don't have time at the moment for capturing requests (it's not super trivial for https connections coming from docker containers). I would try adding the onNotificationResponseFromExtras patch and see if it fixes it - then report back. I would also check you're receiving other types of notifications and there are no errors when processing the push notification tickets. If you do hit issues, the best way to troubleshoot them is to attach a debugger to a physical device in Android Studio and start adding breakpoints, providing you're confident there's no issues with the server component sending out the notifications.

@appsgenie If it helps, our rollout strategy is similar to @Codelica . Existing clients are on SDK49 with fcmv1=false (forced on the server). We will roll out (SDK51 + expo-notifications 0.28 + my onNotificationResponseFromExtras patch) in the next few days. Since that update is backwards compatible with fcmv1=false (providing you use expo-notifications 0.28.8), old + new builds (in theory) will continue to work fine until June 20th, which is when fcm legacy is turned off by Google.

That said, come June 19th, like @Codelica , we will force this as an update for Android users (we also have a custom update mechanism which enforces minimum versions for iOS/Android). That way, come June 20th, all Android users will be on the build which supports the fcmv1 API.

@mgscreativa
Copy link

@nakedgun will crate a patch for the function onNotificationResponseFromExtras only

@christopherwalter
Copy link
Contributor Author

Hi all,

I've updated this issue description with the latest status on issues tracked throughout these comments. Here's the current status as of expo@51.0.11 and expo-notifications@0.28.8, please upgrade your packages if you haven't done so already. Let me know if there are any discrepancies :)

The known issues are as follows:

Here is a table showing the overall state of these issues, as of 6/11. Package versions are expo@51.0.11 and expo-notifications@0.28.8:

App State Sound Banner Icon Data Badge Count
Foreground In Progress
Background In Progress
Killed In Progress

douglowder added a commit that referenced this issue Jun 11, 2024
… app in background or killed (#29659)

# Why

The logic in `onNotificationResponseFromExtras` needs to be adjusted to
correctly check whether response listeners are active, and do that check
first before falling back to add the response to the pending responses
(eventually used by `useLastNotificationResponse()` in JS).

See #28656 (comment)

# How

Inverted the order of checks in the method.

# Test Plan

- CI should pass
- Test the flows with the test app, using both expo-server-sdk tool and
expo.dev/notifications web tool

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
This is required for changes to Expo modules.
-->

- [ ] Documentation is up to date to reflect these changes (eg:
https://docs.expo.dev and README.md).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
@mgscreativa
Copy link

mgscreativa commented Jun 11, 2024

@christopherwalter notifications@0.28.8 fails to handle notifications in first background of the app, but as stated by @nakedgun and tested by me this PR fixes it #29659

EDIT: patch to be applied in expo-notificatoins@0.28.8

diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/NotificationManager.java b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/NotificationManager.java
index 384a78b..172bc91 100644
--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/NotificationManager.java
+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/NotificationManager.java
@@ -127,15 +127,26 @@
   }

   public void onNotificationResponseFromExtras(Bundle extras) {
-    if (mPendingNotificationResponsesFromExtras.isEmpty()) {
-      mPendingNotificationResponsesFromExtras.add(extras);
-    } else {
+    // We're going to be passed in extras from either
+    // a killed state (ExpoNotificationLifecycleListener::onCreate)
+    // OR a background state (ExpoNotificationLifecycleListener::onNewIntent)
+
+    // If we've just come from a background state, we'll have listeners set up
+    // pass on the notification to them
+    if (!mListenerReferenceMap.isEmpty()) {
       for (WeakReference<NotificationListener> listenerReference : mListenerReferenceMap.values()) {
         NotificationListener listener = listenerReference.get();
         if (listener != null) {
           listener.onNotificationResponseIntentReceived(extras);
         }
       }
+    } else {
+      // Otherwise, the app has been launched from a killed state, and our listeners
+      // haven't yet been setup. We'll add this to a list of pending notifications
+      // for them to process once they've been initialized.
+      if (mPendingNotificationResponsesFromExtras.isEmpty()) {
+        mPendingNotificationResponsesFromExtras.add(extras);
+      }
     }
   }
 }

@appsgenie
Copy link

Thank you so much for sharing your thoughts @Codelica and @nakedgun 🙏
For me, all users are "public" and I feel like that's a bit harder to get them updated :) but I'll try.

Is the latest version of expo-notifications package even ready? or the outstanding issues here in this ticket are still being ironed out? I feel like some edge cases are still present (sorry wasn't able to follow all of it). Maybe I can just wait for that first 🤔

@Codelica you mentioned OTA update, but with this kinda change (new SDKs + packages) that won't be an option right?

@nakedgun, what happens to old builds after June 20th? Like is it correct to say that starting June 20th, the notifications will act the same way as if I would do fcmv1=true today? for existing clients with an older Expo SDK...

@nakedgun
Copy link

nakedgun commented Jun 11, 2024

@appsgenie come June 20th (when the legacy API is depreciated), yes, it's effectively the same as fcmv1=true. With this, older Android builds without fcmv1 support will start hitting bugs related to the fcmv1 update. An OTA update won't fix this as the changes are in native code. That's why come June 19th we are forcing the update upon users via a custom update flow - gross, but necessary for our use-case :)

In terms of expo-notifications being ready - yes and no. This PR has not yet been merged in but is recommended to fix the first background notification not being received on Android (in some cases - depending on what server SDK you are using). You can however apply this patch manually using patch package. expo-notifications+0.28.8.patch

diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/NotificationManager.java b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/NotificationManager.java
index 384a78b..172bc91 100644
--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/NotificationManager.java
+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/NotificationManager.java
@@ -127,15 +127,26 @@
   }

   public void onNotificationResponseFromExtras(Bundle extras) {
-    if (mPendingNotificationResponsesFromExtras.isEmpty()) {
-      mPendingNotificationResponsesFromExtras.add(extras);
-    } else {
+    // We're going to be passed in extras from either
+    // a killed state (ExpoNotificationLifecycleListener::onCreate)
+    // OR a background state (ExpoNotificationLifecycleListener::onNewIntent)
+
+    // If we've just come from a background state, we'll have listeners set up
+    // pass on the notification to them
+    if (!mListenerReferenceMap.isEmpty()) {
       for (WeakReference<NotificationListener> listenerReference : mListenerReferenceMap.values()) {
         NotificationListener listener = listenerReference.get();
         if (listener != null) {
           listener.onNotificationResponseIntentReceived(extras);
         }
       }
+    } else {
+      // Otherwise, the app has been launched from a killed state, and our listeners
+      // haven't yet been setup. We'll add this to a list of pending notifications
+      // for them to process once they've been initialized.
+      if (mPendingNotificationResponsesFromExtras.isEmpty()) {
+        mPendingNotificationResponsesFromExtras.add(extras);
+      }
     }
   }
 }

Also note case: #29622.

@Codelica
Copy link

@appsgenie, @nakedgun's post covers things well. But once Expo's push API must use the new API next week it's not that older Android builds won't receive notifications (go silent) -- technically they will go out via the new API and be delivered. However, unpatched/older Android builds will have several issues in trying to handle them, like:

  • Missing data in the messages
  • Missing icons/colors (if you use them)
  • Missing notification banners with app in the background or killed state
  • Other issues with background notifications depending on what Expo server SDK you use for delivery.
  • Etc..

So it is sort of messy.

@nakedgun
Copy link

@appsgenie, @nakedgun's post covers things well. But once Expo's push API must use the new API next week it's not that older Android builds won't receive notifications (go silent) -- technically they will go out via the new API and be delivered. However, unpatched/older Android builds will have several issues in trying to handle them, like:

* Missing data in the messages

* Missing icons/colors (if you use them)

* Missing notification banners with app in the background or killed state

* Other issues with background notifications depending on what Expo server SDK you use for delivery.

* Etc..

So it is sort of messy.

Word. Basically an invitation for 1-star reviews, unless handled somewhat gracefully in advance :) Thanks for clarifing that side of things @Codelica .

douglowder added a commit that referenced this issue Jun 11, 2024
… app in background or killed (#29659)

# Why

The logic in `onNotificationResponseFromExtras` needs to be adjusted to
correctly check whether response listeners are active, and do that check
first before falling back to add the response to the pending responses
(eventually used by `useLastNotificationResponse()` in JS).

See #28656 (comment)

# How

Inverted the order of checks in the method.

# Test Plan

- CI should pass
- Test the flows with the test app, using both expo-server-sdk tool and
expo.dev/notifications web tool

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
This is required for changes to Expo modules.
-->

- [ ] Documentation is up to date to reflect these changes (eg:
https://docs.expo.dev and README.md).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
@appsgenie
Copy link

Thanks @Codelica for confirming that it will still "work" but with terrible experience like @nakedgun said :) at least iOS I hope will work fine...

I am just debating maybe it's ok for it to work badly like this for a few extra days while the the expo-notifications package has all the outstanding PRs merged.. This way I'd start implementing SDK 51 now and include latest expo-notifications at the end once it's ready. But not too sure how long that will take 🤔

@codercoder292
Copy link

codercoder292 commented Jun 12, 2024

There is an issue after updating to the latest version.

When using useFcmV1=true in the Master App for push notifications:
- In terminated or background state, the top alert does not appear, but the push notification is received.
- In terminated state, when the push notification is touched, the link data is missing. (data)

Resolved Issues:
    - Icon is displayed correctly.
    - Link data is available in the background state.
  • only android
  • sdk 51
  • expo-notifications 0.28.8

marklawlor pushed a commit that referenced this issue Jun 12, 2024
… app in background or killed (#29659)

# Why

The logic in `onNotificationResponseFromExtras` needs to be adjusted to
correctly check whether response listeners are active, and do that check
first before falling back to add the response to the pending responses
(eventually used by `useLastNotificationResponse()` in JS).

See #28656 (comment)

# How

Inverted the order of checks in the method.

# Test Plan

- CI should pass
- Test the flows with the test app, using both expo-server-sdk tool and
expo.dev/notifications web tool

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
This is required for changes to Expo modules.
-->

- [ ] Documentation is up to date to reflect these changes (eg:
https://docs.expo.dev and README.md).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
@mgscreativa
Copy link

@codercoder292, please check out my demo repo which applies the last patch needed for this to work https://github.com/mgscreativa/expo-notifications-test

@mgscreativa
Copy link

Just tested expo-notifications@0.28.9 and it works just fine. Updated test repo here https://github.com/mgscreativa/expo-notifications-test

useFcmV1=true

App State Sound Banner Icon Data
Foreground
Background
Killed

douglowder added a commit that referenced this issue Jun 12, 2024
…e legacy icon and color (#29491)

Based on customer feedback from `expo-notifications@0.28.7`, three
adjustments are still needed:

- Set both FCM legacy and FCMv1 metadata items in the Android manifest,
so that icon and color work in both cases
- Add a config plugin property, `defaultChannel`, to allow a developer
to set the FCMv1 default channel in the manifest.
- The Android lifecycle listeners should check to see if the intent
extras have a `notificationResponse` object, and not map the intent
bundle to create a duplicate response in JS.

See [this
comment](#28656 (comment))
by @mgscreativa and other comments in that issue.

- Make the appropriate code changes in the plugin and in
`ExpoNotificationLifecycleListener.java`

- CI should pass
- Test app patched with these changes should behave as expected

<!--
Please check the appropriate items below if they apply to your diff.
This is required for changes to Expo modules.
-->

- [ ] Documentation is up to date to reflect these changes (eg:
https://docs.expo.dev and README.md).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
douglowder added a commit that referenced this issue Jun 12, 2024
… app in background or killed (#29659)

The logic in `onNotificationResponseFromExtras` needs to be adjusted to
correctly check whether response listeners are active, and do that check
first before falling back to add the response to the pending responses
(eventually used by `useLastNotificationResponse()` in JS).

See #28656 (comment)

Inverted the order of checks in the method.

- CI should pass
- Test the flows with the test app, using both expo-server-sdk tool and
expo.dev/notifications web tool

<!--
Please check the appropriate items below if they apply to your diff.
This is required for changes to Expo modules.
-->

- [ ] Documentation is up to date to reflect these changes (eg:
https://docs.expo.dev and README.md).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
@NoZiL
Copy link

NoZiL commented Jun 12, 2024

There is an issue after updating to the latest version.

When using useFcmV1=true in the Master App for push notifications: - In terminated or background state, the top alert does not appear, but the push notification is received. - In terminated state, when the push notification is touched, the link data is missing. (data)

Resolved Issues:
    - Icon is displayed correctly.
    - Link data is available in the background state.
  • only android
  • sdk 51
  • expo-notifications 0.28.8

I am facing the same issue migrating to fcm v1, I found out that the notification that I get from getLastNotificationResponseAsync when app is killed has unparsed "dataString" instead of "data". After going up the thread, I found that the issue was already discussed.
I did not found out yet why the parse did not occurred.

If you want to quickfix it, you can do something like:

const url =notification.request.content.data?.url ?? JSON.parse((notification.request.content as any).dataString)?.url;

@Codelica
Copy link

@codercoder292 and @NoZiL are you doing a fresh build after updating to expo-notifications 0.28.8? The symptoms described (like banner not appearing, missing/unparsed data) all required native code fixes.

A few suggestions:

  • Use the latest expo-notifications which is currently 0.28.9
  • For configuration (in app.json / app.config.js) for the notifications plugin, include defaultChannel set to whatever channelId you use, and any icon/color info. For example:
[
  "expo-notifications",
    {
      "icon": "./assets/images/android-notification.png",
      "color": "#D84F4F",
      "defaultChannel": "default"
    }
]
  • Consider using the useLastNotificationResponse() hook to handle notifications, as I know that's what several of us who have been testing are using successfully across all Android app states.
  • Make sure you do a fresh build, as expo-notifications has updated native code that's needed.

@mgscreativa
Copy link

expo-notifications is at v0.28.9 at the moment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests