wix / react-native-notifications

React Native Notifications
MIT License
3.23k stars 761 forks source link

[ANDROID] Notifications.getInitialNotification() no data when app is in kill state #906

Open viktor-CCM opened 1 year ago

viktor-CCM commented 1 year ago

Notifications.getInitialNotification() return undefined when the application is in a kill state. If the application is foreground and the user tap on the notification - Notifications.events().registerNotificationOpened works properly.

const registerNotificationOpened = async () => {
    Notifications.events().registerNotificationOpened((notification) => {
      console.log('Notification opened by device user', notification.payload);
    });

    const initialNotification = await Notifications.getInitialNotification();
  };

Case 1 (Android) Dead state (100% dead) Click on the notification message App will open Notifications.getInitialNotification() return undefined

In iOS it works properly.


"react-native-notifications": "^4.3.1", "react-native": "^0.69.6",


// Android Manifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="...........">

<uses-permission android:name="android.permission.INTERNET" />
<permission
        android:name="${applicationId}.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

<application
  android:name=".MainApplication"
  android:label="@string/app_name"
  android:icon="@mipmap/ic_launcher"
  android:roundIcon="@mipmap/ic_launcher_round"
  android:allowBackup="false"
  android:theme="@style/BootTheme">
    <meta-data
            android:name="com.google.firebase.messaging.default_notification_icon"
            android:resource="@drawable/notification_icon" />
    <!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
                notification message. See README(https://goo.gl/6BKBk7) for more. -->
    <meta-data
            android:name="com.google.firebase.messaging.default_notification_color"
            android:resource="@color/primary" />
  <activity
    android:name=".MainActivity"
    android:label="@string/app_name"
    android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
    android:launchMode="singleTask"
    android:windowSoftInputMode="adjustPan"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
  </activity>
</application>


Google service package

dependencies {
    classpath("com.android.tools.build:gradle:7.1.1")
    classpath("com.facebook.react:react-native-gradle-plugin")
    classpath("de.undercouch:gradle-download-task:5.0.1")
    classpath 'com.google.gms:google-services:4.3.10'
    classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2'
}

// Test devices OnePlus 9R android 12 Pixel 4 API 30 (simulator)

victorious85 commented 1 year ago

I faced the same issue

Lapaenergy commented 1 year ago

I have this problem too

viktor-CCM commented 1 year ago

I created a new project from template RN(npx react-native init AwesomeProject). I used the guide from the documentation for the integration Android part.

I sent the following HTTP POST request to https://fcm.googleapis.com/fcm/send (via Postman). I got the push notification. But if app killed Notifications.getInitialNotification() return undefined.

dmitrykurochka commented 1 year ago

I have the same problem. Could someone help with it?

viktor-CCM commented 1 year ago

@DanielEliraz I saw your first fix in PR. I checked it locally. It doesn't work.

nschild commented 1 year ago

I am seeing this same issue but also noticed that the initial props on my does carry android_notification_info. I am going to try tapping into that.

EDIT: Here is my working proof of concept

#push-notification-helper.ts

... {include all the stuff from the docs} 

export const loadInitialNotification = (initialNotification?: Notification) => {
    Notifications.getInitialNotification().then(async (notification = initialNotification) => {
        console.log(`getInitialNotification opened:`, notification);

        if (notification)
            onNotification(notification, AnalyticsLabel.Cold);
        else {
            store.dispatch(generalActionSetInitialNavigationState(undefined));
        }

        Notifications.events().registerNotificationOpened((notification2, completion) => {
            console.log(`Notification opened: `, notification2);
            onNotification(notification2, AnalyticsLabel.Warm);
            completion();
        });
    });
};
#App.tsx

export default class App extends Component {
  constructor(props: AppProps) {
    super(props);

    const notification = Platform.OS === 'android' && !!props.android_notification_info && ({
      identifier: props.android_notification_info.google?.message_id,
      payload: {data: props.android_notification_info},
      title: props.android_notification_info.title,
      body: props.android_notification_info.body,
      sound: '',
      badge: 1,
      type: '',
      thread: '',
    }) as Notification || undefined;

    loadInitialNotification(notification);
  }

  ...

}
DanielEliraz commented 1 year ago

@viktor-CCM do you expect that getInitialNotification will return the notification only when the application is in a kill state, while registerNotificationOpened will be triggered only when the application is in a background state?

viktor-CCM commented 1 year ago

@viktor-CCM do you expect that getInitialNotification will return the notification only when the application is in a kill state, while registerNotificationOpened will be triggered only when the application is in a background state?

@DanielEliraz Yes.

DanielEliraz commented 1 year ago

I think I found a way to trigger the registerNotificationOpened also in kill state. do you think it's an advantage or you prefer the way it is now?

@viktor-CCM do you expect that getInitialNotification will return the notification only when the application is in a kill state, while registerNotificationOpened will be triggered only when the application is in a background state?

@DanielEliraz Yes.

viktor-CCM commented 1 year ago

I think I found a way to trigger the registerNotificationOpened also in kill state. do you think it's an advantage or you prefer the way it is now?

@viktor-CCM do you expect that getInitialNotification will return the notification only when the application is in a kill state, while registerNotificationOpened will be triggered only when the application is in a background state?

@DanielEliraz Yes.

I like your way with registerNotificationOpened. But it will be breaking changes and it will be difficult migration (e.x different documentation for versions, migration guide). All other libs use getInitialNotification, it is a common way.

diegolmello commented 1 year ago

It seems to fix specifically the getInitialNotification issue, but brings back https://github.com/wix/react-native-notifications/pull/837 Ideally everything should work like it did before Android SDK 31, without changing any behavior. I'm not an Android dev, but is there something I can help you with? If you give me any insights or unfinished patches, I can try on my end.

diegolmello commented 1 year ago

@DanielEliraz this seems to fix the issue for us https://github.com/RocketChat/Rocket.Chat.ReactNative/pull/4648/commits/929ec66cc2b1a1e0045d674379ad0a1d5fb6699d Is there any way to call mAppLifecycleFacade directly instead of doing that stuff?

StefanLuecke commented 1 year ago

@DanielEliraz @diegolmello any news on this issue ? we are facing the same problem. Is there a workaround ? Do you need support somehow ?

diegolmello commented 1 year ago

@StefanLuecke Our fix is partial only. We found it to fix it only for the first push notification tap. After that, any new push notification tap is going to redirect to the first push again.

We're going to test 4.3.3, because they released official support to RN 0.68 and targeting SDK 31, so maybe there's a fix https://github.com/wix/react-native-notifications/pull/907 However it's very sad we don't get any updates about any of those issues we've been suffering with.

StefanLuecke commented 1 year ago

@diegolmello @DanielEliraz We debugged the Android stuff and figured out that the function callOnOpenedIfNeed in RNNotificationsPackage is causing the Error.

we changed

private void callOnOpenedIfNeed(Activity activity) {
        Intent intent = activity.getIntent();
        if (NotificationIntentAdapter.canHandleIntent(intent)) {
            Context appContext = mApplication.getApplicationContext();
            Bundle notificationData = NotificationIntentAdapter.canHandleTrampolineActivity(appContext) ?
                    intent.getExtras() : NotificationIntentAdapter.extractPendingNotificationDataFromIntent(intent);
            final IPushNotification pushNotification = PushNotification.get(appContext, notificationData);
            if (pushNotification != null) {
                pushNotification.onOpened();
            }
        }
    }

to

private void callOnOpenedIfNeed(Activity activity) {
        Intent intent = activity.getIntent();
        if (NotificationIntentAdapter.canHandleIntent(intent)) {
            Context appContext = mApplication.getApplicationContext();
            Bundle notificationData = intent.getExtras();
            final IPushNotification pushNotification = PushNotification.get(appContext, notificationData);
            if (pushNotification != null) {
                pushNotification.onOpened();
            }
        }
    }

because the function NotificationIntentAdapter.extractPendingNotificationDataFromIntent(intent) is returning null.

We forked this repo. maybe you can check if this works for you as well.

we figured out some more issues i.e. the function onNewIntent in class RNNotificationsModule is never called.

diegolmello commented 1 year ago

@StefanLuecke your patch seems to have fixed the bug for us. Thanks!

stale[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

stale[bot] commented 1 year ago

The issue has been closed for inactivity.

korzonkiee commented 1 year ago

@StefanLuecke thanks for the patch, I really appreciate that you spent your time to investigate the issue and share the solution 🤗

I'm playing with the solution you proposed and the getInitialNotification callback does fire now when the app launched from the killed state.

However, I noticed that whenever I resume the app (e.g. by minimising it and opening it back from task manager), the registerNotificationOpened callback is called every time with the initial notification payload. Here is a video that demonstrates it.

It seems that resuming the app fires the onActivityStarted callback. Then, the callOnOpenedIfNeed function fires and since the activity initially was launched with a notification, then the activity.getIntent() will contain the push notification bundle and it will propagate to JS.

I managed to fix it by clearing the intent once the push notification is handled, but I wonder if it won't have any undesired effect 🤔

CleanShot 2023-03-15 at 17 23 01@2x

bhandanyan-nomad commented 1 year ago

activity.setIntent(null) caused our app to crash on any android version less than 13. activity.setIntent(new Intent()) seems to work better as we continue to test it.

DanielEliraz commented 1 year ago

@bhandanyan-nomad version 5.0.0 was released with activity.setIntent(new Intent()), can you please verify it?

bhandanyan-nomad commented 1 year ago

@DanielEliraz we ended up not using a patch because even with activity.setIntent(new Intent()) we found our app to still be crashing on older androids.

We ended up fixing all our android related linking issues when we upgraded to version 4.3.5 of this package. We will try 5.0.0 on the old device to see if it is still working properly or if the crashing comes back.

stale[bot] commented 12 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

tsalama commented 12 months ago

@DanielEliraz we ended up not using a patch because even with activity.setIntent(new Intent()) we found our app to still be crashing on older androids.

We ended up fixing all our android related linking issues when we upgraded to version 4.3.5 of this package. We will try 5.0.0 on the old device to see if it is still working properly or if the crashing comes back.

How were your results on older devices?