notifee: Android: onBackgroundEvent not fired when quick action is pressed

I’ve a notification with two actions (accept call/ reject call).

 android: {
        channelId: callChannelId,
        category: AndroidCategory.CALL,
        circularLargeIcon: true,

        color: AndroidColor.BLUE,

        // Recommended to set importance to high

        importance: AndroidImportance.HIGH,
        ongoing: true,
        fullScreenAction: {
          id: 'incoming-call',
        },
        largeIcon: largeIcon,

        // smallIcon: 'name-of-a-small-icon', // optional, defaults to 'ic_launcher'.

        actions: [
          {
            title: 'Reject',
            pressAction: { id: NOTIFICATION_ACTIONS_ID.cancelIncomingCall },
          },
          {
            title: 'Accept',
            pressAction: { id: NOTIFICATION_ACTIONS_ID.acceptIncomingCall, launchActivity: 'default' },
          },
        ],
        badgeCount: 1,
        timeoutAfter: ONE_MINUTE,
        autoCancel: false,
      },

handleOnForegroundEvent works fine.
And now I’m trying to add handleOnForegroundEvent: The notification get displayed in killed state and handleOnForegroundEvent fired once then when I pressed I can’t get wich action get pressed because onBackgroundEvent not fired when I pressed.

notifee.onBackgroundEvent(async ({ type, detail }) => {

  const { notification, pressAction } = detail;
    

    if (type === EventType.ACTION_PRESS) {
      if (pressAction.id === NOTIFICATION_ACTIONS_ID.acceptIncomingCall || type === EventType.PRESS) {
        // accept call
        incomingCallNotifications.handleAcceptCall(notification);
      } else {
        incomingCallNotifications.handleRejectCall(notification);
      }

      return;
    }
});

Package.json

"@notifee/react-native": "^5.0.3",
"react-native": "0.67.4",

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 8
  • Comments: 67 (30 by maintainers)

Most upvoted comments

Massive thanks to @mieszko4 for fixing this issue! Released in 7.2.0

Has anybody made any progress with onBackgroundEvent for Android >= 12? I am trying to understand the issue but not quite sure where to start.

Hello, we can’t downgrade targetSdk to 30, because Play Store is not accepting it. What other workarounds do we have?

Please note that I am a React developer and have little experience with Android development, so this question may be fundamentally wrong.

I believe the most common way to start an Activity is startActivity(). However, due to Android 12’s notification trampoline limitations, apps can no longer call startActivity() within a service or broadcast receiver. https://developer.android.com/about/versions/12/behavior-changes-12#notification-trampolines

In notifee/core/ReceiverService.java, in the launchPendingIntentActivity method, create an Intent for starting an Activity, wrap it in a PendingIntent and send it with the send method. In other words, StartActivity does not appear to be used.

Apps can no longer call startActivity() within a service or broadcast receiver.

Does the restriction here for Android 12 and later also apply to PendingIntent.send?

Was the following PR modification necessary? https://github.com/invertase/notifee/pull/301

I am using 5.7.0version and it works fine on Android 12 without this PR modification.

Please note that the English may not be appropriate due to the use of translation software.

Just wanted to share my findings.

On Android 5 appProcess.importance is never IMPORTANCE_FOREGROUND in background state hence isAppInForeground returns false. And on frontend state isAppInForeground always throws hence it returns true. On Android 12 appProcess.importance is IMPORTANCE_FOREGROUND after push is tapped hence it throws and returns true. I am not sure why it returns IMPORTANCE_FOREGROUND in case only push is visible - looks like ActivityManager.RunningAppProcessInfo is not reliable to be used here.

My point is the current implementation of isAppInForeground will always throw when condition in the loop is satisfied because it casts to ReactContext, wheres it should cast to ReactApplication like it is done in getReactContext. So that seems like a bug that did not have a chance to be noticed 😃

This patch fixes that bug. However, it now makes Android 12 show taps as headless when app is opened because reactContext.getLifecycleState() is BEFORE_RESUME when push is visible:

