0

I'm writing a native Android code to open my app when a notification is pressed. If the app is already opened (whether running in foreground or in background), I want clicking the notification to bring the app to front, without restarting it, so that its state is preserved.

I tried the following code (showing only relevant code):



        ///////// Create an activity on tap (intent)
        const Intent = android.content.Intent;
        const PendingIntent = android.app.PendingIntent;
        // Create an explicit intent for an Activity in your app
        const intent = new Intent(context, com.tns.NativeScriptActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_NEW_TASK);


        const pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);

        ///////// Creating a notification 
        var NotificationCompat = android.support.v4.app.NotificationCompat;
        const builder = new NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.btn_star_big_on)
            .setContentTitle(title)
            .setContentText(message)
            .setStyle(
                new NotificationCompat.BigTextStyle()
                .bigText("By default, the notification's text content is truncated to fit one line.")
                )
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            // Set the intent that will fire when the user taps the notification
            .setContentIntent(pendingIntent)
            .setAutoCancel(true);

        ///////// Show the notification
        notificationManager.notify(NOTIFICATION_ID, builder.build());

But that opened the application without preserving its state.

Following recommendations here, I also tried emulating pressing the app icon from the launcher - so that the app is just brought to the frontground and the Nativescript activity is not recreated.

        const packageName = context.getPackageName();
        console.log('Package name: ',packageName);

        const emulateLaunchByAppIconIntent = context.getPackageManager()
            .getLaunchIntentForPackage(packageName)
            .setPackage(null)
            .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

        const pendingIntent_emulated = PendingIntent.getActivity(context, 0, emulateLaunchByAppIconIntent, 0);


        ///////// Creating a notification 
        var NotificationCompat = android.support.v4.app.NotificationCompat;
        const builder = new NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(android.R.drawable.btn_star_big_on)
            .setContentTitle(title)
            .setContentText(message)
            .setStyle(
                new NotificationCompat.BigTextStyle()
                .bigText("By default, the notification's text content is truncated to fit one line.")
                )
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            // Set the intent that will fire when the user taps the notification
            .setContentIntent(pendingIntent_emulated)
            .setAutoCancel(true);

        ///////// Show the notification
        notificationManager.notify(NOTIFICATION_ID, builder.build());

This indeed made the app come to front, but didn't preserve its state (even if the app was already in foreground - it reloaded the app).

Then I tried pressing a Nativescript application app icon (manually), when the app has just been sent to the background - and I found that it would restart the app, and not just bring it to the foreground.

My question is - why does a Nativescript application behave like this? How can I make Android just bring the app to foreground and not re-build a new nativescript activity?

Lorraine R.
  • 1,545
  • 1
  • 14
  • 39

1 Answers1

0

The code in the question above, actually works - and does bring the app to the foreground without restarting the app, preserving its state.

The reason the app was restarting, even by clicking the Nativescript application app icon (manually) was related to the development environment.

  1. This happened when I was running the app on a physical device while connected to my Mac running tns run android --bundle, or

  2. Running the app in an emulator (either by running tns run android --bundle or by launching the app directly from the app icon)

Running the app on a physical device that is not connected to the nativescript development environment - showed the real behavior - and the app was brought to the foreground without restarting after clicking the notification.

More info with code examples:

I found that there's no need to launch the app by simulating an icon press using this code

const emulateLaunchByAppIconIntent = context.getPackageManager()
   .getLaunchIntentForPackage(packageName)
   .setPackage(null)
   .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

const pendingIntent_emulated = PendingIntent.getActivity(context, 0, emulateLaunchByAppIconIntent, 0);

as PendingIntent.FLAG_UPDATE_CURRENT or Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED in the code below, is sufficient to bring app to the foreground without restarting after clicking the notification:

const openActivityIntent = new Intent(context, com.tns.NativeScriptActivity.class);
openActivityIntent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_NEW_TASK);
const openActivityPendingIntent = PendingIntent.getActivity(context, 0, openActivityIntent, 0);

///////// Creating a notification
const notificationManager = <NotificationManager> context.getSystemService(NotificationManager.class);
var NotificationCompat = android.support.v4.app.NotificationCompat;

const builder = new NotificationCompat.Builder(context, CHANNEL_ID)
    .setSound(soundUri)
    .setSmallIcon(android.R.drawable.ic_lock_idle_alarm)
    .setContentTitle(title)
    .setContentText(message)
    .setStyle(
        new NotificationCompat.BigTextStyle()
        .bigText('More explaination text if needed. Disabled for now.')
        )
    .setPriority(NotificationCompat.PRIORITY_DEFAULT)
    // Set the intent that will fire when the user taps the notification
    .setContentIntent(openActivityPendingIntent)
    .setWhen(scheduledTime)
    .setAutoCancel(true)
    .build();


///////// Show the notification
notificationManager.notify(NOTIFICATION_ID, builder);

Hope this helps you if you got into the same issue.

Lorraine R.
  • 1,545
  • 1
  • 14
  • 39