I have added two actions to the notification i.e. accept and reject.
I can see both when the app is in foreground. But I cant see the actions when app is in background.
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
private String mOrderId, mBillId;
private Boolean mUpdateNotification;
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Log.d(TAG, "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.describeContents());
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
}
//get data from server notification.
sendNotification(remoteMessage.getNotification().getBody(), remoteMessage.getNotification().getTitle());
}
//send notification
private void sendNotification(String messageBody, String title) {
Intent intent = new Intent();
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 , intent,
PendingIntent.FLAG_UPDATE_CURRENT);
long[] pattern = {500, 500, 500, 500, 500};
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.login_logo_1)
.setContentTitle(title)
.setContentText(messageBody)
.setAutoCancel(true)
.setVibrate(pattern)
.setSound(defaultSoundUri)
.addAction(R.string.accept,getString(R.string.accept), pendingIntent)
.addAction(R.string.reject,getString(R.string.reject), pendingIntent)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 , notificationBuilder.build());
}
}
Also I want to handle the intents from these actions. For this I have created a class which extends broadcast receiver,but how to call this in an activity?
public class NotificationReceiver extends BroadcastReceiver {
String ACCEPT,REJECT;
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(ACCEPT.equals(action)) {
Log.v("Delivery","Accepted");
}
else if(REJECT.equals(action)) {
Log.v("Delivery","Rejected");
}
}
}
Please help. Thank you..
In FCM there are three type of messages you can send
1. Notification message
FCM automatically displays the message to end-user devices on behalf
of the client app. Notification messages have a predefined set of
user-visible keys and an optional data payload of custom key-value
pairs.
Use notification messages when you want FCM to handle displaying a
notification on your client app's behalf.
2.Data message
Client app is responsible for processing data messages. Data messages
have only custom key-value pairs.
Use data messages when you want to process the messages on your
client app.
3. Both Notification and Data
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.
So if you want to handle message on client side better you go with Data Message
here you get all details
For send Data Message
For Data Message you have to call post service using following URL
https://fcm.googleapis.com/fcm/send
Headers
Authorization:key=yourserverkey
Content-Type: application/json
Payload
{"data": "extra data to be send",
"to" : "devicetoken"
}
Note: replace "to" with "registration_ids" : ["1","2","3","4","5","6"] for multiple devices
In Application onMessageReceived you can get data message using remoteMessage.getData()
For detail already mentioned this https://firebase.google.com/docs/cloud-messaging/concept-options
Here you also check to send notification to Topics using data message https://firebase.google.com/docs/cloud-messaging/android/topic-messaging
Related
I'm sending firebase-messages using the firebase-console. The messages shall contain additional data like shown below with the purpose to open a specific URL within a webview in my app:
I set up my manifest and firebase class to get the messages. Within my firebase class I try to get the data:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
if(remoteMessage.getData().containsKey("key1")) {
intent.putExtra("destination", remoteMessage.getData().get("key1"));
}
PendingIntent pendingIntent = PendingIntent.getActivity
(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
String channelId = "default";
NotificationCompat.Builder builder;
if (remoteMessage.getNotification() != null ) {
if (remoteMessage.getNotification().getTitle() != null) {
builder = new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_stat_onesignal_default)
.setContentTitle(remoteMessage.getNotification().getTitle())
.setStyle(new NotificationCompat.BigTextStyle().bigText(remoteMessage.getNotification().getBody()))
.setAutoCancel(true)
.setContentIntent(pendingIntent);
} else {
builder = new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_stat_onesignal_default)
.setStyle(new NotificationCompat.BigTextStyle().bigText(remoteMessage.getNotification().getBody()))
.setAutoCancel(true)
.setContentIntent(pendingIntent);
}
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId, "default", NotificationManager.IMPORTANCE_DEFAULT);
manager.createNotificationChannel(channel);
}
manager.notify(0, builder.build());
}
}
Within my MainActivity class I try to get the data. When the app is in the foreground, the following works (no matter what activity is opened, it will jump to the MainActivity and execute the following):
#Override
protected void onNewIntent(Intent intent) {
if (intent.getExtras() != null) {
Bundle extras = intent.getExtras();
if(extras.containsKey("destination")) {
Log.e("FIREBASE_CONTAINS", (String) extras.get("destination"));
}
}
}
But the event wont trigger if the app started from the background. I tried to get the intent and check for the key within the onResume() event of the activity, but it does not work (Same in inCreate() and onStart()).
Can anybody help me?
------------EDIT-----------------
As described in one of the comments, the problem seems to be that Notification-Messages won't reach the onMessageReceived() event. Apparently the firebase console can't send data-notifications (which would reach the event) so I tried using POSTMAN. I've read that I have to leave the notification tag out of the message body and put all my information in the data section. But if I do so, the messages won't reach my app (they do, when I add the notification section again, but of course they are not reaching the onMessageReceived() event in that case).
There are 3 types of push messages
notification
data
and both
A push messages is basically a json payload:
payload:{
notificacion...
data
}
Rules for each type of push messages are differente. In your case you are using the Firebase web console and adding custom data, which mean your payload will have notification and data.
For the combined type the behaviour in backgroun is to use a default notificacion (NotificationCompat, the visual kind) and open the default activity registered in the manifest. In the activity you can get the data.
Lets say your default activity is called MainActivity
public class MainActivity {
onCreate...{
//... usual stuff
Intent fcmIntent = getIntent();
if fcmIntent != null
//check the extras and forward them to the next activity if needed
}
}
There are two type of push message
(1)Notification Message (will receive when app is in foreground)
(2)Data Message (will receive when app is in background+foreground)
Reference : https://firebase.google.com/docs/cloud-messaging/android/receive
You need to set click_action in firebase notification data set to be able to receive data from background and implement onMessageReceived to handle foreground data
See updated answer here: https://stackoverflow.com/a/73724040/7904082
I'm using firebase-cloud-messaging for push notification to my application. I wanted that when user clicks on notification it open OpenWeb class and an Intent open url.
Sended data using PHP:
$data = array("notification"=> array("title"=>"http://example.com/",
"text"=>"This is a test msg!",
"click_action"=>"OpenWeb"),
"priority" => "high",
"to"=>"/topics/main");
MyFirebaseMessagingService.java
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
String title = remoteMessage.getNotification().getTitle();
String body = remoteMessage.getNotification().getBody();
String click_action = remoteMessage.getNotification().getClickAction();
Context context = getApplicationContext();
Intent intent = new Intent(click_action);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("link",title);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0 , intent, PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.notification)
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(),R.drawable.notification))
.setContentTitle("Notification")
.setContentText(body)
.setSound(defaultSoundUri)
.setAutoCancel(true)
.setContentIntent(contentIntent);
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 , notificationBuilder.build());
}
OpenWeb.java
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(getIntent.getStringExtra("link"));
startActivity(intent);
}
AndroidManifest.xml
<activity android:name=".OpenWeb">
<intent-filter>
<action android:name="OpenWeb" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
When I click on notification the activity starts and getIntent.getStringExtra("link") in OpenWeb is null. That means the MyFirebaseMessagingService class doesn't send the data to the activity.
What should I do to send the data on OpenWeb ?
Well there is some problems with the code
1. in your php script you are not specifying any "body" but you are still calling String body = remoteMessage.getNotification().getBody(); thats one Null pointer exception.
2.This click_action key will work only when the app is in Foreground, for all other case when the app is in Background and closed, it doesn't work.
3.you need to set flags to start a new activity so intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
so if pending intent is firing youre ending up with an npe due to reason number 2, now you can do around this by sending data messages instead of the firebase sdk handling your notifications and then it will hallways be NONNULL
okay firebase has two types of messages
Push messages which are handled by the firebase SDK and that is messages that you set the title and the body and other factors but you cannot send custom data
data masseages has to be key-value pairs though.
as an example you want to send some data with your notification that the client app will handle for example you are sending some news about a sports match so you can create a node in JSON format saying
data: {
coolNews: "Some Cool News1",
coolNews2: "Some really cool news2"
}
and then you can call remoteMessage.getData().get("coolNews");
however be careful because if you send the following JSON
Notification:{
to: //UserToken ,
title: "Some Title",
body: "Some body",
data: {
coolNews: "Some Cool News1",
coolNews2: "Some really cool news2"
}}
The data payload will only be managed after the client open the notification, however if you send the whole notification json as a data payload and you handle everything on the client side it will all be received at the same time.
like the following:
Notification:{
to: //UserToken
data: {
title: "Some Title",
body: "Some body",
coolNews: "Some Cool News1",
coolNews2: "Some really cool news2"
}}
and then in your FirebaseMessageId you can call remotemessage.getData().get("title"); for the title and the same for all the others such as body and coolNews..
Now for the BroadCast recevier you can send broadcast through your firebasemessagingId as follows:
Intent intent = new Intent(this, NotificationBR.class);
Bundle bundle = new Bundle();
bundle.putDouble("key1",remoteMessage.getData().get("title"));
bundle.putDouble("key2",remoteMessage.getData().get("coolNews1"));
......
intent.putExtras(bundle);
sendBroadcast(intent);
and initiate a broadcast class and
DONT FORGET TO ADD TO YOUR MANIFEST!
something like this...
public class NotificationBR extends BroadCastReciever {
#Override
public void onReceive(Context ctx, Intent intent){
if(intent.getExtras() != null){
String key1 = intent.getStringExtra("key1");
......
}
//Then you can use intent to send it to whichever activity you want
Intent sendToActivity = new Intent(ctx, Activity.class);
sendToActivity.putExtras(someBundle) //Containing your strings you want to pass to activity, you can also use sendToActivity.putStringExtra("Some values")
startActivity(sendToActivity);
and thats it .
sorry about the typos..
I try to execute a function in my MainActivity when a notification is clicked.
The function needs a data that I put in intent extras.
The problem is when I click the notification when the application is running the function is executed, but when I click the notification when the application is in the background, the function isn't executed. I've checked it and it's because the data that I put in intent extras is empty when the application is in the background.
How can I solve this problem? Thanks!
This is the response i receive :
{
"to":"blablabla",
"notification": {
"body":"Sentiment Negative from customer",
"title":"Mokita"
},
"data" : {
"room_id":1516333
}
}
This is my notification code :
public void onMessageReceived(RemoteMessage message) {
super.onMessageReceived(message);
Log.d("msg", "onMessageReceived: " + message.getData().get("room_id"));
String roomId = message.getData().get("room_id");
Intent intent = new Intent(this, HomePageTabActivity.class);
intent.putExtra("fromNotification", true);
intent.putExtra("roomId", roomId);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
String channelId = "Default";
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(message.getNotification().getTitle())
.setContentText(message.getNotification().getBody())
.setAutoCancel(true)
.setContentIntent(pendingIntent);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId, "Default channel", NotificationManager.IMPORTANCE_DEFAULT);
manager.createNotificationChannel(channel);
}
manager.notify(0, builder.build());
}
}
And this is the function and how i executed it in MainActivity :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawer);
onNewIntent(getIntent());
}
#Override
public void onNewIntent(Intent intent){
Bundle extras = intent.getExtras();
if(extras != null){
if(extras.containsKey("fromNotification") || extras.containsKey("roomId")) {
openChatRoom(Long.valueOf(extras.getString("roomId")));
}else if(extras.containsKey("fromNotification") && extras.containsKey("roomId")){
openChatRoom(Long.valueOf(extras.getString("roomId")));
}else{
Log.e("EXTRAS room",""+extras.getString("roomId"));
Log.e("EXTRAS STATUS",""+extras.getBoolean("fromNotification"));
}
}else{
Toast.makeText(HomePageTabActivity.this,"Empty",Toast.LENGTH_SHORT).show();
}
}
public void openChatRoom(long roomId){
Log.d("LONG ROOM",""+roomId);
QiscusRxExecutor.execute(QiscusApi.getInstance().getChatRoom(roomId),
new QiscusRxExecutor.Listener<QiscusChatRoom>() {
#Override
public void onSuccess(QiscusChatRoom qiscusChatRoom) {
startActivity(GroupRoomActivity.
generateIntent(HomePageTabActivity.this, qiscusChatRoom));
}
#Override
public void onError(Throwable throwable) {
throwable.printStackTrace();
}
});
}
Firebase has two types of messages: notification messages and data messages. If you want FCM SDK to handle the messages by its own, you need to use notification. When the app is inactive, FCM will use notification body to display the messages. In this state, onMessageReceived also will not be triggered. If you want app to process the messages, you need to use data. You might need to change push notification payload from
{
"message":{
"token":"xxxxx:...",
"notification":{
"title":"Your title",
"body":"Your message"
}
}
}
to
{
"message":{
"token":"xxxxx:...",
"data":{
"title":"Your title",
"body":"Your message",
"fromNotification":"true",
"roomId":"123"
}
}
}
You also need to process the messages in onMessageReceived(RemoteMessage remoteMessage) accordingly. You can read about notification behaviour in Notifications and data messages.
these payloads will be delivered to the activity you are specifying in the pending intent. so when the user clicks on your notification, HomePageTabActivity launches and you can get the intent by calling getIntent() anywhere in activity lifecycle. but because you are setting singleTop flag on activity if HomePageTabActivity is already launched, Android will not launch it again and will pass the new Intent (provided in notification) to onNewIntent() instead. you can consume it there or even call the getIntent() to get the new value from there on.
Receive messages in an Android app. Messages with both notification and data payload, both background and foreground. In this case the data payload is delivered to extras of the intent of your launcher activity. If you want to get it on some other activity, you have to define click_action on the data payload. So get the intent extra in your launcher activity.
My Android application gets firebase notifications. And I need to localize this notifications depends on application language on the client side, not on server side.
If application is in foreground I use onMessageReceived() from FirebaseMessagingService and push my own localized notification. But if application is in background onMessageReceived() doesn't called.
In this case I use my own class extended BroadcastReceiver. onReceive(Context context, Intent intent) method catches notification, I localize it and push. Everything goes good, but in the end I get 2 push notifications: my own localized and firebase.
How can I get rid of this firebase notification and get only my own?
public class FirebaseDataReceiver extends BroadcastReceiver {
Context context;
PendingIntent pendingIntent;
public void onReceive(Context context, Intent intent) {
this.context = context;
Bundle dataBundle = intent.getExtras();
String title = "";
String body = "";
String type = "";
String objectId = "";
if (dataBundle != null) {
type = dataBundle.getString("type");
objectId = dataBundle.getString("objectId");
title = NotificationUtils.getNotificationTitle(context, dataBundle);
body = NotificationUtils.getNotificationBody(context, dataBundle);
}
Intent newIntent = new Intent(context, TutorialActivity_.class);
newIntent.putExtra("target", "notification");
newIntent.putExtra("type", type);
newIntent.putExtra("objectId", objectId);
newIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
pendingIntent = PendingIntent.getActivity(context,
0,
newIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new Notification.Builder(context)
.setContentTitle(title)
.setContentText(body)
.setPriority(Notification.PRIORITY_HIGH)
.setDefaults(Notification.DEFAULT_ALL)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setSmallIcon(R.drawable.splash_mini)
.build();
deleteLastNotification();
NotificationManagerCompat.from(context).notify(0, notification);
}
}
You should really use Data notifications from the server. Normal message notifications can't achieve this behaviour you're looking for. Check out the docs here:https://firebase.google.com/docs/cloud-messaging/concept-options
So your request to Firebase from the server should look something like this:
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
"Nick" : "Mario",
"body" : "great match!",
"Room" : "PortugalVSDenmark"
}
}
}
Instead of:
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"title":"Portugal vs. Denmark",
"body":"great match!"
}
}
}
I am using Firebase to send notification to my application. Please check the below code
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
private static int a=0;
/**
* Called when message is received.
*
* #param remoteMessage Object representing the message received from Firebase Cloud Messaging.
*/
// [START receive_message]
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// [START_EXCLUDE]
// There are two types of messages data messages and notification messages. Data messages are handled
// here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
// traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
// is in the foreground. When the app is in the background an automatically generated notification is displayed.
// When the user taps on the notification they are returned to the app. Messages containing both notification
// and data payloads are treated as notification messages. The Firebase console always sends notification
// messages. For more see: https://firebase.google.com/docs/cloud-messaging/concept-options
// [END_EXCLUDE]
// TODO(developer): Handle FCM messages here.
Log.d(TAG, "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
if (/* Check if data needs to be processed by long running job */ true) {
// For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
} else {
// Handle message within 10 seconds
handleNow();
}
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
sendNotification(remoteMessage.getNotification().getBody());
}
// Also if you intend on generating your own notifications as a result of a received FCM
// message, here is where that should be initiated. See sendNotification method below.
}
// [END receive_message]
/**
* Handle time allotted to BroadcastReceivers.
*/
private void handleNow() {
Log.d(TAG, "Short lived task is done.");
}
/**
* Create and show a simple notification containing the received FCM message.
*
* #param messageBody FCM message body received.
*/
private void sendNotification(String messageBody) {
Intent notificationIntent = new Intent(getApplicationContext(), DisplayNotificaiton.class);
notificationIntent.putExtra("message",messageBody);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, notificationIntent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.profile)
.setContentTitle("FCM Message")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(a++ /* ID of notification */, notificationBuilder.build());
}
}
This is working pretty fine but the case is when the phone is rebooted and when the app is not open, the messages being sent to device at that time do not display the icon or prompt the sound.
I know if I use the FireBase API I can send an icon and sound as well so everything will be taken from the URL, but Im trying to keep things simple for the moment and only use the Firebase console.
Therefor, how can I sort out this issue? The icon and sound will be fixed, nothing to change from message to message. At least the app logo will do fine.