Open activity on firebase notification received in foreground

妖精的绣舞 提交于 2020-12-01 10:05:39

问题


When my application is open and I receive a notification I want to be able to open the activity associated immediately without the need of the user to tap on the notification.

This question is very similar: Open app on firebase notification received (FCM)

But it opens the app when it is in background, I need to do it when my app is in foreground.

From the firebase documentation:

Notifications delivered when your app is in the background. In this case, the notification is delivered to the device’s system tray. A user tap on a notification opens the app launcher by default. Messages with both notification and data payload, both background and foreground. In this case, the notification is delivered to the device’s system tray, and the data payload is delivered in the extras of the intent of your launcher Activity.

This is my implmentation of onMessageReceived

@Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

       // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
            Log.d(TAG, "Message data payload: " + remoteMessage.getData());
        }

        // Check if message contains a notification payload.
        if (remoteMessage.getNotification() != null) {
            Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
            sendNotification( remoteMessage);              
        }     
    }

    /**
     * Create and show a simple notification containing the received FCM message.
     *
     * @param remoteMessage FCM message message received.
     */
    private void sendNotification(RemoteMessage remoteMessage) {
        Intent intent = new Intent(this, MyActivity.class);

        Map<String, String> hmap ;
        hmap = remoteMessage.getData();
        hmap.get("data_info");
        intent.putExtra("data_info", hmap.get("data_info"));
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);


        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);

    }

I am able to get the notification correctly but the activity only starts once I tap the notification on the system tray.

Is there a way to start the activity without tapping the notification while in foreground?

The method onMessageReceived() from the class MyFirebaseMessagingService that extends FirebaseMessagingService is getting called correctly while in foreground, but the activity is not getting started. I have also tried with the flag FLAG_ACTIVITY_NEW_TASK also with no luck. Thanks in advance.


回答1:


You can achieve that registering a broadcast receiver in you foreground activity and sending a broadcast from your onReceiveMessage() method.

ForegroundActivity

mReceiver = new BroadcastReceiver() {
 @Override
 public void onReceive(Context context, Intent intent) {
     Intent myNewActivity = new Intent(this, MyActivity.class);
     startActivity(myNewActivity);
   }
 };

mIntentFilter=new IntentFilter("OPEN_NEW_ACTIVITY");

@Override
protected void onResume() {
     super.onResume();
     registerReceiver(mReceiver, mIntentFilter);
}



@Override
protected void onPause() {
     if(mReceiver != null) 
            unregisterReceiver(mReceiver);
            mReceiver = null;
     }
     super.onPause();
   }

FirebaseNotificationReceiver

@Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

   // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());
    }

    // Check if message contains a notification payload.
    if (remoteMessage.getNotification() != null) {
        Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
        sendNotification( remoteMessage);  

        Intent broadcast = new Intent();
        broadcast.setAction("OPEN_NEW_ACTIVITY);
        sendBroadcast(broadcast);
    }     
}

You can add a check to know if the app is in foreground or not to choose between send a notification or send a broadcast.




回答2:


I was able to achieve this by calling send() on the pendingIntent:

PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);
try {
       pendingIntent.send();
        } catch (PendingIntent.CanceledException e) {
            e.printStackTrace();
    }



回答3:


Creating BroadcastReceiver is the best way of handling for your scenario. But you need to know which activity is being used by the user.

Creating BroadcastReceiver in every activity gives odd look. So Create one BaseActivity which extends Activity. BaseActivity will have the BroadcastReceiver code, and All other activity extends this BaseActivity.

open class BaseActivity : AppCompatActivity() {

private lateinit var broadcastReceiver: BroadcastReceiver

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    broadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(p0: Context?, p1: Intent?) {
            if (p1 != null) {
                handleBroadcastActions(p1)
            }
        }

    }
}

private fun handleBroadcastActions(intent: Intent) {
    when (intent.action) {
        Constants.ACTIVITY_STUFF -> {
            onHandleActivity()
        }
    }
}

protected open fun onHandleActivity() {
    startActivity(intentFor<YourActivity>())
}

