expo / expo

An open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.
https://docs.expo.dev
MIT License
32.91k stars 5.24k forks source link

[expo-notifications] notifications arrive to different channel by default with FCM V1 #31502

Open basti4557 opened 4 days ago

basti4557 commented 4 days ago

Minimal reproducible example

https://github.com/basti4557/expo-notification-channel-bug

What platform(s) does this occur on?

Android

Where did you reproduce the issue?

in a standalone app

Summary

The TL;DR (written by vonovak): with fcmv1, when channelId is sent in the notification request to Expo push service, the channelId is correctly received by the device. This is the correct and expected behavior.

The issue reported here is that prior to using FCMv1, if channel id was not specified, notifications were delivered to default channel. This behavior has changed.


Previously with FCM legacy, all messages in expo-notifications were routed through the "default" notification channel, ensuring consistent behavior for notifications, whether the app was in the background or foreground. The channelId was unset in my request to the expo servers before and got filled by your server with "default".

However, with the introduction of FCM V1, this behavior has changed. The system now automatically creates channels like "fcm_fallback_notification_channel" and "expo_notifications_fallback_notification_channel." They both have different channel configurations, one of them is also silent.

In the documentation, I noticed the new configuration option "defaultChannel". Wouldn't it be more intuitive for this to default to the "default" channel?

The channelId parameter in the expo api was default before when not channelId value was sent, and at the moment it dont behaves like before. When i sent the "channelId" parameter with my request to expo all notifications get routed again to the channel "default", which was the expected behaviour before.

Without sending channelId to expo servers: Screenshot_20240916-173408~2

Environment

expo-env-info 1.2.0 environment info: System: OS: macOS 14.6.1 Shell: 5.9 - /bin/zsh Binaries: Node: 20.16.0 - ~/.nvm/versions/node/v20.16.0/bin/node npm: 10.8.1 - ~/.nvm/versions/node/v20.16.0/bin/npm IDEs: Android Studio: 2024.1 AI-241.18034.62.2411.12169540 Xcode: /undefined - /usr/bin/xcodebuild npmPackages: expo: ~51.0.28 => 51.0.32 react: 18.2.0 => 18.2.0 react-native: 0.74.5 => 0.74.5 npmGlobalPackages: eas-cli: 12.3.0 Expo Workflow: managed

Expo Doctor Diagnostics

✔ Check Expo config for common issues ✔ Check package.json for common issues ✔ Check native tooling versions ✔ Check if the project meets version requirements for submission to app stores ✔ Check dependencies for packages that should not be installed directly ✔ Check for common project setup issues ✔ Check for app config fields that may not be synced in a non-CNG project ✔ Check npm/ yarn versions ✔ Check for issues with metro config ✔ Check for legacy global CLI installed locally ✔ Check that native modules do not use incompatible support packages ✔ Check Expo config (app.json/ app.config.js) schema ✔ Check that native modules use compatible support package versions for installed Expo SDK ✔ Check that packages match versions required by installed Expo SDK

Didn't find any issues with the project!

basti4557 commented 4 days ago

Some snippet of my BE server. Payload before (with channels glitching arround) ` $channel = 'user_' . $receiversUserId;

    $this->expoApi->subscribe($channel, $deviceToken);

    $notification = [
        'title' => $title,
        'body' => $message,
        'data' => [
            'title' => $title,
            'body' => $message,
            'answerUserId' => strval($answerUserId),
            'layout' => $layout
        ],
    ];

    if (strlen($layout) > 0) {
        $notification['categoryId'] = $layout;
    }

    try {
        $this->expoApi->notify([$channel], $notification);
        return true;
    } catch (UnexpectedResponseException $e) {
        return false;
    }`

Payload after changes, which results in channel "default" gets triggered again all times like before: ` $channel = 'user_' . $receiversUserId;

    $this->expoApi->subscribe($channel, $deviceToken);

    $notification = [
        'title' => $title,
        'body' => $message,
        'data' => [
            'title' => $title,
            'body' => $message,
            'answerUserId' => strval($answerUserId),
            'layout' => $layout
        ],
        'channelId' => 'default',
    ];

    if (strlen($layout) > 0) {
        $notification['categoryId'] = $layout;
    }

    try {
        $this->expoApi->notify([$channel], $notification);
        return true;
    } catch (UnexpectedResponseException $e) {
        return false;
    }`

I just added explicitly the parameter "channelId" to the payload, which was not necessary before.

vonovak commented 4 days ago

@basti4557 thank you for providing a reproduction. If I understand correctly, you're NOT explicitly sending a channel id in the notification request, correct?

Thank you

basti4557 commented 4 days ago

@basti4557 thank you for providing a reproduction. If I understand correctly, you're NOT explicitly sending a channel id in the notification request, correct?

Thank you

That is correct. After adding it to my backend server explicitly the behaviour is like before (= correct).

vonovak commented 4 days ago

After adding it to my backend server explicitly the behaviour is like before.

"like before" means that the channel id seems to be ignored? Getting to the core question: what is the behavior that you see and what do you instead expect to see? (why?)

Thank you

basti4557 commented 4 days ago

Before If No Channel was sent to the Expo Servers the notification got presented in the "Default" Channel, in all App states.

Now the notification gets presented in "fcm_fallback_notification_channel" or "expo_notifications_fallback_notification_channel", If No channel ist sent to the Expo Servers.

I expect that no channel always will be handled AS the "Default" Channel, Like it did 2-3 weeks before.

So: If Key "channelId" ist empty/Not exists, send notification to "Default" channel

DB1703 commented 3 days ago

Do you get a different behaviour when testing through Expo Go app? In my case, is working normally but i don´t know why in production it changes the payload, and i still couldn´t find wich part of the payload is

vonovak commented 3 days ago

hello, my advice is to not use Expo Go for notifications - as we explain in several places in the documentation, Expo Go is intended for experimenting and it cannot accurately work in some scenarios. Notifications is one of them. I recommend you use a development build. Read more in https://expo.dev/blog/expo-go-vs-development-builds