Code Monkey home page Code Monkey logo

Comments (24)

Salakar avatar Salakar commented on June 15, 2024 2

Hey,

launchActivityFlags is live in 0.7.0 with support for all the Activity flags.

Here's an example using SINGLE_TOP;

import { AndroidStyle, AndroidLaunchActivityFlag } from '@notifee/react-native';


const notification = {
  title: 'Testing SINGLE_TOP launch.',
  body: 'Expand for a cat!',
  android: {
    channelId: 'foo',
    pressAction: {
      id: 'default',
      launchActivity: 'default',
      launchActivityFlags: [AndroidLaunchActivityFlag.SINGLE_TOP],
    },
    style: {
      type: AndroidStyle.BIGPICTURE,
      picture: 'https://icatcare.org/app/uploads/2018/07/Thinking-of-getting-a-cat.png',
    },
  },
};

from react-native-notifee.

shubhamverma27 avatar shubhamverma27 commented on June 15, 2024 2

@mikehardy yes, making it async seems to solve the issue.
Yes,I am using it with Rnfirebase messaging and the messaging background handler's promise function had to be made async..You may update that in your documentation :)

from react-native-notifee.

Salakar avatar Salakar commented on June 15, 2024 1

The notification won't bring up the app unless I set launchActivity

For this part its intentional - as not every action needs to launch an activity, e.g. 'liking a post' action doesn't need to open the app as an example.


In terms of it launching a fresh activity every-time I think this is down to the launch mode we use internally - we'll take a look. (cc @Ehesp I think this is the code in launchPendingIntentActivity thats doing it, I think we might need to also set launch flags on launchIntent too)

@LuisRodriguezLD as part of your app startup (or Activity in this case) you should be calling getInitialNotification to determine what notification (if any) caused your app to open/relaunch. It's best using this along side onBackgroundEvent as the system can recycle backgrounded activities, meaning in that case it'd be a fresh launch anyway, otherwise if it doesn't then your onBackgroundEvent will handle navigation for an already open activity.

from react-native-notifee.

Ehesp avatar Ehesp commented on June 15, 2024 1

Hey @whenmoon I've just had a play around, essentially under the hood we create and launch a new Intent when something happens.

Right now, there are no flags on the intent which causes the activity to "relaunch". If I set it to FLAG_ACTIVITY_SINGLE_TOP, the app re-opens without reloading the app.

cc @Salakar I remember we looked into this, can you remember a reason we decided to not use FLAG_ACTIVITY_SINGLE_TOP? From memory, if you specify a custom activity, it meant you'd also lose your current app activity...

from react-native-notifee.

Salakar avatar Salakar commented on June 15, 2024 1

This should be in a version later today / tomorrow as launchActivityFlags, will post here when up

from react-native-notifee.

shubhamverma27 avatar shubhamverma27 commented on June 15, 2024 1

Making my handler method async fixed it for me