override fun onResume() {
    super.onResume()
    registerReceiver(broadcastReceiver, IntentFilter(Constants.ACTIVITY_STUFF))

}

override fun onPause() {
    super.onPause()
    unregisterReceiver(broadcastReceiver)
}}

I have added my kotlin code. Hope you can understand :)

Finally you can call this BroadcastReceiver from onMessageReceived() in FirebaseMessagingService.

override fun onMessageReceived(message: RemoteMessage) {
    sendBroadcast(Intent(Constants.ACTIVITY_STUFF))
}



回答4:


You need to get infos about the current foreground app in your device. Based on that you can decide if start the activity or send a notification.

In order to do this I'll suggest something like this:

public void onMessageReceived(RemoteMessage remoteMessage) {
    // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());
    }

    // Check if message contains a notification payload.
    if (remoteMessage.getNotification() != null) {
        Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
        handleNotification(remoteMessage);              
    }  
}

private void handleNotification(RemoteMessage remoteMessage){
    Intent intent = new Intent(this, MyActivity.class);
    Map<String, String> hmap ;
    hmap = remoteMessage.getData();
    hmap.get("data_info");

    intent.putExtra("data_info", hmap.get("data_info"));
    intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

    Context context = getApplicationContext();

    //CHECK IF THIS APP IS IN FOREGROUND
    ActivityManager am = (ActivityManager)
    AppService.this.getSystemService(ACTIVITY_SERVICE);

    // The first in the list of RunningTasks is always the foreground task.
    RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
    String foregroundTaskPackageName = foregroundTaskInfo .topActivity.getPackageName();

    if(foregroundTaskPackageName.equals(context.getPackageName()){
        //THIS STARTS MAINACTIVITY DIRECTLY IF THE FOREGROUND APP IS THIS APP
        startActivity(intent);
    }else{
        //IF THE FOREGROUND APP ISN'T THIS APP THEN SEND A PENDING INTENT TO OPEN MAIACTIVITY WHEN USER TAP ON NOTIFICATION
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
            PendingIntent.FLAG_ONE_SHOT);
        //CREATE A NOTIFICATION IN THE SYSTEM TRAY
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
                .setContentTitle("TITLE")
                .setContentText("SUBMESSAGE")
                .setPriority(Notification.PRIORITY_MAX)
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                .setContentIntent(pendingIntent)
                .setAutoCancel(true);
        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);

        // notificationId is a unique int for each notification that you must define
        notificationManager.notify(notificationId, mBuilder.build());
    }
}

You have to set the notification id, the title and the submessage that will be shown in the notification.

You will also need <uses-permission android:name="android.permission.GET_TASKS" /> permission to be added in the app manifest.




回答5:


(kotlin) use this code inside onMessageReceived if you want to check is app either foreground or background

    var foreground = false

    try {
        foreground = ForegroundCheckTask().execute(this).get()
    } catch (e: InterruptedException) {
        e.printStackTrace()
    } catch (e: ExecutionException) {
        e.printStackTrace()
    }

then use the "foreground" variable to do action as you needed

 if (foregroud) { //app in foreground
            intent = Intent(this, ChatAdminActivity::class.java)
            intent.putExtra("intent_backchat", 1)
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK)
            pendingIntent = PendingIntent.getActivity(this, Integer.valueOf(random) /* Request code */, intent, PendingIntent.FLAG_UPDATE_CURRENT)
            startActivity(intent)      // to directly open activity if app is foreground
        } else { //app in background
            intent = Intent(this, ChatAdminActivity::class.java)
            intent.putExtra("intent_backchat", 1)
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
            pendingIntent = PendingIntent.getActivity(this, Integer.valueOf(random) /* Request code */, intent, PendingIntent.FLAG_UPDATE_CURRENT)
        }
.....

hope its helping..

and you can see my full FCMService code




回答6:


