问题
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