Firebase Cloud Messaging Notification not received in web app - firebase

I am using FCM for notification. FCM gets triggered on creation of data from the Firebase database. I received first message. After that other consecutive messages is not received. I'm running this in a local environment. Is the problem due to the below message "Billing account not configured. External network is not accessible and quotas are severely limited. Configure billing account to remove these restrictions" or any other issue. Do I need to get into a billing plan for receiving messages. Working in test environment and that is the reason not moving to billing plan. If the issue is not related to billing plan can someone point any other problem with the code.
Firebase function log
6:22:52.133 PM
sendFollowerNotification
Function execution started
6:22:52.133 PM
sendFollowerNotification
Billing account not configured. External network is not accessible and quotas are severely limited. Configure billing account to remove these restrictions
6:22:52.143 PM
sendFollowerNotification
Function execution took 10 ms, finished with status: 'ok'
6:22:52.401 PM
sendFollowerNotification
1 messages were sent successfully
Node js code
exports.sendFollowerNotification = functions.database.ref('/notification/message/{gId}/{pId}')
.onCreate(async (change, context) => {
//console.log('Group id:', context.params.gId," Push ID:",context.params.pId, "Change",change);
const notificationData = change.val();
var topic = notificationData.topic;
var title = notificationData.title;
var body = notificationData.body;
var registrationTokens = notificationData.tokens;
const message = {
notification: {
title: title,
body: body
},
tokens: registrationTokens,
};
admin.messaging().sendMulticast(message)
.then((response) => {
// Response is a message ID string.
console.log(response.successCount + ' messages were sent successfully');
})
.catch((error) => {
console.log('Error sending message:', error);
});
});

That message does not indicate an error. It's just a warning letting you know that outbound networking does not work if your project is not on a payment plan. FCM messaging does not fall in this category - it should work.
The problem is that your code doesn't return a promise that resolves after all asynchronous work is complete. Right now, it returns nothing, and the function terminates immediately before the message is sent. Please read and understand the documentation about this.
Minimally, you will need to return the promise chain to let Cloud Functions know when the message is sent, and it's safe to terminate.
return admin.messaging().sendMulticast(message)
.then((response) => {
// Response is a message ID string.
console.log(response.successCount + ' messages were sent successfully');
})
.catch((error) => {
console.log('Error sending message:', error);
});
Note the return keyword above.
If the message still isn't being sent, then there is some other problem here that we can't see. You might not be handling your device tokens correctly.

I think this might answer your question: Why will I need a billing account to use Node.js 10 or later for Cloud Functions for Firebase?:
Because of updates to its underlying architecture planned for August 17, 2020, Cloud Functions for Firebase will rely on some additional paid Google services: Cloud Build, Container Registry, and Cloud Storage. These architecture updates will apply for functions deployed to the Node.js 10 runtime. Usage of these services will be billed in addition to existing pricing.
In the new architecture, Cloud Build supports the deployment of functions. You'll be billed only for the computing time required to build a function's runtime container.
On the other hand, the Service Firebase Clud Messaging itself is free:
Firebase Cloud Messaging (FCM) provides a reliable and battery-efficient connection between your server and devices that allows you to deliver and receive messages and notifications on iOS, Android, and the web at no cost.
Given that you are using Node in your CFs, the Platform requires to you a Billing Account.

Related

Firebase's Google Sign In keeps shutting down DOTNET API

Well, I'm really lost here so any help would be great. My app works with a DOTNET6 API backend and a Vue3 frontend.
I'm registering users via Google Sign In directly from my frontend (Vue3) with this code:
async googleLogIn() {
const provider = new GoogleAuthProvider;
var gUser;
await signInWithPopup(getAuth(), provider)
.then((result) => {
gUser = result.user;
console.log(gUser);
})
.catch((error) => {
console.log(error);
});
}
The user gets correctly saved in Firebase, and that should be all. The thing is, even though I'm not interacting with my DOTNET API, said API gets shut down without specifying the error. The message displayed in VS Debug Console is : ...\my_api.exe (process 32400) exited with code -1.
I believe the ports used by my API might be the problem (already tried changing them but it keeps failing), but I don't understand why the Google Sign In would interfere with my local API.

How do I send push notifications with expo and react native?