public class MyFirebaseMessagingService extends FirebaseMessagingService {
 private static final String TAG = "FCM Service";
 @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // TODO: Handle FCM messages here.
        // If the application is in the foreground handle both data and notification messages here.
        // Also if you intend on generating your own notifications as a result of a received FCM
        // message, here is where that should be initiated.
//     IntentFilter filter = new IntentFilter("OPEN_NEW_ACTIVITY");
//        registerReceiver(new BroadcastNotification(),filter);
//     showNotification(remoteMessage.getNotification().getBody());

        Log.d(TAG, "From: " + remoteMessage.getFrom());
        Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());
     Log.e("Myname","shdjhfghgh");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Intent in= new Intent(this,MainActivity.class);
        in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(in);
    }
}



回答7:


According to the Google page about Broadcasts:

If you don't need to send broadcasts to components outside of your app, then send and receive local broadcasts with the LocalBroadcastManager which is available in the Support Library. The LocalBroadcastManager is much more efficient (no interprocess communication needed) and allows you to avoid thinking about any security issues related to other apps being able to receive or send your broadcasts. Local Broadcasts can be used as a general purpose pub/sub event bus in your app without any overheads of system wide broadcasts.

So, prefer use LocalBroadcastManager instead of BroadcastReceiver.

In the FirebaseMessagingService class, you receive the notification from FCM (Firebase Cloud Messaging) and use:

LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

to send a message to the MainActivity:

public class AppFirebaseMessagingService extends FirebaseMessagingService {
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

        try {
            String messageFrom = remoteMessage.getFrom();
            String messageBody = (remoteMessage.getNotification() != null ? remoteMessage.getNotification().getBody() : null);
            Map<String, String> messageData = remoteMessage.getData();

            NotificationInfo notificationInfo = new NotificationInfo(messageData.get(message));
            notifyMainActivity(notificationInfo);
            showNotification(notificationInfo);
    }

    private void notifyMainActivity(NotificationInfo notificationInfo) {
        Intent intent = new Intent();
        intent.setAction(Constants.BROADCAST_MESSAGE_NOTIFICATION_RECEIVED);
        intent.putExtra(Constants.PARAM_NOTIFICATION_INFO, notificationInfo);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void showNotification(NotificationInfo notificationInfo) {

        Intent intentNotificationClicked = new Intent(this, MainActivity.class);
        intentNotificationClicked.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        intentNotificationClicked.putExtra(Constants.PARAM_NOTIFICATION_INFO, notificationInfo);
        PendingIntent resultIntentNotificationClicked = PendingIntent.getActivity(this, 0, intentNotificationClicked, PendingIntent.FLAG_ONE_SHOT);

        String title = "MY APPLICATION";
        String message = notificationInfo.message;

        Uri notificationSoundURI = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder mNotificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_notification_icon)
                .setContentTitle(title)
                .setContentText(message)
                .setAutoCancel(true)
                .setSound(notificationSoundURI)
                .setContentIntent(resultIntentNotificationClicked);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        int notificationID = Integer.parseInt(new SimpleDateFormat("HHmmssSSS").format(new Date()));
        notificationManager.notify(notificationID, mNotificationBuilder.build());
    }
}

And in MainActivity you create the BroadcastReceiver to receive the message:

public class MainActivity extends AppCompatActivity {
    private NotificationBroadcastReceiver mNotificationBroadcastReceiver = null;
    private IntentFilter mIntentFilter = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        this.mNotificationBroadcastReceiver = new NotificationBroadcastReceiver(this);
        this.mIntentFilter = new IntentFilter(Constants.BROADCAST_MESSAGE_NOTIFICATION_RECEIVED);
    }

    @Override
    protected void onResume() {
        super.onResume();
        LocalBroadcastManager.getInstance(this).registerReceiver(this.mNotificationBroadcastReceiver, this.mIntentFilter);
    }

    @Override
    protected void onPause() {
        if (this.mNotificationBroadcastReceiver != null) {
            unregisterReceiver(mNotificationBroadcastReceiver);
            this.mNotificationBroadcastReceiver = null;
        }

        super.onPause();
    }

    private class NotificationBroadcastReceiver extends BroadcastReceiver {

        WeakReference<MainActivity> mMainActivity;

        public NotificationBroadcastReceiver(MainActivity mainActivity) {
            this.mMainActivity = new WeakReference<>(mainActivity);
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            MainActivity mainActivity = mMainActivity.get();
            if (mainActivity != null) {
                Bundle extras = intent.getExtras();
                if (extras != null && extras.containsKey(Constants.PARAM_NOTIFICATION_INFO)) {
                    NotificationInfo notificationInfo = (NotificationInfo) extras.getSerializable(Constants.PARAM_NOTIFICATION_INFO);
                    mainActivity.notificationReceived(notificationInfo);
                }
            }
        }
    }

    public void notificationReceived(@NonNull final NotificationInfo notificationInfo)
    {
        //handle the notification in MainActivity
    }
}

