Using Ruby to send notification to Firebase - android

I am using Ruby version 1.8.7.
I use this FCM gem https://github.com/spacialdb/fcm and want to send notification message to Android client app but it does not work.
In Controller:
fcm = FCM.new(FIREBASE_API_KEY, :timeout => 30)
options = {:data => {:message => "This is a FCM Topic Message!"}}
response = fcm.send_to_topic('global', options)
Class FCM:
require 'httparty'
require 'cgi'
require 'json'
class FCM
include HTTParty
base_uri 'https://fcm.googleapis.com/fcm'
default_timeout 30
format :json
attr_accessor :timeout, :api_key
def initialize(api_key, client_options = {})
#api_key = api_key
#client_options = client_options
end
def send_with_notification_key(notification_key, options = {})
body = { :to => notification_key }.merge(options)
params = {
:body => body.to_json,
:headers => {
'Authorization' => "key=#{#api_key}",
'Content-Type' => 'application/json'
}
}
response = self.class.post('/send', params.merge(#client_options))
response.parsed_response
end
def send_to_topic(topic, options = {})
if topic =~ /[a-zA-Z0-9\-_.~%]+/
send_with_notification_key('/topics/' + topic, options)
end
end
end
The server key is correct, because I can send notification successfully by PHP code.
The response output as below:
{"message_id"=>8885803884270587181}
Could anyone please to point out what wrong with the code.
Any help would be greatly appreciated.

According to the Firebase API documentation the response you get is the expected response for a successfully queued message.
The fact that you get back a message_id has this meaning:
The topic message ID when FCM has successfully received the request and will attempt to deliver to all subscribed devices.
It looks like your code is working, i.e. the problem must be somewhere else.
EDIT:
You are sending a data message. (Because no notification key, just a data key) Perhaps your client expects a notification message instead?
See the documentation for the distinction between those two message types.
You can try and just add a notification key to the request:
fcm = FCM.new(FIREBASE_API_KEY, :timeout => 30)
options = {:notification => "Test notification",
:data => {:message => "This is a FCM Topic Message!"}}
response = fcm.send_to_topic('global', options)

I have this problem before
try to add priority: "high" and notification: "your message"
in your FCM class instatiation options

I am not sure if this is due to changes in FCM itself but using the syntax from the gem's documentation or using the format from Daniel's answer did not work for me (Daniel's version gives an error response from FCM saying that notification must be a JSON object).
This is what worked for me:
fcm.send_to_topic(topic, notification: { body: "topic notification" })

Unfortunately the fcm library does not provide support to the rubies < 2.0. According to the git history of the repository that was the case already at the start of the project.

Try this
request = HTTParty.post('http://fcm.googleapis.com/fcm/send', :body => { "to" => "#{token}", "priority" => "high", "data" => { "title" =>title,"body"=>message,'massage_type'=>'text'}}.to_json, :headers => { 'Content-Type' => 'application/json', 'Authorization' => "key=#{server_token}" } )

Related

How do I implement JWT with pub sub push

I followed the documentation on pub/sub notifications with the push method here
And I want to have authentication on my call with JWT. I looked at their GitHub example here
app.post('/pubsub/authenticated-push', jsonBodyParser, async (req, res) => {
// Verify that the request originates from the application.
if (req.query.token !== PUBSUB_VERIFICATION_TOKEN) {
res.status(400).send('Invalid request');
return;
}
// Verify that the push request originates from Cloud Pub/Sub.
try {
// Get the Cloud Pub/Sub-generated JWT in the "Authorization" header.
const bearer = req.header('Authorization');
const [, token] = bearer.match(/Bearer (.*)/);
tokens.push(token);
// Verify and decode the JWT.
// Note: For high volume push requests, it would save some network
// overhead if you verify the tokens offline by decoding them using
// Google's Public Cert; caching already seen tokens works best when
// a large volume of messages have prompted a single push server to
// handle them, in which case they would all share the same token for
// a limited time window.
const ticket = await authClient.verifyIdToken({
idToken: token,
audience: 'example.com',
});
const claim = ticket.getPayload();
claims.push(claim);
} catch (e) {
res.status(400).send('Invalid token');
return;
}
// The message is a unicode string encoded in base64.
const message = Buffer.from(req.body.message.data, 'base64').toString(
'utf-8'
);
messages.push(message);
res.status(200).send();
});
But I have some questions.
What is the PUBSUB_VERIFICATION_TOKEN and how do I get it and store it in my environment?
const [, token] = bearer?.match(/Bearer (.*)/); throws the following error
Type 'RegExpMatchArray | null | undefined' must have a 'Symbol.iterator' method that returns an iterator.ts(2488)
Why do they push the claims and tokens in an array if they never check that array in this function for already existing tokens / claims?
I am trying to implement this with a Firebase Cloud Function and this is what I have. Is it even possible to cache the tokens / claims?
//Service account auth client
const authClient = new google.auth.JWT({
email: android_key.client_email,
key: android_key.private_key,
scopes: ["https://www.googleapis.com/auth/androidpublisher"]
});
export const handlePubSub = functions.region('europe-west1').https.onRequest(async (req, res) => {
// What is PUBSUB_VERIFICATION_TOKEN???
if (req.query.token !== PUBSUB_VERIFICATION_TOKEN) {
res.status(400).send('Invalid request');
return;
}
try {
const bearer = req.header('Authorization');
const [, token] = bearer?.match(/Bearer (.*)/); //Error Type 'RegExpMatchArray | null | undefined' must have a 'Symbol.iterator' method that returns an iterator.ts(2488)
tokens.push(token); // Why do this? Can I do this in firebase cloud functions
const ticket = await authClient.verifyIdToken({
idToken: token,
});
const claim = ticket.getPayload();
claims.push(claim); // Why do this? Can I do this in firebase cloud functions
} catch (e) {
res.status(400).send('Invalid token');
return;
}
const message = Buffer.from(req.body.message.data, 'base64').toString(
'utf-8'
);
console.log(message);
return res.status(200).json({
statusCode: 200,
method: req.method,
message: 'Recieved successfully'
});
});
What is the PUBSUB_VERIFICATION_TOKEN and how do I get it and store it
in my environment?
PUBSUB_VERIFICATION_TOKEN can be any value you want. Easiest way to set an environment variable is on the command line when running node:
PUBSUB_VERIFICATION_TOKEN=whatevertoken node app.js
The req.query.token that is compared too comes from the URL query string.
GET /whatever?token=whatevertoken
Type 'RegExpMatchArray | null | undefined' must have a
'Symbol.iterator' method that returns an iterator.ts(2488)
That's a bug in their code. bearer.match can return undefined/null which can't be spread into the array [, token]. The example will only work when there is a successful regex match. This will parse in plain javascript but typescript highlights this issue at compile time.
const bearer = req.header('Authorization');
const m = /Bearer (.*)/.exec(bearer)
if (m) tokens.push(m[1])
Why do they push the claims and tokens in an array if they never check
that array in this function for already existing tokens / claims?
The example comments // List of all messages received by this instance.
So more a debug store than something functional.

Is there a way to send notifications by identifying user rather than device?

In my android application, I want to send notifications for text messages send from one user to another and I've deployed this Node.js function into firebase functions:
'use strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref(`/notification/{receiver_user_id}/{notification_id}`)
.onWrite((data, context) =>
{
const receiver_user_id = context.params.receiver_user_id;
const notification_id = context.params.notification_id;
console.log('We have a notification to send to :' , receiver_user_id);
if (!data.after.val())
{
console.log('A notification has been deleted :' , notification_id);
return null;
}
const DeviceToken = admin.database().ref(`/users/${receiver_user_id}/user_id`).once('value');
return DeviceToken.then(result =>
{
const token_id = result.val();
console.log("Token Id ", token_id);
const payload =
{
notification:
{
title: "New Mesaage",
body: `you have a new Message, Please Check.`,
icon: "default"
}
};
console.log("This is payload ", payload);
return admin.messaging().sendToDevice(token_id, payload).then()
.catch(function (error)
{
console.log("Error sending message: ", error); // here no return
});
});
});
I think the problem lies with sendToDevice() method as I'm not getting any notification and I don't want to send by device_token.
I want to send notifications to the device in which the user with a particular "user_id" is logged in
This is my database model
This is the log I got:
and I don't want to send by device_token
If you want to target a message to a particular user's device, you must use a device token. That's the way it works.
FCM doesn't know anything about the individual users of your app. FCM just knows about individual devices whose tokens you collect in the app and send to your backend (or store in your database). You have to associate the token to the user account somehow. You should also assume that one user might be using multiple devices.
What you should probably do first is start collecting the device tokens and storing them in a field under your user data. Then, when you query that user, you can find the device tokens to use to send the message.

FCM - Notification appear if send from console but not appear if send from JSON in React Native

I try use FCM to send notification.
I try 2 methods to send notification,
I send notification (FCM) via Firebase Console (Success, push notification appear on top screen)
I send notification via https://fcm.googleapis.com/fcm/send. Here my setup :
let title = "My Title";
let msg = "Test Notification";
let header = {
headers: {
'Authorization': 'key=' + serverKey,
'Content-Type': 'application/json'
},
};
let body = {
"registration_ids": clientToken,
"data": {
'body': msg,
'title': title,
'link': '-',
'click_action': 'OPEN_MAIN_ACTIVITY',
}
}
My Question is The first method work fine (notification appear). But
why when i send FCM with the second method, on Android not appear the
push notification? Can you find what mistake of the code ?

How to send push notifications to multiple device with FCM tokens using cloud functions

First I generated a FCM token and stored in firestore. After that I wrote a cloud functions to send notifications based on FCM token. and I deployed cloud functions it says successfully sent notifications with status ok. But it doesn't displays in mobile device. My Index.js is
'use strict';
const functions = require('firebase-functions');
const Firestore = require('#google-cloud/firestore');
const admin = require('firebase-admin');
const firestore = new Firestore();
const db = admin.firestore();
admin.initializeApp(functions.config().firebase);
exports.hellouser = functions.firestore
.document('users/{token}')
.onWrite(event =>{
var document = event.data.data();
console.log("tokens",document);
var token = ['cdNN0AbYKU0:APA91bEyL0zo3zwHZD8H43Vp7bxAfYgehlVI8LrKktPO2eGuByVDdioysIGxHe5wocwq8ynxRToJPpOve_M59YY_MIRbWLnF9AIgoTwJORXZbw6VBw7']// this is my FCM token.
if(
const payload = {
notification: {
title: "Message",
body: "hi hello",
sound: "default"
}
};
return admin.messaging().sendToDevice(token, payload).then((response)=> {
console.info("Successfully sent notification")
}).catch(function(error) {
console.warn("Error sending notification " , error)
});
});
How to send notifications based on the FCMtoken.
If it's the exact code you use then check syntax near if(. This may help you.Next write some code to go through your response object. Firebase may take your tokens and payload, process them and return 200 OK response but in the response you will have errors. Response has general structure like this: { results:
[ { //stuff related to one token },{ //stuff related to one token } ],
canonicalRegistrationTokenCount: 0,
failureCount: 1,
successCount: 0,
multicastId: SOME_LONG_NUMBER }Take in mind that response.results array has status of each message sent to token in the same order as tokens in your token array. You can see all posible errors in Firebase Documentation. If response.failureCount > 0 then no messages were sent and you should get corresponding error in response.results.Also learn about options variable. options.priority must be 'high' to guarantee fast message delivery. Maybe this will help.

How to send Push Notification Firebase

I am new to Firebase and the main reason I adapted to it from my old MySql DB is the ability to send push notification and dynamic links. I have been trying for the past two days to send notification to a group of people who have subscribed to a topic from my node.js script. The script always returns InternalServerError. I am able to send notification from the Firebase console but that is not good enough for my app as I need to implement dynamic notification (i.e. triggered by one users action).
So far I did not understand what was in the official docs and tried following a tutorial I found and I am currently here
app.get('/push',function(req,res){
/*var title = req.params.title;
var body = req.params.body;*/
// var confName = req.params.name;
var message = { //this may vary according to the message type (single recipient, multicast, topic, et cetera)
to: '/topics/ilisten',
// collapse_key: 'your_collapse_key',
notification: {
title: 'This is Title',
body: 'This is body'
},
data: { //you can send only notification or only data(or include both)
my_key: 'Conf Name here'
}
};
fcm.send(message, function(err, response){
if (err) {
console.log("Something has gone wrong!"+err);
} else {
console.log("Successfully sent with response: ", response);
}
});
})
My first question is what should I do in the to field so that all the users in my app reciece the notification.
I would also like to take a look at correct and complete implementation of this concept with android code. If anyone has such code please share it here as it would help the future Firebase users who cannot understand the official docs like me.
Following is one approach using node-gcm (https://github.com/ToothlessGear/node-gcm)
var gcm = require('node-gcm');
var sender = new gcm.Sender(<sender_key>);
var message = new gcm.Message();
message.addNotification('title', title);
message.addNotification('body', body);
sender.send(message, { topic: "/topics/" + topic }, function (err, response) {
if (err) console.error(err);
else console.log(response);
});

Categories

Resources