messaging().setBackgroundMessageHandler(async (remoteMessage) => {

from react-native-notifee.

whenmoon avatar whenmoon commented on June 15, 2024

This is also happening for me and is undesirable in my case. When my calling app is in the background, I provide users with action buttons to either answer or decline a call on receipt of a notification. Here is my 'Answer' launch activity:

actions: [
          {
            title: 'Answer',
            pressAction: {
              id: 'answer',
              launchActivity: 'default',
            },
          },

However, because the app is in the background, it means the app has already been launched which means the user doesn't need to authenticate and event listeners in the app trigger router actions when an incoming call occurs (which also happens when the app is in the background).

So what I need is for the user to be able to press 'Answer' and the launch action is to bring the app from the background, to the foreground and nothing else. Right now this almost behaves like launchActivity: 'default', kills the app first and then launches it again from scratch, which causes errors to occur as the app state is no longer intact.

What would be ideal in my case would be something like launchActivity: 'bringAppToForeground', which would have exactly exactly the same behaviour as if you were to tap on an icon of an app that was in the background.

I am trying to migrate from custom native Java modules to Notifee for handling notifications and the behaviour I describe is what happens when I create and press a notification using this code:

@ReactMethod
    void createNotification(String notificationMessage, int notificationID, String contentText) {
        ReactApplicationContext context = getReactApplicationContext();

        NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        NotificationCompat.Builder builder;

        Resources res = context.getResources();

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {

            String CHANNEL_ID = "channel_ID_0";

            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "channel",
                    NotificationManager.IMPORTANCE_HIGH);
            channel.setDescription("incoming call");
            manager.createNotificationChannel(channel);

            builder = new NotificationCompat.Builder(context, CHANNEL_ID);
        } else {
            builder = new NotificationCompat.Builder(context);
        }

        // Flag indicating that if the described PendingIntent already exists, the
        // current one should be canceled before generating a new one.
        Intent activityIntent = new Intent(context, MainActivity.class);
        activityIntent.putExtra("FromNotification", true);
        PendingIntent action = PendingIntent.getActivity(context, 0, activityIntent, PendingIntent.FLAG_CANCEL_CURRENT);

        builder.setLargeIcon(BitmapFactory.decodeResource(res, R.drawable.ic_stat_icon_))
                .setSmallIcon(R.drawable.ic_stat_icon_).setTicker("Large text!").setAutoCancel(true)
                .setContentTitle(notificationMessage).setPriority(NotificationCompat.PRIORITY_HIGH)
                .setCategory(NotificationCompat.CATEGORY_CALL).setContentText(contentText)
                .setFullScreenIntent(action, true);

        Notification notification = builder.build();

        int notificationCode = notificationID;
        manager.notify(notificationCode, notification);
    }

from react-native-notifee.

Ehesp avatar Ehesp commented on June 15, 2024

I wonder if we can provide the ability to pass something down which determines the launch behaviour - when building the library out we did have a chat about this, but it would make sense to let the user be in-control.

Maybe something like an ENUM on JS side, which is sent to the intent.

from react-native-notifee.

whenmoon avatar whenmoon commented on June 15, 2024

This would really help, thanks 👌🏼

from react-native-notifee.

whenmoon avatar whenmoon commented on June 15, 2024

@Ehesp would you mind providing a code snippet of where to add this flag within the library as a workaround whilst we wait for 'official' support for it? Thanks

from react-native-notifee.

whenmoon avatar whenmoon commented on June 15, 2024

Hi @Salakar, would it be possible to provide an example of how to use this where the app is launched / bought to foreground and app state stays intact?

At the moment with this code:

        actions: [
          {
            title: 'Answer',
            pressAction: {
              id: 'answer',
              launchActivity: 'default',
              launchActivityFlags: [AndroidLaunchActivityFlag.SINGLE_TOP],
            },
          },

or using launchActivityFlags: [AndroidLaunchActivityFlag.BROUGHT_TO_FRONT],, app state is destroyed after launch. I have also noticed that in my debugger console I get two instances of this with different rootTags: Running "app" with {"rootTag":1}, one is logged on first launch, then the app is put in to the background, a notification is received, the above action is used and then I get Running "app" with {"rootTag":31}, the app launches but state is reset.

Thanks

from react-native-notifee.

mikehardy avatar mikehardy commented on June 15, 2024

Hmm - I can't reproduce, I have it working

https://developer.android.com/reference/android/content/Intent#FLAG_ACTIVITY_SINGLE_TOP is supposed to be the one / https://stackoverflow.com/a/19627387/9910298

I had the same problem as I integrated Notifee just now - no action on tapping a notification I naively popped up with no pressAction set - and after setting it like this, it works:

        APKUpdateService.VERSION_NOTIFICATION_ID = await notifee.displayNotification({
          id: APKUpdateService.VERSION_NOTIFICATION_ID,
          title: I18NService.translate('UpdateAvailableTitle'),
          body: I18NService.translate('UpdateAvailableText'),
          android: {
            channelId: APKUpdateService.UPDATE_NOTIFICATION_CHANNEL_ID,
            smallIcon: 'drawable/minilogo_bw',
            pressAction: {
              id: 'default',
              launchActivity: 'default',
              launchActivityFlags: [AndroidLaunchActivityFlag.SINGLE_TOP],
            },
          },
        });

Maybe you have device developer setting "keep activities" set to false or similar?

from react-native-notifee.

whenmoon avatar whenmoon commented on June 15, 2024

Hi @mikehardy, hmmm ok thinking about this I would bet that what's stopping it working for me is the fact that I have another notification set up to launch a custom React component.

backgroundIncomingCallNotification.js:

        actions: [
          {
            title: 'Answer',
            pressAction: {
              id: 'answer',
              launchActivity: 'default',
              launchActivityFlags: [AndroidLaunchActivityFlag.SINGLE_TOP],
            },
          },

killedIncomingCallNotification.js:

actions: [
          {
            title: 'Answer',
            pressAction: {
              id: 'answer',
              mainComponent: 'app-router',
            },
          },

Then I obviously have the custom component registered etc as described here

If you register a custom component for another notification does it still work?

The fact that they have the same id doesn't matter right now as they have not been used together yet.

I'll do some proper testing later cheers.

from react-native-notifee.

whenmoon avatar whenmoon commented on June 15, 2024

Ok I've tried to test this as much as possible and I'm getting very inconsistent results unfortunately. Sometimes on pressing a pressAction button, I get a new Running "app" with {"rootTag":11} logged in the debugger console and the app is launched and the root component is remounted with store state destroyed, and other times I am able to consistently reproduce the following steps:

  1. Launch app
  2. Put app in to background
  3. Receive notification
  4. Notification is displayed by function called from HeadlessJS - without being bought to the foreground the app root is remounted / re-rendered but redux state is left intact: firebase.messaging().setBackgroundMessageHandler(backgroundNotificationHandler)
notifee.onBackgroundEvent(async ({ type, detail }) => {
  const { notification, pressAction } = detail;

  const cancelIncomingCallActions = async () => {
    await notifee.cancelNotification(notification.id);
  }

  if (type === EventType.ACTION_PRESS && pressAction.id === 'answer') {
    store.dispatch(answerCall());
    cancelIncomingCallActions();
  }
});

const backgroundIncomingCallNotification = async (
  notificationTitle,
  notificationBody,
  notificationID,
) => {

  const channelId = await notifee.createChannel({
    id: notificationID,
    name: 'Incoming Call',
    importance: AndroidImportance.HIGH,
    visibility: AndroidVisibility.PUBLIC,
  });

  try {
    await notifee.displayNotification({
      title: `<p style="color: #C9FB5C;"><b>${notificationTitle}</span></p></b></p> &#128075;`,
      description: 'Description',
      android: {
        ongoing: true,
        category: AndroidCategory.CALL,
        channelId,
        importance: AndroidImportance.HIGH,
        visibility: AndroidVisibility.PUBLIC,
        color: COL_BASE_YELLOW,
        vibrationPattern: [300, 500],
        smallIcon: 'ic_stat_icon_',
        style: { type: AndroidStyle.BIGTEXT, text: `${notificationBody}` },
        progress: {
          max: 10,
          current: 5,
          indeterminate: true,
        },
        actions: [
          {
            title: 'Answer',
            pressAction: {
              id: 'answer',
              launchActivity: 'default',
              launchActivityFlags: [AndroidLaunchActivityFlag.SINGLE_TOP],
            },
          },
  1. press pressAction button
  2. Notification is dismissed / app is bought to foreground
  3. Put app in to background
  4. Receive another notification - only thing that happens is backgroundIncomingCallNotification is called
  5. The same notification is displayed
  6. press pressAction button - app is bought to foreground and then app root is remounted / re-rendered but redux state is left intact

If steps 7 - 10 are repeated the the behaviour is consistent - the issue here is that the first time a notification is received, the app is re-mounted in the background before pressing a pressAction button. The second time thereafter the app is only remounted after a pressAction button has been pressed.

The ideal scenario is that the app is never remounted or re-rendered when using a press action. Obviously because the root app component is remounting, functions and so on are being called that you only want to call on first launch, like authentication so I'm having to use flags dispatched to the store to determine how the app has been launched (I would normally do this but am having to do more-so to try and manage this).

Another strange but (I think) linked observation is that when 'reloading' the app from dev tools, I get these stacking up in the console as I mentioned in a comment above:

Running "app" with {"rootTag":31}
Running "app" with {"rootTag":41}
Running "app" with {"rootTag":51}

I also get other logs that I would only expect to see one of - I'm finding it hard to predictably recreate this but it's like the app or some part of it is running more than once at a time if that's even possible.

Some of this could be down to my own logic that needs to be improved upon but one thing that's for sure is that app launch behaviour from press actions is unpredictable for me.

I think I need to move these in to foreground services anyway as I have whole load of async stuff going on in the background.

This is all on physical pixel devices.

from react-native-notifee.

mikehardy avatar mikehardy commented on June 15, 2024

Sounds racy, I wonder if you whittled it down to the minimum viable app and made sure it was all the listeners etc were registered in App.js if that would improve things (i.e., you'd win the race consistently)? Without a reproduction it's going to be tough to reason about this, which is just stating the obvious of course. I was doing most of my testing on an emulator, and I'll move to physical devices next. If I notice anything in my implementation i'll mention it but mine is still behaving as expected

from react-native-notifee.

Salakar avatar Salakar commented on June 15, 2024

@whenmoon I've noticed in your snippet above in backgroundIncomingCallNotification you're setting the channel id to the notification id so this would be creating a new channel everytime if these ids are unique, you're also not passing notificationID as the id to the notification that you're creating there, whether this is relevant I'm not sure

from react-native-notifee.

Salakar avatar Salakar commented on June 15, 2024

Could you also try combining single top flag with other flags like clear top, and see what happens

from react-native-notifee.

whenmoon avatar whenmoon commented on June 15, 2024

@mikehardy yep ok I'm going to work on this and try to remove anything that could have some kind of effect on it like you mention. @Salakar Whilst doing the above testing I was always using the same notification id every time as I base them on the user sending it so they can be identified but thanks for the observation - I'll fix this, will also try other flag combos and report back.

from react-native-notifee.

whenmoon avatar whenmoon commented on June 15, 2024

@mikehardy @Salakar I've done a bunch of testing, foreground services, background events, different combinations of launch activity flags, moving listeners in to index.js, App.js, stripping out everything to test functionality one thing at a time, but whatever way I cook it, what I find as consistent, predictable and undesirable behaviour is:

  1. launch app
  2. put in to background
  3. receive notification
  4. app root component is re-mounted, calling all the functions it would do when it launches for the very first time (obviously conditionals based on press actions should dictate what logic is executed when the app opens via a notification press, but this should be defined in state or using getInitialNotification() etc)
  5. press pressAction button
  6. app opens
  7. app put in to the background
  8. receive notification
  9. press pressAction button
  10. app opens
  11. and then app root component is re-mounted (after press, not on notification receipt)

You should be able to test this just by logging inside a function that gets called early on in your application and observing when it gets called.

Then I have this problem which is related to the app registry (this is the line of RN code that handles the info log):

Screenshot 2020-06-11 at 23 07 43

You can see how Notifee is causing multiple calls / renders (launches) in what is in fact a single launch - my knowledge of the app registry is not sufficient to be able to explain exactly what's happening in the background.

The desirable launch action is to bring the app from the background to the foreground (killed app is a slightly different scenario but let's stick to background for now) whilst still being able to hook in to methods / features like getInitialNotification() and EventType, but literally nothing else.

from react-native-notifee.

whenmoon avatar whenmoon commented on June 15, 2024

I've tested out https://github.com/zo0r/react-native-push-notification to see how it behaves and it does not effect the app in the same way as Notifee when using a press action when the app is in the background. I then modified the library to add setFullScreenIntent to the notification and then it started behaving in the same way as Notifee does. The behaviour I describe in the second half of the comment above always starts a new activity because of the PendingIntent passed to setFullScreenIntent. After changing android:launchMode="singleTop" to android:launchMode="singleTask" in my manifest this behaviour corrected itself - I would guess that the same would be true for Notifee but haven't tested it yet, even though Notifee does not setFullScreenIntent.

from react-native-notifee.

whenmoon avatar whenmoon commented on June 15, 2024

Ok FYI, this zo0r/react-native-push-notification#1482 solves this issue for me and also this issue. Any chance of similar implementation in Notifee? This would complete the package for me (although as far as I know you're not planning to implement Telecom API / Alarm manager)!

from react-native-notifee.

shubhamverma27 avatar shubhamverma27 commented on June 15, 2024

Hi,
I am also facing the same issue have tried setting launchActivityFlags: to single top and BROUGHT_TO_FRONT both but every time when my app is in the background and I get a notification, The app just restarts instead of just coming back to screen.
My android launch mode in the manifest is single-task and this is not expected behaviour.
My app notifications are stuck due to this, please help as this is a big issue.

from react-native-notifee.

mikehardy avatar mikehardy commented on June 15, 2024

@shubhamverma27 seems like you found a solution? May I assume this is an integration with react-native-firebase? Or perhaps it is an issue with any cloud message library. The reason I ask is the documentation for integration with cloud messaging might need a change to emphasize this more strongly

from react-native-notifee.

russellwheatley avatar russellwheatley commented on June 15, 2024

FWIW I've also tested message handling whilst the app is in a background state on Android a number of times, and it never reloaded the app anew.

from react-native-notifee.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.