Below the classes referenced in code:

public class Constants {
    public static final String NOTIFICATION_BROADCAST_RECEIVER_MESSAGE_RECEIVED = "com.mycompany.myapp.NOTIFICATION_RECEIVED";
    public static final String PARAM_NOTIFICATION_INFO = "NotificationContent";
}

public class NotificationInfo implements Serializable {
    public String message;
    public NotificationInfo() { }
    public NotificationInfo(String message) { this.message = message; }
}

That's it!




回答8:


What i usually do is send data message and create a intent from it.

public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
    super.onMessageReceived(remoteMessage);
    Log.d(TAG, "onMessageReceived: called");

    Log.d(TAG, "onMessageReceived: Message received from: " + remoteMessage.getFrom());

    if (remoteMessage.getNotification() != null) {
        String title = remoteMessage.getNotification().getTitle();
        String body = remoteMessage.getNotification().getBody();
        Log.d(TAG, "onMessageReceived: "+title+" "+body);

        Notification notification = new NotificationCompat.Builder(this, FCM_CHANNEL_ID)
                .setSmallIcon(R.mipmap.ridersquare)
                        .setContentTitle(title)
                .setContentText(body)
                .setColor(Color.BLUE)
                .setSubText("KKKK")
                .build();

        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(FCM_CHANNEL_ID, "Default channel", NotificationManager.IMPORTANCE_HIGH);
            manager.createNotificationChannel(channel);
        }
        manager.notify(1002, notification);
    }

    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "onMessageReceived: Data: " + remoteMessage.getData().toString());
        if (remoteMessage.getData().toString().length()>0){
            Notification notification = new NotificationCompat.Builder(this, FCM_CHANNEL_ID)
                    .setSmallIcon(R.mipmap.ridersquare)
                    .setContentTitle("New Order")
                    .setContentText("New order received from"+remoteMessage.getData().get("restaurant_name"))
                    .setSound(App.soundUri)
                    .setLights(Color.RED, 3000, 3000)
                    .setAutoCancel(true)
                    .setPriority(NotificationCompat.PRIORITY_HIGH)
                    .setVibrate(new long[]{0,1000, 500, 1000})
                    .build();

            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationChannel channel = new NotificationChannel(FCM_CHANNEL_ID, "Default channel", NotificationManager.IMPORTANCE_HIGH);
                manager.createNotificationChannel(channel);
            }
            manager.notify(50, notification);
            Intent intent=new Intent(getApplicationContext(), NewOrderNoti.class);
            intent.putExtra("username",remoteMessage.getData().get("username"));
            startActivity(intent);

        }


    }

This basically creates a notification and calls a intent to open new activity




回答9:


If you want to set only your notification, You can change this(Clinet example),

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

   // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());
        sendNotification( remoteMessage.getData());          
    }       
}  

And then server send message like this(example), only data( not notification)

var message = { //this may vary according to the message type (single recipient, multicast, topic, et cetera)
to: token,     
priority: 'high',
content_available: true,    
data: {  
    //you can send only notification or only data(or include both)
    message: 'news'
}};

Ref)

There are two types of messages in FCM:
- display-messages: These messages trigger the onMessageReceived() callback only when your app is in foreground
- data-messages: Theses messages trigger the onMessageReceived() callback even if your app is in background

Two types of messages in FCM



来源:https://stackoverflow.com/questions/39358835/open-activity-on-firebase-notification-received-in-foreground

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!