I am trying to send notifications to users in Android Application, written in Java, using Firebase Functions, but I am still getting this error in the Firebase Functions Console Log:
Error: Messaging payload contains an invalid value for the "notification.title" property. Values must be strings.
at FirebaseMessagingError.Error (native)
at FirebaseMessagingError.FirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:25:28)
at new FirebaseMessagingError (/user_code/node_modules/firebase-admin/lib/utils/error.js:130:23)
at /user_code/node_modules/firebase-admin/lib/messaging/messaging.js:486:27
at Array.forEach (native)
at /user_code/node_modules/firebase-admin/lib/messaging/messaging.js:483:32
at Array.forEach (native)
at Messaging.validateMessagingPayload (/user_code/node_modules/firebase-admin/lib/messaging/messaging.js:476:21)
at /user_code/node_modules/firebase-admin/lib/messaging/messaging.js:313:37
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
Here is my Function:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.pushNotification = functions.database.ref('/messages/send').onWrite(
event => {
console.log('Push notification event triggered');
event.data.adminRef.parent.once('value').then((snapshot) => {
var valueObject = snapshot.val();
const payload = {
notification: {
title: JSON.stringify(valueObject.title),
body: JSON.stringify(valueObject.message),
click_action: ".WebsiteActivityNotification",
sound: "default"
},
data: {
title: JSON.stringify(valueObject.title),
message: JSON.stringify(valueObject.message),
link: JSON.stringify(valueObject.link)
}
};
const options = {
priority: "high",
timeToLive: 60 * 60 * 24 //24 hours
};
return admin.messaging().sendToTopic("notifications", payload, options);
});
});
Here is my Firebase Database structure:
/messages
link: "..."
message: "..."
title: "..."
send: "..."
Here is my Service:
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
public class FCMService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
String notificationTitle = null, notificationBody = null;
String dataTitle = null, dataMessage = null, dataLink = null;
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData().get("message"));
dataTitle = remoteMessage.getData().get("title");
dataMessage = remoteMessage.getData().get("message");
dataLink = remoteMessage.getData().get("link");
}
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
notificationTitle = remoteMessage.getNotification().getTitle();
notificationBody = remoteMessage.getNotification().getBody();
}
sendNotification(notificationTitle, notificationBody, dataTitle, dataMessage, dataLink);
}
private void sendNotification(String notificationTitle, String notificationBody, String dataTitle, String dataMessage, String dataLink) {
Intent intent = new Intent(this, WebsiteActivityNotification.class);
intent.putExtra("title", dataTitle);
intent.putExtra("message", dataMessage);
intent.putExtra("link", dataLink);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(notificationTitle)
.setStyle(new NotificationCompat.BigTextStyle().bigText(notificationBody))
.setContentText(notificationBody)
.setAutoCancel(true)
.setPriority(Notification.PRIORITY_HIGH)
.setDefaults(Notification.FLAG_AUTO_CANCEL | Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}
Activity to open tag in Manifest:
<activity
android:name=".WebsiteActivityNotification"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name=".WebsiteActivityNotification" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Services tags in Manifest:
<service android:name=".FCMService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<service android:name=".FirebaseIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
And still doesn't work...
Every answer is welcomed. Thank you very much!
Related
in AndroidManifest.xml
<service
android:name=".CustomFirebaseInstanceIDService"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service
android:name=".CustomFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
My service:
import android.util.Log
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import org.tokend.template.BuildConfig
class CustomFirebaseMessagingService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage?) {
if (remoteMessage?.data?.isNotEmpty()!!) {
val payloadData: Map<String, String> = remoteMessage.data
PushNotificationService.showNotification(applicationContext, payloadData["title"]!!, payloadData["body"]!!)
}
// Check if message contains a notification payload.
remoteMessage.notification?.let {
val notificationTitle : String? = it.title
val notificationBody: String? = it.body
PushNotificationService.showNotification(applicationContext, notificationTitle!!, notificationBody!!)
}
}
And show push:
object PushNotificationService {
val TAG = PushNotificationService::class.java.name
val CHANNEL_ID = "channelId"
val NOTIFICATON_ID = 1
fun showNotification(context: Context, title: String, body: String) {
val intent = Intent(context, SignInActivity::class.java).apply {
this.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(),
R.mipmap.ic_launcher))
.setContentTitle(title)
.setStyle(NotificationCompat.BigTextStyle().bigText(body))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
// Set the intent that will fire when the user taps the notification
.setContentIntent(pendingIntent)
.setAutoCancel(true)
// Show the notification
with(NotificationManagerCompat.from(context), {
// NOTIFICATON_ID is a unique int for each notification that you must define
this.notify(NOTIFICATON_ID, builder.build())
})
}
So:
when server send data or notification and application is run and foreground then method onMessageReceived success call and success show push notification (title and body) in the status bar (on top)
when server send data or notification and application is run and minimize then method onMessageReceived success call and success show push notification in the status bar (on top)
But when server send data or notification and application is NOT RUNNING then not call method onMessageReceived and also not show push notification on the status bar.
But I need to show push notification on the status bar when app is not running.
I send data message to my android device by Python script:
import firebase_admin, sys
from firebase_admin import credentials, messaging
message = messaging.Message(
data={
"title": "Test data",
"body": "Body of long test text of data test long body message for type data"
},
token=sys.argv[1],
)
response = messaging.send(message)
P.S. If I send message from Firebase console then success show push notification on status bar when app is not running.
Try to only send data payload (without notification payload) it should always call onMessageReceived. Also try adding priority (my .js example):
const payload = {
data: {
title: 'finalTitle',
body: 'message',
},
android:{
priority: 'high'
},
topic: channel
};
admin.messaging().send(payload)
i'm new to firebase cloud function and fcm, My situation is Whenever a new article is published in the database, I need to show the notification to my app user.
firebase cloud function worked perfectly but notification not received by device android.
cloud function
var functions = require('firebase-functions');
var admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/Vacancy/{articleId}')
.onWrite((event: { after: any; }) => {
console.log("Successfully sent message:2");
var eventSnapshot = event.after;
var str1 = "Author is ";
var str = str1.concat(eventSnapshot.child("author").val());
console.log(str);
var topic = "android";
var payload = {
data: {
title: eventSnapshot.child("title").val(),
author: eventSnapshot.child("author").val()
}
};
return admin.messaging().sendToTopic(topic, payload)
.then(function (response: any) {
console.log("Successfully sent message:", response);
})
.catch(function (error: any) {
console.log("Error sending message:", error);
});
});
manifess code
<service
android:name=".ServiceNotification.NotificationMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
NotificationMessagingService class code
public class NotificationMessagingService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
FirebaseMessaging.getInstance().subscribeToTopic("android");
if (remoteMessage.getData().size() > 0) {
showNotification(remoteMessage.getData().get("title"), remoteMessage.getData().get("author"));
}
if (remoteMessage.getNotification() != null) {
}
}
private void showNotification(String title, String author) {
Intent intent = new Intent(this, HomeActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setContentTitle("New Article: " + title)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentText("By " + author)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}
cloud function log
1:33:46.257 AM
sendNotification
Successfully sent message:2
1:33:46.263 AM
sendNotification
Author is Raja
1:33:47.022 AM
sendNotification
Successfully sent message: { messageId: 5711725841493019000 }
1:33:47.040 AM
sendNotification
Function execution took 1005 ms, finished with status: 'ok'
i'm using FCM and follow instructions on firebase site but notifications not working when app in background
i already sync gradle library and download json file and sync done but not notifications recieved when app in background
app gradle
dependencies {
///////
}
apply plugin: 'com.google.gms.google-services'
dependencies {
classpath 'com.android.tools.build:gradle:3.5.1'
classpath 'com.google.gms:google-services:4.3.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
You have to add
classpath 'com.android.tools.build:gradle:3.5.1'
classpath'com.google.gms:google-services:4.3.2'
in project gradle and google plugin in app gradle file.
Then add the following dependencies:
implementation 'com.google.firebase:firebase-core:17.2.0'
implementation 'com.google.firebase:firebase-messaging:19.0.0'
You need to create a service of FCM to recieve notifications.
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private NotificationManager notificationManager;
private static final String ADMIN_CHANNEL_ID = "CHANNEL_ID";
#Override
public void onNewToken(String s) {
super.onNewToken( s );
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived( remoteMessage );
Map<String, String> data = remoteMessage.getData();
String body = data.get("body");
String title = data.get("title");
String image = data.get("image");
notificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
setupChannels( title, body );
}
Log.d( "Notification", "onMessageReceived: " + image);
Intent notificationIntent = new Intent(this, NotificationActivity.class);
notificationIntent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP );
PendingIntent pendingIntent = PendingIntent.getService( this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT );
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder( this, ADMIN_CHANNEL_ID )
.setSmallIcon( R.drawable.ic_launcher_background )
.setContentTitle( remoteMessage.getNotification( ).getTitle( ) )
.setContentText( remoteMessage.getNotification( ).getBody( ) )
.setContentIntent( pendingIntent );
NotificationManager notificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE );
notificationManager.notify( 0, notificationBuilder.build( ) );
}
#RequiresApi(api = Build.VERSION_CODES.O)
private void setupChannels(String adminChannelName, String adminChannelDescription) {
NotificationChannel adminChannel;
adminChannel = new NotificationChannel( ADMIN_CHANNEL_ID, adminChannelName, NotificationManager.IMPORTANCE_LOW );
adminChannel.setDescription( adminChannelDescription );
adminChannel.enableLights( true );
adminChannel.setLightColor( Color.RED );
adminChannel.enableVibration( true );
if (notificationManager != null) {
notificationManager.createNotificationChannel( adminChannel );
}
}
}
And add this code to your manifest:
<service
android:name=".MyFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
There are several steps for achieving the notification when application is in background.
You need to use POST parameter in Android FCM service.
You need to code down the thing inside onMessageReceived() from FCM dependencies.
https://firebase.google.com/docs/cloud-messaging/android/receive#handling_messages
because i just send notification without message body
i tried solution i just found that i forget this gradle library
implementation 'com.google.firebase:firebase-messaging:20.0.0'
I am working on an Android app and by using Node.js based function, I'm sending notification to Android and in Android onMessageReceived() function is used to receive data to show notifications. Now the problem, I'm facing is that I want to send some String type data in parallel to Title and Body. What changes should I make?
Here is my Node.js code
'use-strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.firestore.document("Users/{user_id}/Notifications/{notification_id}").onWrite((change,context)=> {
const user_id = context.params.user_id;
const notification_id = context.params.notification_id;
console.log("User ID:"+user_id+" | Notification ID:"+notification_id);
return admin.firestore().collection("Users").doc(user_id).collection("Notifications").doc(notification_id).get().then(queryResult =>{
const from_user_id = queryResult.data().from;
const from_message = queryResult.data().Message;
const from_data = admin.firestore().collection("Users").doc(from_user_id).get();
const to_data = admin.firestore().collection("Users").doc(user_id).get();
return Promise.all([from_data,to_data]).then(result =>{
const from_name = result[0].data().Name;
const to_name = result[1].data().Name;
const token_id = result[1].data().Token_ID;
const payload = {
notification: {
title: "Hey! "+from_name+" here",
body: "Dear "+to_name+", "+from_message+", Will you help me?",
icon: "default"
}
};
return admin.messaging().sendToDevice(token_id,payload).then(result =>{
return console.log("Notification Sent.");
});
});
});
});
And Here is my android code:
public class FirebaseMsgService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
String messageTitle = remoteMessage.getNotification().getTitle();
String messageBody = remoteMessage.getNotification().getBody();
Uri sound = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.enough);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, getString(R.string.default_notification_channel_id))
.setSmallIcon(R.drawable.logo)
.setContentTitle(messageTitle)
.setSound(sound)
.setContentText(messageBody)
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(messageBody))
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
int mNotificationID = (int) System.currentTimeMillis();
NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNotificationManager.notify(mNotificationID,mBuilder.build());
}
}
While I know squad about nodejs (or js in general) I got this working yesterday by passing a data object in the payload.
So, the json request that google makes (I'm using GCM still, but I'm sure FCM would be the same, or very similar payload) looks like this:
{
"to": "<GCM/FCM token>",
"priority": "normal",
"android_channel_id": -99,
"data": {
"title": "Some title",
"body": "Some body",
"more_data_one": "Some more data",
"more_data_two": "Some more data, again!"
}
}
Somehow, however, if I send both data and notification in the payload, the GCMServiceListener never gets called, and the app just displays whatever is in the notification portion of the payload.
By adding the data section (and therefore making the notification a "silent" notification), you are then on charge of intercepting the message, and displaying it with the Notification builder.
I'm trying to use FCM to send notifications. I'm building an app using Xamarin, so I followed this tutorial to set up my notifications.
Here my firebase service:
[Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class MyFirebaseIIDService : FirebaseInstanceIdService
{
const string TAG = "MyFirebaseIIDService";
public override void OnTokenRefresh()
{
var refreshedToken = FirebaseInstanceId.Instance.Token;
System.Diagnostics.Debug.WriteLine(TAG, "Refreshed token: " + refreshedToken);
SendRegistrationToServer(refreshedToken);
}
void SendRegistrationToServer(string token)
{
// Add custom implementation, as needed.
}
}
[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class MyFirebaseMessagingService : FirebaseMessagingService
{
const string TAG = "MyFirebaseMsgService";
public override void OnMessageReceived(RemoteMessage message)
{
Android.Util.Log.Debug(TAG, "From: " + message.From);
Android.Util.Log.Debug(TAG, "Notification Message Body: " + message.GetNotification().Body);
}
void SendNotification(string messageBody)
{
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity(this, 0 /* Request code */, intent, PendingIntentFlags.OneShot);
var defaultSoundUri = RingtoneManager.GetDefaultUri(RingtoneType.Notification);
var notificationBuilder = new NotificationCompat.Builder(this)
.SetContentTitle("FCM Message")
.SetContentText(messageBody)
.SetAutoCancel(true)
.SetSound(defaultSoundUri)
.SetContentIntent(pendingIntent);
var notificationManager = NotificationManager.FromContext(this);
notificationManager.Notify(0, notificationBuilder.Build());
}
}
I had an issue with the refresh token malfunctioning from time to time so I added this to my MainActivity:
if (IsPlayServicesAvailable())
{
var json = "";
using (StreamReader sr = new StreamReader(Assets.Open("google_services.json")))
{
json = sr.ReadToEnd();
}
var options_from_json = JObject.Parse(json);
try
{
var options = new FirebaseOptions.Builder()
.SetApplicationId(options_from_json["client"][0]["client_info"]["mobilesdk_app_id"].ToString())
.SetApiKey(options_from_json["client"][0]["api_key"][0]["current_key"].ToString())
//.SetDatabaseUrl("Firebase-Database-Url")
.SetGcmSenderId(options_from_json["project_info"]["project_number"].ToString())
.Build();
var firebaseApp = FirebaseApp.InitializeApp(this, options);
}
catch (IllegalStateException e)
{
System.Diagnostics.Debug.WriteLine("L'app firebase existe déjà, donc il n'y a rien à faire.");
}
await Task.Run(() =>
{
var instanceID = FirebaseInstanceId.Instance;
var iid1 = instanceID.Token;
var iid2 = instanceID.GetToken(options_from_json["project_info"]["project_number"].ToString(), Firebase.Messaging.FirebaseMessaging.InstanceIdScope);
System.Diagnostics.Debug.WriteLine("Iid1: {0}, iid2: {1}", iid1, iid2);
});
}
Fine, so far I've got token for emulators as well as real life devices.
My problem is the reception of notification: it's really hazardous, sometime I get some an instant after I hit send on FCM console, sometime I have to reboot the device, sometime it just takes hours to arrive and sometime I just receive nothing... My setup doesn't change and the devices aren't on a wifi.
Any clues?