I am writing a simple app, where I need to send push notifications. For instance, a user liked a post -> send a push notification; or a user commented under a post -> send a push notification; or a user sent you a message -> send a push notification.
I am using Notifications from expo-notifications. I have set up my Notifications.addNotificationReceivedListener and Notifications.addNotificationResponseReceivedListener. I tested them using Expo's push notification tool and it all works fine.
However, I am struggling to send notifications. As suggested per expo's docs they have a library for Node.js called expo-server-sdk-node which takes care of sending notifications. As per their doc:
The Expo push notification service accepts batches of notifications
so that you don't need to send 1000 requests to send 1000
notifications. We recommend you batch your notifications to reduce
the number of requests and to compress them (notifications with
similar content will get compressed).
And I agree with the above statement. Sending notifications on batch makes sense, however, I have a question regarding this:
How do I implement it? Do I keep counter on the user's notification, and lets say, the user has liked 10 posts -> then I send 10 notifications as a batch request? What if they liked 8 posts and then closed the app? Do I send the notifications on closing the app? It doesn't seem right to me. Also, if the user has sent a message, I believe I should straight away send the notification, rather than waiting for a batch request for the user to send 10 messages.
The implementation they offer on their docs is the following:
// Create the messages that you want to send to clients
let messages = [];
for (let pushToken of somePushTokens) {
// Each push token looks like ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]
// Check that all your push tokens appear to be valid Expo push tokens
if (!Expo.isExpoPushToken(pushToken)) {
console.error(`Push token ${pushToken} is not a valid Expo push token`);
continue;
}
// Construct a message (see https://docs.expo.io/push-notifications/sending-notifications/)
messages.push({
to: pushToken,
sound: 'default',
body: 'This is a test notification',
data: { withSome: 'data' },
})
}
Which is OK and understandable. But then I struggle with the next step:
let chunks = expo.chunkPushNotifications(messages);
let tickets = [];
(async () => {
for (let chunk of chunks) {
try {
let ticketChunk = await expo.sendPushNotificationsAsync(chunk);
console.log(ticketChunk);
tickets.push(...ticketChunk);
} catch (error) {
console.error(error);
}
}
})();
That is, at which point do I call expo.chunkPushNotifications(messages) and then await expo.sendPushNotificationsAsync(chunk). Do I wait 10 similar notifications to be collected, do I wait some time, do I do it when the user closes the app, or something else?

Firebase emulator: see outgoing HTTP traffic

I have a Cloud Function that calls to Chargebee. In index.ts:
const chargeBee = new ChargeBee();
...
chargeBee.configure({
site,
api_key: apiKey
});
...
export const finalizeSignup = https.onCall(
async (info: SignupInfo, ctx: CallableContext) => {
const cbCmd = chargeBee.hosted_page.retrieve(info.cbHostedPage);
const callbackResolver = new Promise<any>((resolve, reject) => {
// cbCmd.request returns a Promise that seems to do nothing.
// The callback works, however.
// Resolve/reject the Promise with the callback.
void cbCmd.request((err: any, res: any) => {
if (err) {
reject(err);
}
resolve(res);
});
});
// Calling Promise.resolve subscribes to the Promise.
return Promise.resolve(callbackResolver);
}
);
I am testing this function using the Firebase emulators, started via firebase emulators:start --only functions. Chargebee is responding strangely. They require the domain of their incoming requests to be whitelisted: my first guess is that the domain being used by my locally emulated Cloud Function is not whitelisted on the Chargebee side.
How do I see outgoing HTTP information sent by my locally emulated Cloud Function?
The connection is actually HTTPS, not HTTP.
The emulators provide no functionality to intercept network traffic of any form.
For HTTP: you have to apply your own tooling to monitor the HTTP traffic (ie Wireshark).
For HTTPS: possible to monitor using Wireshark, but impossible to analyze without knowing the SSL key. And in the setup above, where a third-party library is handling the request, there is currently no way to obtain the SSL key. I entered a feature request with Firebase to gauge the interest of developing a way to define an SSL key log when starting the Functions emulator, similar to Chrome. A user only identifying themselves as 'Oscar' told me in a private email that "I've already filed a feature regarding this topic to our engineering team regarding this matter, which will be discussed internally." So that tells us that (1) Firebase is aware that the feature is currently lacking, and (2) there is no progress to report on the feature.

iOS FCM data only message does not call messaging:didReceiveMessage

