Now I can send test message from Firebase Console and get a push notification in my phone. I have some queries about generating in-app notification right now. This is my current layout.
I want the push notifications to appear as in-app notifications in my app too. The only class handling the message is MyFirebaseMessagingService class which includes a notificationHelper to help build the notification. How do I pass the message information from MyFirebaseMessagingService to the Notification Fragment I have now? Do I need to store the information in a local file then retrieve the information from the local file to be used in Notification Fragment again? What is the best approach in this case?
public class MyFirebaseMessagingService extends FirebaseMessagingService {
#Override
public void onMessageReceived(#NonNull RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
if (remoteMessage.getNotification() != null) {
String title = remoteMessage.getNotification().getTitle();
String body = remoteMessage.getNotification().getBody();
NotificationHelper.displayNotification(getApplicationContext(), title, body);
}
}
}
Another trivial question is about the FCM token issue. I have already created a FCM token. How do I make the app to check if a token has been generated to prevent the token be generated every time I launch the app?
if(instanceIdResult.getToken() == null)
{
//generate token
}
Can I write the code like this?
You can use room database. You save all the notifications and then show them in the fragment. If the fragment is already show, you can send and show instantly with broadcastReceiver. Room
FCM token is created once. The registration token may change when:
The app deletes Instance ID
The app is restored on a new device
The user uninstalls/reinstall the app
The user clears app data.
You can retrieve the current token like this:
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
#Override
public void onComplete(#NonNull Task<InstanceIdResult> task) {
if (!task.isSuccessful()) {
Log.w(TAG, "getInstanceId failed", task.getException());
return;
}
String token = task.getResult().getToken();
}
});
you can use sharedpreferences to store number of notifications you get and when yor app opens show the number on notification and if user read them reset the counter . also you can store the token too
Related
I have deployed the following firebase function for implementing push notifications in my cloud firestore chat app. I am doing this for the first time after watching this tutorial.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotificationToTopic = functions.firestore.document('chats/{roomid}/messages/{uid}').onWrite(async(event)=>{
let content = event.after.get('message')
var message ={
notification: {
title: 'You have an unread message',
body: content,
},
topic:'namelesscoder',
};
});
While testing the function, the log shows the function to be properly working without any errors, however my device isn't actually getting the notification. Is this because of the way I have declared the database structure? The path in code mentioned above is where is store my chat messages.
This function will send push notifications to a topic (group of users who are subscribed to a topic) rather than a specific user. In case you want to send notification to a group of users, you can use this function and your users must be subscribed to topic. In this function, topic is 'namelesscoder', so your user needs to be subscribed to this topic.
If you are on android, write following code to subscribe to topic 'namelesscoder'
FirebaseMessaging.getInstance().subscribeToTopic("namelesscoder")
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
String msg = "subscribed to topic nameless coder.";
if (!task.isSuccessful()) {
msg = "Failed to subscribe to topic";
}
Log.d(TAG, msg);
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
});
In case you wanna send notification to a specific user, you must send it to a FCM token.
I am using FCM in my project and when trying to test the incoming notifications with the firebase "compose notification" feature I am putting a title, a body and an image URL to the message and it shows what it should look like - a rich notification with image. But the notification that is being sent to me is a normal one without any image.
here is the firebase UI and what is suposed to happen -
My issue is that I am getting only the text, without the image.
here is my MyFirebaseMessagingService class -
public class MyFirebaseMessagingService extends FirebaseMessagingService {
public static final String RECEIVED_FCM_ACTION = "com.onemdtalent.app.RECEIVED_FCM_ACTION";
public static final String BD_KEY_BODY = "BD_KEY_BODY";
#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]
String image = remoteMessage.getData().get("image");
Timber.d("onMessageReceived: %s", remoteMessage.getFrom());
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
String body = remoteMessage.getNotification().getBody();
Timber.d("Message Notification Body: %s", body);
// broadcast
Intent localIntent = new Intent(RECEIVED_FCM_ACTION);
localIntent.putExtra(BD_KEY_BODY, image);
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
}
}
}
As I sayed, I am getting only the text without the image. what am I missing?
Solved - I used an old version of firebase messaging dependency and I updated it, including my entire project to androidX and now I can see the images :)
I am using cloud messaging from firebase with my android app, I am trying to receive a realtime update without refreshing the activity and getting data from the database, so when a user sends another user a message, this last user will receive a notification, anyone knows how to guide me in the right direction?
In the Firebase service FirebaseMessagingService you implement the method onMessageReceived in such a way that lets you update the chat based on the infos in the notification.
For example, to get the data needed from the notification message:
String sender = null;
int chatId;
String msg = null;
public void onMessageReceived(RemoteMessage remoteMessage) {
//YOU NEED TO USE DATA MESSAGES TO CARRY ALL THE INFORMATION ABOUT THE MESSAGE
Map<String,String> data = remoteMessage.getData();
title = data.get("sender");
msg = data.get("body");
chatId = data.get("chatId");
//this function implements the updating of the chat with the new message received
updateChat(chatId,sender,msg);
}
This code example is based on a push notification message data payload that looks like:
{
"Message": {
"Token": client_device_token,
"Data": {
"sender": "John",
"chatId": chatId_between_me_and_Jhon,
"body": "Hi you, this is John"
}
}
}
The implementation of the method updateChat(chatId,sender,msg) is up to you and depends on the logic of your app and your database.
I have just migrated to FCM. I have added my class that extends from FirebaseInstanceIdService to receive a refreshedToken as and when appropriate.
My question is specific to the case when user installs my app first time and due to some reason, unable to receive a registration Id from onTokenRefresh. How are we supposed to handle this? Can I set a broadcast receiver from my FirebaseInstanceIdService class which will notify the Main activity when a registration Id is received?
if your device have no connection to the internet onTokenRefresh() is never called and you should notify to user his/her device has no internet connection
firebase has its own network change listener and when a device connected to the internet then try to get token and return it, at this time you can tell your main activity by sending a local broadcast receiver that registration token is received.
use below codes:
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d("FCN TOKEN GET", "Refreshed token: " + refreshedToken);
final Intent intent = new Intent("tokenReceiver");
// You can also include some extra data.
final LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
intent.putExtra("token",refreshedToken);
broadcastManager.sendBroadcast(intent);
}
in your main activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
LocalBroadcastManager.getInstance(this).registerReceiver(tokenReceiver,
new IntentFilter("tokenReceiver"));
}
BroadcastReceiver tokenReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String token = intent.getStringExtra("token");
if(token != null)
{
//send token to your server or what you want to do
}
}
};
}
Change this in manifest.xml file
tools:node="replace"
to
tools:node="merge".
As far as I know, token will be null only when you try to run your app on emulator on which google play service is not there and when you are using dual email id on you google play store(on you actual device), but only one email id is verified for the usage. Those are the cases which will give you null token and I have already implemented FCM in my new project. So for rest of any cases , token won't be null.
Use this class extends with..
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
private static final String TAG = "MyFirebaseIIDService";
public static final String REGISTRATION_SUCCESS = "RegistrationSuccess";
#Override
public void onTokenRefresh() {
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
Toast.makeText(MyFirebaseInstanceIDService.this,refreshedToken,Toast.LENGTH_LONG).show();
}
}
I was facing the same problem. I looked through a lot of SO posts and other forums and I found a solution that worked for me. FCM documentation says to use this method to get a token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
I found a post online (I apologize, I don't remember which one. I found it a while ago) that used this method instead:
String refreshedToken = FirebaseInstanceId.getInstance().getToken() (String authorizedEntity, String scope);
FCM documentation describes the first method as:
Return the master token for the default Firebase project.
While the second one is described as:
Returns a token that authorizes an Entity to perform an action on behalf of the application identified by Instance ID.
This is similar to an OAuth2 token except, it applies to the application instance instead of a user.
For example, to get a token that can be used to send messages to an application via FirebaseMessaging, set to the sender ID, and set to "FCM".
I have been looking into why the first method call takes a longer time to return a token, but I haven't found an answer yet. Hope this helps.
depending on your application logic you can write the code to handle the "new" token directly in the FirebaseInstanceIdService.onTokenRefresh() method, or you can use a LocalBroadcast to send this information to your activity if you need to change the UI when this event happens.
Note that when onTokenRefresh() is called your activity could be closed.
A possible implementation could a mix of the two options:
add some logic in onTokenRefresh() to send the token to your server
use a LocalBroadcastReceiver to inform your activity, if you have a piece of UI that need to change when the token is available.
If you are running it on your emulator, check that you have Google play services enabled in Tools -> Android -> SDK Manager -> SDK Tools -> Google play services
Once installed, reboot both Android Studio and your emulator
It worked for me
I'm using intercom.io to send messages to my customers. I can receive gcm (with notification) from intercom just fine, ONLY if the message that I sent is the first message in a conversation. For subsequent messages in the conversation, I don't receive anything. I put a log in my onMessageReceived() but it didn't receive anything, except if the message is the first message in a conversation.
public class MyGcmListenerService extends GcmListenerService {
#Override
public void onMessageReceived(String from, Bundle data) {
MessageUtils.log("onMessageReceived data is " + data);
}
}
Any idea what am I missing?
In case you don't get what I'm trying to say, here's what I meant:
I select a customer from my intercom.io web dashboard (or
whatever it's called)
Then I click on the 'Message' button to
send a message to the customer.
The customer received my message, together with the notification.
Now I send another message to the customer within the same conversation as before.. but now the customer won't receive any more gcm message from intercom.
Yes it does support now. The github issue is closed now and they added it in 3.0.3
They have a git hub project for FCM, but it is missing few code.
The code is available on this github page and is as follows
if you are extending FirebaseMessagingService in a class in your own app? then you will need to manually pass on the push to intercom now.
private final IntercomPushClient intercomPushClient = new IntercomPushClient();
public void onMessageReceived(RemoteMessage remoteMessage) {
Map<String, String> message = remoteMessage.getData();
if (intercomPushClient.isIntercomPush(message)) {
intercomPushClient.handlePush(getApplication(), message);
} else {
//DO HOST LOGIC HERE
}
}