I implemented my backend service (using java and FCM) to send push-notifications to mobile apps.
I implemented my service using Java Firebase Admin-SDK (https://firebase.google.com/docs/reference/admin/java/reference/com/google/firebase/messaging/package-summary and https://firebase.google.com/docs/cloud-messaging/send-message#java) about this and I'm able to send (and receive) push notifications on iOS and Android mobile apps.
Now I received a request from mobile-developers that they needs to customize (client-side) the received push notifications (also when the app is in background mode).
Probably here is reported a same question: What is the difference between Firebase push-notifications and FCM messages?
Reading the documentation (https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages) I understood that It's necessary to use a Data-message instead of a Notification message.
It's not clear for me what's necessary to change to support this delivery type.
Do I change the Android-config of the FCM-message or Do I remove some unnecessary data (just set all info into the custom data without others info for example Android configuration etc..)
It's possible to have a small example?
If your json will have notification key, developers will not able to handle notifications in background. They will receive this notification only when app is in foreground. In case when developers should receive “silent pushes” or they need control all notifications, you should remove notification key, and use only data key.
This can be achieved by changing the key 'notification' to 'data' as follows:
{
"notification": { //replace this line by "data"
"title": "Hey Gajanan",
"body": "Thanks for visiting omnidecoder.com"
},
"to" : "YOUR-GENERATED-TOKEN"
}
Related
In my application, I am offering video and voice calls between users. I'm using Firebase Realtime database and FCM as well to do so.
Here is the data that my notification is delivering:
data: {
channel_id: channel_id,
user_id: user_id
}
In my FirebaseMessagingService class, I retrieve the data and open the Video/Call activity like so:
if(remoteMessage.getData().size > 0) {
Intent intent = new Intent(this, VideoCallActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra("channel_id", remoteMessage.getData().get("channel_id"));
intent.putExtra("user_id", remoteMessage.getData().get("user_id"));
getApplicationContext().startActivity(intent);
}
Everything is working perfectly even when the application is in background. However, I'm facing this issue:
If an user didn't have internet connection when he was called, when he connects to internet his phone will automatically start the VideoCallActivity even if the call has been aborted (by the caller) and the notification removed from Firebase real time database.
So, please is there a way to cancel sent notifications, or know the delivery status of those notifications, or another way around to do so? That will allow me to add the list of missed calls for users.
Thanks!
In a scenario like this, I know of two options:
Send another FCM message when the call is cancelled
Only use FCM to send a tickle
Send another FCM message when the call is cancelled
One of the properties you can give an FCM message is an collapse_key. When you send a message with a collapse_key, that message replaces any previous message with the same collapse_key value.
You can use this to send a "nope, forget about it" message, when the user cancels the call.
Only use FCM to send a tickle
Alternatively you can have the FCM message just be a so-called tickle: an almost empty message, that just tells the app to wake up and go check its queue of incoming messages in the database.
That way: if the call is still in the database, the app can pick it up. But if there is no call in the database, it can just do nothing.
You'll want to do this type of database interaction in a service, so that it can run when the app is backgrounded.
Giving an expiration time is feasible as suggested in the documentation
Check Here
Setting the lifespan of a message
On Android and Web/JavaScript, you can specify the maximum lifespan of a message. The value must be a duration from 0 to 2,419,200 seconds (28 days), and it corresponds to the maximum period of time for which FCM stores and attempts to deliver the message. Requests that don't contain this field default to the maximum period of four weeks.
Here are some possible uses for this feature:
Video chat incoming calls
Expiring invitation events
Calendar events
Requirement is to sync mails from Gmail for an user into our CRM. The system in place is based on Google Pub/Sub which watches inbox of the user for any change and fires the notification to our HTTPs endpoint. More on this at Gmail cloud pub/sub.
Based on the above procedure we git history of changes. And then i am interested in only new messages, so history.getMessagesAdded is preferred as per this guide. Issue we are facing now is the first mail of a thread is not captured under messagesAdded all the subsequent messages are passing through our system.
Note: For the first mail, we do get push from Google. But when we try to get Messages added it turns out empty. Is there anything special needs to be done for the first mail of the thread or am i missing out something.
I was experiencing a very similar problem, and my mistake was that I was using the historyId from the push notification, the solution was to store the last known historyId on my database, so, every time I get a notification, I get the history from the id I have stored, not the one from the notification.
In my case, the historyId from the notification doesn't even make part of the history, maybe because of my watch restrictions: labelIds=['INBOX']
This is the google pub/sub notification:
{
message:
{
data: {"emailAddress": "user#example.com", "historyId": "9876543210"},
message_id: "1234567890",
}
subscription: "projects/myproject/subscriptions/mysubscription"
}
I was using the message.data.historyId, wich was causing the confusion!
The message.data, comes as a base64 encoded string, in this example I just decoded it!
Step by step for watching new e-mails on the inbox:
Do all the configuration in the google pub/sub.
Start watching the user with the filters you want (docs.: https://developers.google.com/gmail/api/v1/reference/users/watch)
Store the historyId obtained in the step 2
When receive the notification, get all the events (history) using the stored id as the startHistoryId parameter (docs: https://developers.google.com/gmail/api/v1/reference/users/history/list)
In the history list obtained on the step 4, look for the new messages: history.getMessagesAdded().
Update the last known history id in your database, so you don't need to deal with the whole history every time!
I hope it helps.
I am thinking about keeping all registration ids(push token) in DB and sending notifications to user from iPhone. I tried something like this but did not get any notification.
func sendPNMessage() {
FIRMessaging.messaging().sendMessage(
["body": "hey"],
to: TOKEN_ID,
withMessageID: "1",
timeToLive: 108)
}
What I am doing wrong or maybe it is impossible at all?
Currently it's not possible to send messages from the application itself.
You can send messages from the Firebase Web Console, or from a custom server using the server-side APIs.
What you might want to do is to contact a server (like via http call) and that server will send the message to the user.
This way ensure that the API-KEY of the server is protected.
PS: the sendMessage(..) api is called upstream feature, and can be used to send messages from your app to your server, if you server has an XMPP connection with the FCM server.
Yes you can send push notification through Firebase.Please make sure do NOT include the server-key into your client. There are ways "for not so great people" to find it and do stuff... The Proper way to achieve that is for your client to instruct your app-server to send the notification.
You have to send a HTTP-Post to the Google-API-Endpoint.
You need the following headers:
Content-Type: application/json
Authorization: key={your_server_key}
You can obtain your server key within in the Firebase-Project.
HTTP-Post-Content: Sample
{
"notification": {
"title": "Notification Title",
"text": "The Text of the notification."
},
"project_id": "<your firebase-project-id",
"to":"the specific client-device-id"
}
Google Cloud Functions make it now possible send push notifications from device-to-device without an app server.
From the Google Cloud Functions documentation:
Developers can use Cloud Functions to keep users engaged and up to
date with relevant information about an app. Consider, for example, an
app that allows users to follow one another's activities in the app.
In such an app, a function triggered by Realtime Database writes to
store new followers could create Firebase Cloud Messaging (FCM)
notifications to let the appropriate users know that they have gained
new followers.
Example:
The function triggers on writes to the Realtime Database path where followers are stored.
The function composes a message to send via FCM.
FCM sends the notification message to the user's device.
Here is a demo project for sending device-to-device push notifications with Firebase and Google Cloud Functions.
Diego's answer is very accurate but there's also cloud functions from firebase it's very convenient to send notifications in every change in the db. For example let's say you're building chat application and sending notification in every new follower change.
This function sample is very good example.
For more information about cloud functions you can check official docs.
I have an app that has a "send feedback to developer" section. I also have a User collection in my firestore database. When a user logs into the app, I have that Users data update their FCM token with the following code in my SceneDelegate.swift:
import Firebase
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
authListener = Auth.auth().addStateDidChangeListener({ (auth, user) in
Auth.auth().removeStateDidChangeListener(self.authListener!)
if user != nil {
DispatchQueue.main.async {
let docRef = Firestore.firestore().collection("User").document((user?.email)!)
docRef.getDocument { (snapshot, error) in
guard let snapshot = snapshot else {return}
Messaging.messaging().token { token, error in
if let error = error {
print("Error fetching FCM registration token: \(error)")
} else if let token = token {
docRef.updateData(["FCMtoken":token])
print("FCM registration token: \(token)")
}
}
}
}
}
})
guard let _ = (scene as? UIWindowScene) else { return }
}
then in my feedback view controller i have this code to send my specific device (but you can look up/fetch which specific device you want in your database where the FCMtoken is stored where i have INSERT-DEVICE-TOKEN-HERE). The url to send to is "https://fcm.googleapis.com/fcm/send" and you can find YOUR-APP-FCM-KEY by going to your project settings in firebase, going to cloud messaging tab and its the server key.
func sendMePushNotification() {
let token = "INSERT-DEVICE-TOKEN-HERE"
if let url = URL(string: "https://fcm.googleapis.com/fcm/send") {
var request = URLRequest(url: url)
request.allHTTPHeaderFields = ["Content-Type":"application/json", "Authorization":"key=YOUR-APP-FCM-KEY"]
request.httpMethod = "POST"
request.httpBody = "{\"to\":\"\(token)\",\"notification\":{\"title\":\"Feedback Sent!\",\"body\":\"\(self.feedbackBox.text!)\",\"sound\":\"default\",\"badge\":\"1\"},\"data\": {\"customDataKey\": \"customDataValue\"}}".data(using: .utf8)
URLSession.shared.dataTask(with: request) { (data, urlresponse, error) in
if error != nil {
print("error")
} else {
print("Successfully sent!.....")
}
}.resume()
}
}
Use onesignal,you can send device to notifications or device to segments ,it can work with firebase in this way
Use onesignal functions to create a specific id,save it in a firebase database ,then when the id can be put in another function that is used to send a notification
Notes: 1-i am using it in my apps with firebase works perfectly
2-i can submit that code,just someone comments so i can find this answer
I want to debug GCM messages which receives my application but the problem I can't log fields outside the data array: collapse key, time-to-live , etc. GCM message which comes from the server is look like this:
{
"registration_ids" : ["xyz"],
"data" : {
text: {...}
},
"time_to_live" : 3
},
For debugging purposes i want to log time-to live parameters and others.But when I do this: String text = intent.getExtras().getString("text"); I can only view what is inside data. How can I view all the GCM message structure?
I don't believe you can.
The parameters outside of data are not part of the notification payload. It's quite reasonable to believe that they are not even passed by the GCM server to your application. These outside params' only purpose is to tell the GCM server how to deliver the message (whether to send it to an idle device, how long to keep it in the GCM server when the device is not available, whether to override older undelivered messages that have the same collapse key, etc...).
EDIT :
Handling Received Data
The com.google.android.c2dm.intent.RECEIVE intent is used by GCM to deliver the messages sent by the 3rd-party server to the application running in the device. If the server included key-pair values in the data parameter, they are available as extras in this intent, with the keys being the extra names. GCM also includes an extra called from which contains the sender ID as an string, and another called collapse_key containing the collapse key (when in use).
From this quote, it seems you can also retrieve the collapse_key and the sender ID in addition to the key/value pairs inside data.
I know that the SMS content provider is not part of the public API (at least not documented), but if I understand correctly it's still possible to use many of the SMS features as long as you know how to use the API(?).
E.g it's pretty straightforward to insert an SMS into your inbox:
ContentValues values = new ContentValues();
values.put("address", "+457014921911");
contentResolver.insert(Uri.parse("content://sms"), values);
Unfortunately this does not trigger the standard "new-SMS-in-your-inbox" notification. Is it possible to trigger this manually?
Edit: AFAIK the "standard mail application (Messaging)" in Android is listening for incoming SMSes using the android.permission.RECEIVE_SMS permission. And then, when a new SMS has arrived, a status bar notification is inserted with a "special" notification id.
So one solution to my problem (stated above) could be to find, and send the correct broadcast intent; something like "NEW SMS HAS ARRIVED"-intent.
Edit: Downloaded a third party messaging application (chompsms) from Android market. This application satisfies my needs better. When i execute the code above the chompsms notice the new sms and shows the "standard status bar notification". So I would say that the standard Android Messaging application is not detecting sms properly? Or am I wrong?
Unfortunately the code responsible for these notifications is hidden in the messaging application. The class MessagingNotification has a static method updateAllNotifications that you could call using a PathClassLoader and reflection:
PathClassLoader c = new PathClassLoader("/system/app/Mms.apk", getClassLoader());
Class.forName("com.android.mms.util.ContactInfoCache", true, c)
.getMethod("init", Context.class).invoke(null, context);
Class.forName("com.android.mms.transaction.MessagingNotification", true, c)
.getMethod("updateAllNotifications", Context.class).invoke(null, context);
This is obviously a very bad idea for several reasons but I can't think of another way to do what you described.
Could you trigger a PUSH notification after the SMS?
Thread: Does Android support near real time push notification?
Maybe you should replace
content://sms
with
content://sms/inbox