Firebase Messaging version 5.6.0. I am attempting to handle a data only message in the foreground via Firebase Messaging on iOS 9.0 (10 if needed), but it is not calling FIRMessagingDelegate's messaging:didReceiveMessage per the documentation. I see the message come in # FIRMessaging.m's appDidReceiveMessage:message, but never comes through to the delegate.
This is the snippet from the cloud function that sends data to the topic per sending to a topic:
const message = {
data: {
test: '123'
}
topic: 'example'
}
admin.messaging().send(message);
Did I miss something?
Update: I do receive the data if I implement application:didReceiveRemoteNotification:userInfo
fetchCompletionHandler:completionHandler.
Thanks to Kat at Firebase support, here is the answer.
Use legacy sendToTopic instead of send, as send quietly adds content_available=1 which gets treated as APNs silent notification. Here is the updated version:
admin.messaging().sendToTopic('example', {
data: {
test: '123'
}
});
// Always use strings for key/values in the data object.
Below verbatim from Kat at Firebase support:
How the FCM data message is handled would depend on your setting for content_available.
If you have content_available = 1, the message is sent via APNs and is treated similar as an APNs silent notification. This is handled in the application:didReceiveRemoteNotification: callback when the app is running in foreground or background (i.e. not killed). See this related StackOverflow post for more information.
Without content_available, the message is sent via FCM direct channel. This only handled in the messaging:didReceiveMessage: when app is in foreground.
Note that messages sent via the Admin SDK's send() method uses the FCM HTTP v1 API which have content_available=1 by default, so they are always sent via APNs. If you want to configure the content_available field, you'll need to use the Admin SDK's sendToDevice() method which uses the legacy protocols.
In addition, here is the list of legacy protocols.

Firebase Cloud Messaging for web: how to send to multiple tokens?

i hope i don't get downvotes on this one, i've been trying to set up web notifications for my CMS using Firebase, and i noticed that Google's Firebase documentations on the topic are huge, i mean very huge you get confused.
So far i managed to add the functionality of letting people subscribe to the notification by letting the browser asking their permission to send them notifications, then i get the unique tokens after they accept and store those tokens in my database, i also managed to change the location of the service worker and everything looks good and dandy.
Now, i want to send a notification to all my users (tokens) that are stored in my database, i think looping through them and send a notification using CURL to each one individually is a nasty solution. I can't find a documentation on how to send a notification to all my tokens in one CURL call.
This is my code so far:
<!-- Firebase Technologies -->
<!-- Firebase App is always required and must be first -->
<script src="https://www.gstatic.com/firebasejs/5.1.0/firebase-app.js">
</script>
<script src="https://www.gstatic.com/firebasejs/5.1.0/firebase-
messaging.js"></script>
<script>
// Initialize Firebase
var config = {
apiKey: "AIzaSyAR84lF2vbnfUWPZ2899dnqiTthgvfv7Ms",
authDomain: "lazemnicms.firebaseapp.com",
databaseURL: "https://lazemnicms.firebaseio.com",
projectId: "lazemnicms",
storageBucket: "lazemnicms.appspot.com",
messagingSenderId: "268754114869"
};
firebase.initializeApp(config);
messaging = firebase.messaging();
//Registering the service worker
navigator.serviceWorker.register("firebase-messaging-sw.js", {scope: "firebase-cloud-messaging-push-scope"}).then(function (registration) {
messaging.useServiceWorker(registration);
}).catch(function (err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
permissionGranted = false;
messaging.getToken().then(function(currentToken) {
if (currentToken) {
console.log(currentToken);
permissionGranted = true;
//sendTokenToServer(currentToken);
//updateUIForPushEnabled(currentToken);
} else {
permissionGranted = false;
}
}).catch(function(err) {
permissionGranted = false;
});
And also if a user got a refreshedToken, how can i know this user's old token so i can remove it from my database after i store his/her new token?
Those questions are really troubling me.
Thanks in advance.
The v1 API currently only allows sending to a single token at a time. Multicast is planned to be added (it was present in the previous API), but I don't have a timeline for when it will be available. So right now that means that you'll need to do a call to the FCM API for each token.
There is nothing built-in to know the previous token for a user. The typical way to do this is to keep the "last known token" in local storage, and unregister that when you get a new token. Alternatively, you can instead catch the errors that indicate an invalid token when sending messages, and remove them from the database that way (see an example of that here). A combination of these two approaches is probably best.

Resources