I have successfully send notifications using Firebase Cloud Messaging (FCM) triggered by a Firebase function:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const fs = require('fs');
admin.initializeApp();
exports.testNotif = functions.https.onRequest((request, response) => {
const mySecretNumber = getRandomInt(147)
var payload = {
notification: {
title: `You got a new Message`,
body: `My highest break ${mySecretNumber}`,
badge: mySecretNumber.toString(),
sound: `notif1.aiff`,
}
};
const ackString = `All done ${mySecretNumber}`;
console.log(ackString)
response.send(ackString);
//send to all topic
admin.messaging().sendToTopic(`all`, payload)
});
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
As you can see I am sending the notifications to a topic called 'all'.
In the firebase console you can send notifications to an audience that you can create. In my case I have created different audiences based on user properties from the analytics module.
Is it possible to also send notifications via Firebase Functions to audiences?
There is no Analytics API to retrieve the users that fall into a specific analytics audience. Nor is there an FCM API to send a notification to such an audience.
If you want to send notifications to audiences, you'll have to create your own way of defining these audiences. The most direct way is to connect Google Analytics for Firebase to BigQuery, and then define the audience on the analytics events you receive there.
Also see: How to send firebase notifications to audience via HTTP
Related
I have some problem about using Firebase Cloud Messaging from Firebase Cloud Functions.
The error message is below. It is from my Firebase Cloud Functions Log console.
Error: An error occurred when trying to authenticate to the FCM servers. Make sure the credential used to authenticate this SDK has the proper permissions.
At first, I follow Firebase Cloud Functions CodeLabs.
https://firebase.google.com/codelabs/firebase-cloud-functions
And at last lab "New Message Notifications", when I insert new message at Web "FriendlyChat" app, there is not display notification message. Then I checked log in Firebase Cloud Functions Log console, there was an error message which I had told.
How to solve problem Firebase Cloud Messaging error in Firebase Cloud function?
Or ... How can I check about cloud functions credential before call FCM?
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
// Sends a notifications to all users when a new message is posted.
exports.sendNotifications = functions.firestore.document('messages/{messageId}').onCreate(
async (snapshot) => {
// Notification details.
const text = snapshot.data().text;
const payload = {
notification: {
title: `${snapshot.data().name} posted ${text ? 'a message' : 'an image'}`,
body: text ? (text.length <= 100 ? text : text.substring(0, 97) + '...') : '',
icon: snapshot.data().profilePicUrl || '/images/profile_placeholder.png',
click_action: `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com`,
}
};
// Get the list of device tokens.
const allTokens = await admin.firestore().collection('fcmTokens').get();
const tokens = [];
allTokens.forEach((tokenDoc) => {
tokens.push(tokenDoc.id);
});
if (tokens.length > 0) {
// Send notifications to all tokens.
const response = await admin.messaging().sendToDevice(tokens, payload);
await cleanupTokens(response, tokens);
functions.logger.log('Notifications have been sent and tokens cleaned up.');
}
});
Thank you in advance.
I solve this problem by set "Enabled" at "Cloud Messaging API (Legacy)" at Project Settings.
i'm using react native with firebase to use fcm push notification..
this is documnet example
// Node.js
var admin = require('firebase-admin');
// ownerId - who owns the picture someone liked
// userId - id of the user who liked the picture
// picture - metadata about the picture
async function onUserPictureLiked(ownerId, userId, picture) {
// Get the owners details
const owner = admin
.firestore()
.collection('users')
.doc(ownerId)
.get();
// Get the users details
const user = admin
.firestore()
.collection('users')
.doc(userId)
.get();
await admin.messaging().sendToDevice(
owner.tokens, // ['token_1', 'token_2', ...]
{
data: {
owner: JSON.stringify(owner),
user: JSON.stringify(user),
picture: JSON.stringify(picture),
},
},
{
// Required for background/quit data-only messages on iOS
contentAvailable: true,
// Required for background/quit data-only messages on Android
priority: 'high',
},
);
}
document says if i want to request message by using rest api instead of firebase admin
i have to use this url
which is
https://fcm.googleapis.com/fcm/send
but i confused how can i use this url??
and i wonder should i use this url in backend or frontend?
Sending messages to devices through FCM requires that you specify the so-called FCM server key to the API. As its name implies this key should only be used in trusted environments, such as a server you control, your development machine, or Cloud Functions.
There is no secure way to send messages directly from client-side code directly through the FCM API. For more on this, see:
the architectural overview in the Firebase documentation
How to send one to one message using Firebase Messaging
I have an application that sends data to the firebase realtime database. Now I'm creating a dashboard to manage this data. At the moment I need to receive a notification on the dashboard when the user sends some new data to the firebase. I need to receive a message with the data id he sent and submit a notification similar to a social network.
I'm using FCM, I've already configured and tried to implement the onCreate () function. But when the bank is upgrading, this function is not being performed.
I'm implementing the code in the dashboard
I believe it is a lack of asynchronism. is there any way to apply it to the function call?
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.makeUppercase = functions.database
.ref("/users/{userID}")
.onCreate((snapshot, context) => {
const original = snapshot.val();
console.log("new User " + original);
});
I've created two Firebase functions - one is an HTTPS where I am publishing a message to a topic, and a pub/sub function where I am responding to messages published to that topic.
testPubSub.ts
import { pubsub } from "firebase-functions";
export const testPubSub = pubsub
.topic("high-scores")
.onPublish(async (message, context) => {
console.log("hit test pubsub");
return null;
});
testHttps.ts
import { https } from "firebase-functions";
import { messaging } from "firebase-admin";
export const testHookEndpoint = https.onRequest(async (request, response) => {
const payload = {
notification: {
title: "Test title",
body: "test body"
}
};
const pubsubResponse = await messaging().sendToTopic("high-scores", payload);
console.log("response from pubsub", pubsubResponse);
response.send("success");
});
The HTTPS function appears to be running fine (200 response) and messaging is returning a message ID in the response, however I am not seeing the pub/sub function run in the Firebase Console.
When I look at GCP Console I see that "high-scores" has registered as a topic in the Pub/Sub tab, and I'm able to trigger other pub/sub functions in the project through Google Cloud Scheduler.
I'm not sure what step I'm missing for this.
messaging().sendToTopic("high-scores", payload) is using Firebase Cloud Messaging to send a message to mobile applications subscribed to the given topic. This is completely different than Cloud Pubsub messaging. These two products don't actually have anything in common - FCM is for mobile apps and pubsub is for servers.
What you'll need to do instead is use the node pubsub SDK to send the message to your pubsub topic.
While using Cloud Firestore as data backend, I need to share some data collections with non-tech site managers (editors, sales teams, etc.). Also, I wish to give these people access to edit the data stored in Cloud Firestore.
Google Sheets is a very familiar tool with site managers which can save me time in developing a CRUD admin panel like the interface from scratch for data updating and viewing.
This Stack Overflow answer shows how to send data using cloud function and levels deep, and this Github library can get data from Firestore using Google Apps Script (I wish to do it using Cloud Functions or Firebase Admin SDK), but I am still trying to figure out how to make an end-to-end Sheets based interface.
Please guide if there are any better alternatives to achieve the same objective. I'm facing some difficulties switching from SQL databases and Django auto-created admin interfaces to the Firebase-Firestore NoSQL world.
I understand that you want to be able to call a Cloud Function from a Google Sheet in order to build an "end-to-end Sheets based interface" for Firestore.
You can use the UrlFetchApp Class to make a request to fetch the URL of an HTTP Cloud Function.
You Apps Script code would be like:
function callSimpleHTTPCloudFunction() {
const url = "https://xxxxxxxx.cloudfunctions.net/simpleHttp";
response = UrlFetchApp.fetch(url, {
method: 'get'
})
respObj = JSON.parse(response.getContentText());
Logger.log(respObj);
}
While your Cloud Function would be like:
exports.simpleHttp = functions.https.onRequest((req, res) => {
res.send({ msg: 'simpleHttp' });
});
This is a very simple example of Cloud Function, but you can adapt this Cloud Function to read and write data from/to Firestore. Have a look at this official video for a starting point: https://www.youtube.com/watch?v=7IkUgCLr5oA&t=1s&list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM&index=3
Now, if you want to authenticate your users in such a way you can control who can access your data through the Cloud Function, it is going to be a bit more complex.
There is an official Cloud Function Sample which shows "how to restrict an HTTPS Function to only the Firebase users of your app": https://github.com/firebase/functions-samples/tree/master/authorized-https-endpoint
As explained in the code comments: "The Firebase ID token needs to be passed as a Bearer token in the Authorization HTTP header like this: Authorization: Bearer <Firebase ID Token>. When decoded successfully, the ID Token content will be added as req.user."
So you need, in your Apps Script code, to generate a Firebase ID Token for the Firebase user. For that we will use the Firebase Auth REST API. In this example we will use the email of the user authenticated in the Google Sheet (Session.getActiveUser().getEmail()) as the Firebase User Name.
As explained in the doc, to call the Firebase Auth REST API, you need to obtain a Web API Key for your Firebase project, through the project settings page in your Firebase admin console.
The following Apps Script function will do the job:
function getToken() { {
const userName = Session.getActiveUser().getEmail();
const pwd = 'xyz' //For example get the password via a prompt.
//This is NOT the password of the account authenticated with Google Sheet, but the password of the Firebase user. In this example, the emails are the same but they are different accounts.
const verifyPasswordUrl = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=[API_KEY]" //Replace with your Web API Key
const payload = JSON.stringify({"email":userName,"password": pwd,"returnSecureToken": true});
const verifyPasswordResponse = UrlFetchApp.fetch(verifyPasswordUrl, {
method: 'post',
contentType: 'application/json',
muteHttpExceptions: true,
payload : payload
});
const token = JSON.parse(verifyPasswordResponse.getContentText()).idToken;
return token;
}
Then, still in Apps Script, you use the token in the call to the Cloud Function, as follows:
function callSecuredHTTPCloudFunction() {
const authHeader = {"Authorization": "Bearer " + getToken()};
const url = "https://us-central1-<yourproject>.cloudfunctions.net/securedHttp/";
const response = UrlFetchApp.fetch(url, {
method: 'get',
headers: authHeader,
muteHttpExceptions: true,
});
Logger.log(response);
//Here do what you want with the response from the Cloud Function, e.g. populate the Sheet
}
The Cloud Function code would be as follows, adapted from the official example.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const cors = require('cors')({
origin: true
});
const express = require('express');
const cookieParser = require('cookie-parser')();
const app = express();
// Express middleware that validates Firebase ID Tokens passed in the Authorization HTTP header.
// The Firebase ID token needs to be passed as a Bearer token in the Authorization HTTP header like this:
// `Authorization: Bearer <Firebase ID Token>`.
// when decoded successfully, the ID Token content will be added as `req.user`.
const validateFirebaseIdToken = (req, res, next) => {
console.log('Check if request is authorized with Firebase ID token');
if (
!req.headers.authorization ||
!req.headers.authorization.startsWith('Bearer ')
) {
console.error(
'No Firebase ID token was passed as a Bearer token in the Authorization header.',
'Make sure you authorize your request by providing the following HTTP header:',
'Authorization: Bearer <Firebase ID Token>'
);
res.status(403).send('Unauthorized');
return;
}
let idToken;
if (
req.headers.authorization &&
req.headers.authorization.startsWith('Bearer ')
) {
console.log('Found "Authorization" header');
// Read the ID Token from the Authorization header.
idToken = req.headers.authorization.split('Bearer ')[1];
console.log(idToken);
} else {
// No cookie
res.status(403).send('Unauthorized');
return;
}
admin
.auth()
.verifyIdToken(idToken)
.then(decodedIdToken => {
console.log('ID Token correctly decoded', decodedIdToken);
req.user = decodedIdToken;
return next();
})
.catch(error => {
console.error('Error while verifying Firebase ID token:', error);
res.status(403).send('Unauthorized');
});
};
app.use(cors);
app.use(cookieParser);
app.use(validateFirebaseIdToken);
app.get('/', (req, res) => {
res.send(`Your email is ${req.user.email}`);
});
// This HTTPS endpoint can only be accessed by your Firebase Users.
// Requests need to be authorized by providing an `Authorization` HTTP header
// with value `Bearer <Firebase ID Token>`.
exports.securedHttp = functions.https.onRequest(app);
You can very well write a similar function with a POST and a payload in order to send data from the Google Sheet to the Cloud Function and then write to Firestore.
Finally, note that you could implement the same approach for calling, from the Google Sheet, the Firestore REST API instead of calling Cloud Functions.