invertase / notifee

⚛️ A feature rich notifications library for React Native.
https://notifee.app
Apache License 2.0
1.82k stars 215 forks source link

PRESS event is not detected in onBackgroundEvent #1105

Open tamirla opened 1 week ago

tamirla commented 1 week ago

I'm using notifee to send local notification from inside the app and want to be able to detect that user pressed on notification.

I thought I will be able to check for PRESS event type inside onBackgroundEvent, however I noticed that onBackgroundEvent is triggered only once with DELIVERED event type, then the app is opened, and only then I can detect PRESS event type inside onForegroundEvent that is triggered once the app is opened.

my questions are -

I found the following "hint" that implies I should use onForegroundEvent but I didn't really understand why...

I'm using only notifee without Firebase, most examples & issues I saw involve also Firebase.

In iOS I at least get both onBackgroundEvent & onForegroundEvent triggered, in Android I'm seeing only onBackgroundEvent triggered once with DELIVERED and don't see onForegroundEvent triggered at all.

I thought this could be related to this issue, however I'm using RN < 0.73:

"react-native": "0.72.10" "@notifee/react-native": "^7.8.2",

Just to clarify - I want to detect when user pressed on notification itself, I don't have any buttons on the notification.

vkukade-altir commented 1 week ago

Same issue for me. "react-native": "0.72.4", "@notifee/react-native": "9.0.0", Android version : 14 (API level 34)

On android, notifee's onBackgroundEvent and even getInitialNotification doesn't fire if user click on notification. I have already added following in index.js file.

messaging().setBackgroundMessageHandler(async remoteMessage => { console.log('Message handled in the background!', remoteMessage); });

I even tried what he says in this comment. https://github.com/invertase/notifee/issues/616#issuecomment-1380264271 But still not working for Android.

My use case is: that I want to support both local and remote push notifications.

What I have tried:

If I use the standalone package https://github.com/wix/react-native-notifications only for remote push notifications -> This works fine in all cases for Android and IOS. But this doesn't support android local notifications.

If I use Notifee package version 5.7.0 and use Firebase functions (getInitialNotification, onNotificationOpenedApp) this also works good for remote notifications and local notifications. But here still notification tap doesn't work

If I try to use notifee version 9.0.0 above mentioned issue occurs.

Eclipses-Saros commented 1 week ago

this is what I wanted to find why: android events are not working as expected. I didn't find the reason yet, but I can share some information you might help.

const apiModule = new NotifeeApiModule_1.default({
    version: version_1.version,
    nativeModuleName: 'NotifeeApiModule',
    nativeEvents: utils_1.isIOS
        ? [utils_1.kReactNativeNotifeeNotificationEvent, utils_1.kReactNativeNotifeeNotificationBackgroundEvent]
        : [utils_1.kReactNativeNotifeeNotificationEvent],
});

first, notifee registers nativeEvents to receive events. remember the event name: kReactNativeNotifeeNotificationEvent.

export const kReactNativeNotifeeNotificationEvent = 'app.notifee.notification-event';

second, initialize module based on NotifeeApiModule.java (create method to connect native module). you can find some platform specific workaround.

class NotifeeApiModule extends NotifeeNativeModule_1.default {
    constructor(config) {
        super(config);
        if (utils_1.isAndroid) {
            // Register background handler
            react_native_1.AppRegistry.registerHeadlessTask(utils_1.kReactNativeNotifeeNotificationEvent, () => {
                return (event) => {
                    if (!backgroundEventHandler) {
                        console.warn('[notifee] no background event handler has been set. Set a handler via the "onBackgroundEvent" method.');
                        return Promise.resolve();
                    }
                    return backgroundEventHandler(event);
                };
            });
        }
        else if (utils_1.isIOS) {
            this.emitter.addListener(utils_1.kReactNativeNotifeeNotificationBackgroundEvent, (event) => {
                if (!backgroundEventHandler) {
                    console.warn('[notifee] no background event handler has been set. Set a handler via the "onBackgroundEvent" method.');
                    return Promise.resolve();
                }
                return backgroundEventHandler(event);
            });
        }
    }
    ...
    onForegroundEvent = (observer) => {
        if (!(0, utils_1.isFunction)(observer)) {
            throw new Error("notifee.onForegroundEvent(*) 'observer' expected a function.");
        }
        const subscriber = this.emitter.addListener(utils_1.kReactNativeNotifeeNotificationEvent, 
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore See https://github.com/facebook/react-native/pull/36462
        ({ type, detail }) => {
            observer({ type, detail });
        });
        return () => {
            subscriber.remove();
        };
    };
    ...

as you can see, Android event listener uses same key, kReactNativeNotifeeNotificationEvent. the only difference is, foreground is using emitter.addListener, while background is AppRegistry.registerHeadlessTask.

public void onNotificationEvent(NotificationEvent notificationEvent) {
    ....
    if (isAppInForeground()) {
      eventMap.putBoolean(KEY_HEADLESS, false);
      NotifeeReactUtils.sendEvent(NOTIFICATION_EVENT_KEY, eventMap);
    } else {
      eventMap.putBoolean(KEY_HEADLESS, true);
      NotifeeReactUtils.startHeadlessTask(NOTIFICATION_EVENT_KEY, eventMap, 60000, null);
    }
    ....
}

onNotificationEvent called when you have some notification events, such as delivered, press. and check app is foreground or not, module send event with sendEvent or startHeadlessTask.

to sum up, Android uses same event key, and native module calls different function whether foreground or not. that's the how logic works. let's back to the question what you've asked:

Is this the expected behaviour ?

yes, and no. (as far as I've researched)

the only point checking foreground status is there. isAppInForeground() function. and what that means, if the function returns true, it always works as foreground. in reverse, yes background as well. you expected pressing notification from background should be call background event, but it's not. isAppInForeground() says you're in foreground, so onForegroundEvent called.

expected: (pressing notification from background) -> detected as background and calls startHeadlessTask -> show events at onBackgroundEvent -> app shows up reality: (pressing notification from background) -> app shows up -> detected as foreground and calls sendEvent -> show events at onForegroundEvent

shouldn't onBackgroundEvent be able to use also to detect PRESS event ?

I also remember that feature, when I was using 5.7.0 before. but years later... it just disappeared! (well, I can merely guess there are tons of things changed after Android 12 (and 13, 14!), notifee has no option but following up these changes.)

Is it possible that onBackgroundEvent will be triggered multiple times, first with DELIVERED, then with PRESS? If not, how else it can detect PRESS if it was already triggered with DELIVERED ?

If you can fix logic, yes. there is no data difference between foreground and background.

Android I'm seeing only onBackgroundEvent triggered once with DELIVERED and don't see onForegroundEvent triggered at all.

if "triggered at all" means no events shows up, you need to check reactContext. I've said bug can occur RN >0.73, but there are no guarantee not to happened when you avoid it.