diff --git a/packages/react-native/android/src/main/java/io/invertase/notifee/NotifeeReactUtils.java b/packages/react-native/android/src/main/java/io/invertase/notifee/NotifeeReactUtils.java
index b60e6d4..805447c 100644
--- a/packages/react-native/android/src/main/java/io/invertase/notifee/NotifeeReactUtils.java
+++ b/packages/react-native/android/src/main/java/io/invertase/notifee/NotifeeReactUtils.java
@@ -210,12 +210,9 @@ class NotifeeReactUtils {
     for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
       if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
           && appProcess.processName.equals(packageName)) {
-        ReactContext reactContext;
-
-        try {
-          reactContext = (ReactContext) context;
-        } catch (ClassCastException exception) {
-          return true;
+        ReactContext reactContext = getReactContext();
+        if (reactContext == null) {
+          return false;
         }
 
         return reactContext.getLifecycleState() == LifecycleState.RESUMED;

If I find some time I will check if this is an issue with current stable versions.

+1 Downgrading targetSDK solves it, but Playstore requires new apps to be built with SDK 31 so this is not a solution for us 😕 And indeed onBackgroundEvent only has an issue with “ACTION_PRESS” events, so for now we just won’t be able to use that feature 😢

@mikehardy my logcat output seems pretty similar to @fabyeah 's above. Do you mind sharing if there’s any plans to address this issue?

Not offensive - no worries - just wanted to make sure expectations were aligned.

I maintain react-native repositories on contract and have a startup that’s taking off right now, I write code for money, though I do enjoy it. I never have enough time in the day though, and don’t personally have time for this one right now

@mieszko4 I can confirm, I just tested

try {
  reactContext = (ReactContext) context;
} catch (ClassCastException exception) {
  return false; // <== forced to false
}

Returning false in the ClassCastException on "@notifee/react-native": "7.1.0" on Android 12 and 13 is working correctly, the onBackgroundEvent gets correctly fired when I tap on the press action ACTION_PRESS

Unfortunately this is not a solution, but posting it here just to confirm it.

Really appreciated your research 👍🏽

@ZaidQ797 very interesting result, thanks for testing some combinations and reporting back

In attempt to reduce this to only current version, and one simple difference, is this correct?

test case:

1- set a listener for onBackgroundEvent prior to registering app in AppRegistry 2- post a notification somehow 3- tap the notification

1- on android, with v7.0.1 here, and targetSdkVersion 33, onBackgroundEvent does not call the listener 2- on android, with v7.0.1 here, and targetSdkVersion 30, onBackgroundEvent does call the listener

The point here is to reduce this to declarative unambiguous statements with (hopefully) only a single thing to vary for a clean reproduction and then someone that has this as an important use case (that justifies their time looking into it) has a really low barrier to get started and inspect what actually changes with that targetSdkVersion variation

+1

When app is killed, onBackgroundEvent is never called on press action (Android 11 & 12).

Downgrading targetSDK to 30 “solves” the problem for me (RN 0.68.2)

I think this problem should be considered as critical by the Notifee Team

With apologies - just to set expectations, considering it critical or not does not magically make more hours appear in the day. It’s an open source project, and all reasonable PRs will be merged + released.

If this is something that affects your business, it may be worth it for you to prioritize development resources to investigate + fix

At the same time, open source is amazing - you’ve got all the source and if you’ve got some solution that works for you, use it! https://github.com/ds300/patch-package is something I use frequently myself.

Though I typically use it only temporarily while I’m already on current stable versions and I’m working a PR through the upstream package…

My case: "@notifee/react-native": "5.7.0",, "react-native": "0.64.4",, Android 12, targetSdkVersion = 31

App is in QUIT state. I create a push with action after getting high priority remote data push. onBackgroundEvent is triggered when push is delivered (EventType=DELIVERED, headless=true). onForegroundEvent is triggered when push action is tapped (EventType=ACTION_PRESS, headless=undefined) BUT ONLY if I register onForegroundEvent directly in index.js

Since AppRegistry.registerComponent registers a component that does not run in headless mode, it looks like event actually comes in headless mode but is wrongly interpreted as foreground.

Obviously registering onForegroundEvent directly in index.js is not correct since I cannot clean up listeners. Android 5 correctly uses onBackgroundEvent.

I can reproduce this on iOS too.

notifee.onBackgroundEvent(async (event) => {
  console.log('I can see this log');
  if (event.type === EventType.PRESS) {
       console.log('I cannot see this log');
  }
});
"react-native": "0.68.2",
"@notifee/react-native": "5.4.1"

Hi @fabyeah, unfortunately it’s not working. I end up downgrading my my targetSdkVersion from 31 to 30 This is what I have now :

build.gradle

ext {
        buildToolsVersion = "30.0.2"
        minSdkVersion = 21
        compileSdkVersion = 31
        targetSdkVersion = 30
        ndkVersion = "21.4.7075529"
    }

gradle version


distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip

package.json

"@notifee/react-native": "^5.2.2",
"react-native": "0.67.4",

index.js

/**
 * @format
 */

import messaging from '@react-native-firebase/messaging';
import { AppRegistry } from 'react-native';
import App from './App';
import { name as appName } from './app.json';
import firebaseNotificationHandler from './app/utils/firebaseNotificationHandler';
// firebase
messaging().onMessage(firebaseNotificationHandler.onMessageReceived);
messaging().setBackgroundMessageHandler(firebaseNotificationHandler.onMessageReceived);
// notifee, same function as OnForegroundEvent
notifee.onBackgroundEvent(async (props) => firebaseNotificationHandler.handleOnForegroundEvent(props));
AppRegistry.registerComponent(appName, () => App);

functions:

 // on foreground notification pressed;

  handleOnForegroundEvent({ type, detail: { notification, pressAction } }: any) {
    const notificationData = JSON.parse(notification.data.notification);
    if (type === EventType.ACTION_PRESS && pressAction?.id === NOTIFICATION_ACTIONS_ID.acceptIncomingCall) {
      return incomingCallNotifications.handleAcceptCall(notificationData);
    }
    if (type === EventType.ACTION_PRESS && pressAction?.id === NOTIFICATION_ACTIONS_ID.cancelIncomingCall) {
      return incomingCallNotifications.handleRejectCall(notificationData);
    }
    if (type !== EventType.PRESS) {
      return Promise.resolve();
    }
    return firebaseNotificationHandler.handleInitialNotification(notificationData);
  },
  
   async handleRejectCall(notification: IIcomingCallNotification) {
    const { conversationId, notificationId } = notification;
    const accessToken = await load('accessToken');

    axios
      .get(..............)
    if (notificationId) {
      await notifee.cancelNotification(notificationId);
    }
  }
  
    async makeIncomingCallNotification(title: string, body: string, user: any, notification?: any) {
    const callChannelId = await notifee.createChannel(INCOMING_CHANNEL_OPTIONS);
    const notificationId = generateId();
    const largeIcon = getNotificationLargeIconByUser(user);

    if (isIOS) {
      await getIosCategory();
    }

    await notifee.displayNotification({
      title: title,
      body: body,
      id: notificationId,
      android: {
        channelId: callChannelId,
        category: AndroidCategory.CALL,
        circularLargeIcon: true,

        color: AndroidColor.BLUE,

        // Recommended to set importance to high

        importance: AndroidImportance.HIGH,
        ongoing: true,

        largeIcon: largeIcon,

        // smallIcon: 'name-of-a-small-icon', // optional, defaults to 'ic_launcher'.
        pressAction: {
          id: NOTIFICATION_ACTIONS_ID.acceptIncomingCall,
        },
        actions: [
          {
            title: '<span style="color: #FF0000;">Réfuser</span>',
            pressAction: { id: NOTIFICATION_ACTIONS_ID.cancelIncomingCall },
          },
          {
            title: '<span style="color: #00FF00;">Accepter</span>',
            pressAction: { id: NOTIFICATION_ACTIONS_ID.acceptIncomingCall },
          },
        ],
        badgeCount: 1,
        timeoutAfter: ONE_MINUTE,
        autoCancel: false,
      },
      ios: {
        categoryId: 'incoming-call',
        attachments: [
          {
            // iOS resource

            url: largeIcon,
            thumbnailHidden: true,
          },
        ],
        foregroundPresentationOptions: {
          alert: true,
          sound: true,
        },

        critical: true,
      },
      data: {
        notification: JSON.stringify({ ...notification, notificationId }),
      },
    });
  },

@hussainimp indeed, it is almost undoubtedly this commit https://github.com/invertase/notifee/commit/ed22c8ff35ec1c69dc1015709920e50d835f3c57 - just not sure exactly what yet - we can use all the help we can get with regard to isolating the specific issue and ideally 🙏 🙏 seeing a PR from someone affected - I can collaborate with anyone to get a fix released but this is not a personal use case of mine so it’s not personally urgent and I won’t have time to personally fix it at the moment, it will end up on the general work pile and might sit otherwise

If I find some time I will check if this is an issue with current stable versions.

I started fresh (https://reactnative.dev/docs/environment-setup) using react-native": "0.70.6, keeping newArchEnabled=false and with compileSdkVersion = 33 and installing latest @notifee/react-native@7.1.0 with basic snippet from https://notifee.app/react-native/docs/displaying-a-notification:

function Screen() {
  async function onDisplayNotification() {
    // Request permissions (required for iOS)
    await notifee.requestPermission()

    // Create a channel (required for Android)
    const channelId = await notifee.createChannel({
      id: 'default',
      name: 'Default Channel',
    });

    // Display a notification
    await notifee.displayNotification({
      title: 'Notification Title',
      body: 'Main body content of the notification',
      android: {
        channelId,
        //smallIcon: 'name-of-a-small-icon', // optional, defaults to 'ic_launcher'.
        // pressAction is needed if you want the notification to open the app when pressed
        pressAction: {
          id: 'default',
        },
      },
    });
  }

  return (
    <View>
      <Button title="Display Notification" onPress={() => onDisplayNotification()} />
    </View>
  );
}

And I added Log.e("ERROR", "", exception); in catch of isAppInForeground defined in react-native/android/src/main/java/io/invertase/notifee/NotifeeReactUtils.java Finally I rebuild the app using yarn android.

On Android 12, after tapping on Display Notification I get ERROR msg. After tapping on the push I also get ERROR msg.

I cannot see the point of this try/catch if it always throws and makes isAppInForeground to return true 😃

@mikehardy thank you again for your guidance and support. https://github.com/ds300/patch-package This is definitely what I’m looking for.

A suggestion: everyone upgrade to current stable versions of software then try reproducing? That’s a best practice, ends up saving more time then the apparent “possibly wasted time” of updating to current stable, in my experience

@venux92 Which version of react-native do you use?

🤔 I wonder if that’s related to incompatibility of react-native and targetSDKVersion=31. In v0.68.0 targetSDKVersion was changed to 31. So maybe upgrading react-native to 0.68.0 will fix this…

I’m using react native 0.68.4 and targetSDK 33 and it’s not fixed.

@venux92 Which version of react-native do you use?

🤔 I wonder if that’s related to incompatibility of react-native and targetSDKVersion=31. In v0.68.0 targetSDKVersion was changed to 31. So maybe upgrading react-native to 0.68.0 will fix this…

Looks like isAppInForeground returns true when it should return false, i.e. after hardcoding return false in isAppInForeground I receive the event ACTION_PRESS in onBackgroundEvent as expected.

It is returning true because of ClassCastException exception. Not sure if that’s expected logic or an actual exception which should never happen.

java.lang.ClassCastException: [...].MainApplication cannot be cast to com.facebook.react.bridge.ReactContext

I’m already setting a listener for onBackgroundEvent prior to registering app in AppRegistry So I tested with Notifee versions 7.0.0 & 7.0.1 but these two versions only works with compileSdkVersion 33 and my targetSDKVersion is 31.I had issue with ios notifications and these two newer versions solved as soon as I upgraded from 5.6.0.Now on android onBackgroundEvent is only being called with following scenarios;

  • When Android App is in foreground onBackgroundEvent being called for type Delivered and Press
  • When Android App is in background onBackgroundEvent is being called with Type 3 Delivered and If Notification Pressed then onBackgroundEvent being called with Type 1 Press
  • When Android App is in quit state and onBackgroundEvent is only called once with Type 3 Delivered.But When Notification Pressed onBackgroundEvent is not being called with Type 1 Press

I have a same problem I tested notifee versions 5.6.0,7.0.0,7.0.1 with api targetSDK version 31 and complieSDK 33 and 31 but **OnBackgroundEvent** didn’t fired OnPress.If I downgrade the targetSDK to 30 it works but thing is we Can’t upload app to play store with 30

@mikehardy The error in Logcat when the app is terminated is this:

Indirect notification activity start (trampoline) from [app-id] blocked

So seems to be the same as #250 where the proposed fix is to downgrade from targetSdkVersion = 31 to targetSdkVersion = 30. I was indeed on 31, because react-native-bootsplash says to set it: https://github.com/zoontek/react-native-bootsplash#android-1

I downgraded and pressing notifications works now. 👍 (and the boot screen still shows)

That’s great though! Really tight range of commits!

Only 3

1- https://github.com/invertase/notifee/commit/50aa11e9788c256a65bcbe4364e782a3ae95bc51 - going to say it’s not that, it’s only a model change, and java specific

2- https://github.com/invertase/notifee/commit/f5da72227339574897f37717e4609937025b6887 - maybe this one? But it is java only, and you did not differentiate on the failure, you indicated it was android and ios? Not sure how this could affect iOS as well

3- https://github.com/invertase/notifee/commit/ed22c8ff35ec1c69dc1015709920e50d835f3c57 - massive change, but is also java only

If the result of 4.0.1 working and 4.1.0 not working is to be believed, I’m confused how it could manifest on iOS. Can you confirm that this happens on both android and ios? If it is on both then there is something really subtle going on and will need some thinking. If it’s actually android only then we pick apart the specific commits and find it

🤔 hmm - what’s the execution environment here? I don’t see that specified (android vs ios)

Our releases are usually pretty small so even though the range is large, the actual number of functional (non-test, non-docs) commits is pretty small:

https://github.com/invertase/notifee/compare/%40notifee/react-native%404.0.1...%40notifee/react-native%405.2.1

Total release count is 8 so if you attempted to bisect which release starts to fail it would probably take just 3 attempts before you located the precise commit and we’d have the bug on the dissection table 🔬

Hi, it sounds like there’s an issue with onBackgroundEvent rather than action_press, where in your project have you put onBackgroundEvent? We have an example app that might help, you can pull it down and run it