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!"
}
}
}
Related
I have successfully developed a chat app using java and firebase and I am stuck at sending and receiving chat notifications when chatting with a friend who has install my app. i have tried using FCM but to no avail. I have written the code and when i send a message, the friend doesn't receive a notification whether app is in foreground or background as well as no errors are found. please help me out. Below is the code for that class that extends the FirebaseMessagingService.
#SuppressLint("MissingFirebaseInstanceTokenRefresh")
public class NotifyFirebaseMessaging extends FirebaseMessagingService {
#Override
public void onMessageReceived(#NonNull #NotNull RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
String sent = remoteMessage.getData().get("sent");
String user = remoteMessage.getData().get("user");
SharedPreferences preferences = getSharedPreferences("PREFS", MODE_PRIVATE);
String currentUser = preferences.getString("currentuser", "none");
FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
if(firebaseUser != null && sent.equals(firebaseUser.getUid())) {
if (!currentUser.equals(user)) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
sendOreoNotification(remoteMessage);
}
else{
sendNotification(remoteMessage);
}
}
}
}
#RequiresApi(api = Build.VERSION_CODES.O)
private void sendOreoNotification(RemoteMessage remoteMessage){
String user = remoteMessage.getData().get("user");
String icon = remoteMessage.getData().get("icon");
String title = remoteMessage.getData().get("title");
String body = remoteMessage.getData().get("body");
RemoteMessage.Notification notification = remoteMessage.getNotification();
assert user != null;
int j = Integer.parseInt(user.replaceAll("[\\D]", ""));
Intent intent = new Intent(this, ChatActivity.class);
Bundle bundle = new Bundle();
bundle.putString("userid", user);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, j, intent,PendingIntent.FLAG_ONE_SHOT);
Uri defaultSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
OreoNotification oreoNotification = new OreoNotification(this);
Notification.Builder builder = oreoNotification.getOreoNotification(title,body,pendingIntent,defaultSound,icon);
int i = 0;
if(j>0){
i = j;
}
oreoNotification.getManager().notify(i, builder.build());
}
private void sendNotification(RemoteMessage remoteMessage) {
String user = remoteMessage.getData().get("user");
String icon = remoteMessage.getData().get("icon");
String title = remoteMessage.getData().get("title");
String body = remoteMessage.getData().get("body");
RemoteMessage.Notification notification = remoteMessage.getNotification();
assert user != null;
int j = Integer.parseInt(user.replaceAll("[\\D]", ""));
Intent intent = new Intent(this, ChatActivity.class);
Bundle bundle = new Bundle();
bundle.putString("userid", user);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, j, intent,PendingIntent.FLAG_ONE_SHOT);
Uri defaultSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setSmallIcon(Integer.parseInt(icon))
.setContentTitle(title)
.setContentText(body)
.setAutoCancel(true)
.setSound(defaultSound)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
int i = 0;
if(j>0){
i = j;
}
notificationManager.notify(i, builder.build());
}
}
I think you may be confused about what your sendNotification does. As far as I can tell, the code you shared only receives a message from Firebase Cloud Messaging and then displays it in the notification tray of the local device.
None of the code sends a message to Firebase Cloud Messaging, which is actually only supported from trusted environments (such as your development machine, a server you control, or Cloud Functions/Cloud Run) and not from within your client-side application code.
You can also send a message from within the Firebase console, which is great for testing receipt and for targeted messaging campaigns.
To learn more about this, I recommend checking out:
How to send one to one message using Firebase Messaging
How to send Device to device notification by using FCM without using XMPP or any other script.?
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 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 MyFirebaseMessagingService.
public class MyFirebaseMessagingService
extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "FRCM:"+ remoteMessage.getFrom());
/*Check if the message contains data*/
if(remoteMessage.getData().size() > 0){
Log.d(TAG,"Message data: "+ remoteMessage.getData());
}
/*Check if the message contains notification*/
if(remoteMessage.getNotification() != null){
Log.d(TAG,"Message body: "+ remoteMessage.getNotification().getBody());
sendNotification(remoteMessage.getNotification().getBody());
}
}
/*Display Notification Body*/
private void sendNotification(String body) {
Intent intent = new Intent(this, Home.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0/*Request code*/, intent, PendingIntent.FLAG_ONE_SHOT);
/*Set sound of Notification*/
Uri notificationSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notifiBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_event_note_black_24dp)
.setContentTitle("Firebase Cloud Messaging")
.setContentText(body)
.setAutoCancel(true)
.setSound(notificationSound)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0/*ID of notification*/, notifiBuilder.build());
intent = new Intent("myAction");
intent.putExtra("title", title);
intent.putExtra("message", message);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
and My Activity Messaging is.
public class Mess{
}
You send messages from your phone using FCM. You need to make a POST to https://fcm.googleapis.com/fcm/send api with payload that you want to send, and you server key found in Firebase Console project or You can Use POSTMAN google chrome extension
As an exameple of payload sending to a single user with to param:
{ "data": {
"score": "5x1",
"time": "15:10"
},
"to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1..."
}
Also, to param can be used for topics "to": "topics/yourTopic"
In data you can send whatever you want, message is received in onMessageReceived() service from Firebase.
More details you can found in Firebase documentation.
For sending data to another activity
private void sendNotification(String body) {
Intent intent = new Intent(this, Home.class);
here you can set intent
intent.putExtra("word", body);
and to read from activity use
b = getIntent().getExtras();
String passed_from = b.getString("word");
I am working on an android app where I need to get incoming message from whatsapp or any other chatting app and then reply to that message using my app.
I am able to extract message and other data from notification using NotificationListener Service, but I don't know how to reply to that notification from my app.
I got all the information using the following method of NotificationListener Class.
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
super.onNotificationPosted(sbn);
Intent intent = new Intent(this, ChatHeadService.class);
startService(intent);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
String key = sbn.getKey(); // notification key
PendingIntent intent1 = sbn.getNotification().contentIntent; // pending intent
String pack = sbn.getPackageName(); // package name of app
Bundle noti = sbn.getNotification().extras; // extra bundle of notification
String name = noti.getString("android.title"); // name of the sender
Bitmap img = sbn.getNotification().largeIcon; // the icon of the sender user
CharSequence[] textlines = noti.getCharSequenceArray("android.textLines");
if (textlines != null)
Log.i("textlines", textlines.toString());
Now I need to reply to the above notification!