Push notifications using Firebase Cloud Function iOS - node.js

Trying to send remote push notifications through firebase cloud functions. Resources I've been following achieves this through sendToDevice method, which takes a String as an argument. A resource from GitHub says its a "device notification token" that is retrieved when user agrees to receive notifications in app. Firebase says its a "registration token that comes from the client FCM SDKs". What should be the input here, and how to I retrieve it?
// Send notification to device via firebase cloud messaging.
// https://firebase.google.com/docs/cloud-messaging/admin/send-messages
// https://github.com/firebase/functions-samples/blob/master/fcm-notifications/functions/index.js
//
admin.messaging().sendToDevice(request.query.tokenId, payload).then(response => {
response.results.forEach((result, index) => {
const error = result.error
if (error) {
console.log("Failure sending notification.")
}
});
});

You need to integrate FCM into your iOS app. Pay attention to the part about receiving the current registration token.
Registration tokens are delivered via the FIRMessagingDelegate method
messaging:didReceiveRegistrationToken:. This method is called
generally once per app start with an FCM token. When this method is
called, it is the ideal time to:
If the registration token is new, send it to your application server (it's recommended to implement server logic to determine whether the
token is new).
Subscribe the registration token to topics. This is required only for new subscriptions or for situations where the user has
re-installed the app.
So, you'll have to get a hold of this token in your app, store it somewhere that the Cloud Function can get a hold of (traditionally, Realtime Database), and query for it at the time the function runs.

Related

Node.js: Google Calendar On Behalf of User

I am trying to access multiple users' Google Calendars in a search functionality with Flutter and Firebase Functions in Node.js.
I originally ask for user permission here in the app (Flutter):
clientViaUserConsent(_credentialsID, _scopes, prompt)
.then((AuthClient client) async {
The credentials for the user are then stored locally and in Firestore via a restricted Firebase Function for security reasons.
Calling Firebase Function (Node.js):
FirebaseFunctions.instance
.httpsCallable('addCalendar')
.call(<String, dynamic>{
'calendarAuthToken': client.credentials.accessToken.data,
'calendarRefreshToken': client.credentials.refreshToken!,
'calendarExpiration':
client.credentials.accessToken.expiry.toString(),
'idToken': client.credentials.idToken.toString()
});
Firebase Function:
return await admin.firestore().collection('[example text]').doc('[example text]').set({
CalendarAccessToken: calendarAccessToken,
CalendarRefreshToken: calendarRefreshToken,
CalendarExpiration: calendarExpiration,
// CalendarIDToken: calendarIDToken
}).then(() => {
I have a search functionality which needs access to all users' calendars. Obviously this should never be done locally due to the sensitivity of the data, so I am trying to do this in a Firebase Function as well.
exports.isAvailableNow = functions.https.onCall(async (data, context) => {
const id = data.id;
const cal= await admin.firestore().collection('[example text]').doc(id)
Should I be reconstructing user's credentials in the Firebase Function, or should I instead be using a service account? The reconstruction could get blocked because it is running on Firebase, not locally like the user permitted. If I need to use a service account, how does that change the original authorization in flutter?
EDIT: Changed the title
UPDATE: I managed to reconstruct the authentication for the user on the server-side, but my fear has become a reality. Google is saying I am not authorized for the user. How do I authorize a user on the client then access their data on the backend?

How to retrieve all FCM tokens from server side to subscribe users to a topic?

Background
I posted a question a few days ago and gained some insight: previous question. However, I did a poor job asking the question so I still don't know how I can retrieve all the users FCM tokens in order to use something like this: Subscribe the client app to a topic. This is also listed under the Server Environments documentation. My clients are on the iOS platform.
This function requires the client FCM tokens to be in a list to iterate over and subscribe each client to a topic to later be used for push notifications. Also I have almost 3,000 users which is more than the 1,000 device limit noted in the documentation.
I was also directed to some server documentation by another clever answer: Manage relationship maps for multiple app instances. However, after reading through the material I still believe I need an array of client registration tokens to use this method. My analysis could be totally incorrect. I am quite ignorant since I'm very young and have a ton to learn.
I also tried to get the client FCM tokens with Bulk retrieve user data, but this does not have access to device tokens.
Question
How cant I obtain all of the users registration tokens to provide to this function:
var registrationTokens = [];
admin.messaging().subscribeToTopic(registrationTokens, topic)
.then(function(response) {
console.log('Successfully subscribed to topic:', response);
})
.catch(function(error) {
console.log('Error subscribing to topic:', error);
});
Furthermore, if I have over 1000 users, let's say 3000. How can I make separate request to subscribe everyone and not surpass the 1000 device per request limit?
Additional question on device groups
I've been trying to accomplish a "Global" push notification by sending messages with topics. Is sending messages to device groups perhaps a better approach?
send different messages to different phone models, your servers can add/remove registrations to the appropriate groups and send the appropriate message to each group
After reading the documentation they both seem adequately to accomplish my goal, however, device groups allows the server to more accurately send messages to specified devices. Are one of these methods a better practice? Or for my case is the difference trivial?
The thing about tokens here is that they can change at any time like:
The app is restored on a new device
The user uninstalls/reinstall the app
The user clears app data.
so even if you save them some where then try to register them all at once, some of them may not be valid at that time.
better way to do this is form your registaration token on your client side (IOS):
Messaging.messaging().token { token, error in
if let error = error {
print("Error fetching FCM registration token: \(error)")
} else if let token = token {
print("FCM registration token: \(token)")
self.fcmRegTokenMessage.text = "Remote FCM registration token: \(token)"
}
}
then monitor changes on this token:
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
print("Firebase registration token: \(String(describing: fcmToken))")
let dataDict:[String: String] = ["token": fcmToken ?? ""]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
and send changes to server (which can be any type of servers here) like Firebase Functions with Nodejs. Check here to know how to post a request to Firebase HTTP functions. Then, you can use the same code that you have posted here within that function to register the token to the topic.
This way, you will never exceed that limit and you keep track of all the users' registeration tokens changes.

Register device on Azure notifications hub

I'm developing an application using Ionic & capacitor. My backend is Azure functions (nodejs) javascript, i'm able to get the device token using the below code:
PushNotifications.addListener(
'registration',
(token: PushNotificationToken) => {
alert('Push registration success, token: ' + token.value);
},
);
This token I send to my backend, but i don't know how to save it in Azure Notifications Hub?
Typically this is stored on your app backend. Please see this document for more information.
Let me know if there are further questions on this matter.
Was able to use azure-sb to successfully register the device and send notifications, sample code here: https://github.com/mpodwysocki/azure-notificationhubs-node-sample/blob/main/src/index.ts

How to send push notifications in Flutter android app?

I developed a flutter android app. and my database is MongoDB. I use Node.js API to connect my flutter app with the MongoDB. I want to send push notifications when a new data record is coming to MongoDB. How can I do that?
The simplest way is to use Firebase Cloud Messaging. Especially since Google is deprecating GCM which was previously used for Android. Also Firebase cloud messaging is free and can be used for both iOS and Android. Apple's APN service will require a setup as well though and a paid developer account.
Create a Firebase project if you haven't already and enable cloud messaging.
To set up your Node.js server so that it can send push notifications to your android and IOS devices. Click on the Project Overview, Settings and service accounts and follow the directions to generate a private key for your project and follow the instructions for setup. Also npm install "firebase-admin".
Once you have firebase setup refer to these docs for how to send messages. https://firebase.google.com/docs/cloud-messaging/send-message
There are several ways to send messages. You can send messages directly.
with this code
// This registration token comes from the client FCM SDKs.
var registrationToken = 'YOUR_REGISTRATION_TOKEN';
var message = {
data: {
score: '850',
time: '2:45'
},
token: registrationToken
};
// Send a message to the device corresponding to the provided
// registration token.
admin.messaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
You can also create topics for devices to subscribe to as well if you are sending out mass notifications. More examples once again are within the docs. Now if you are wondering what the token is that is the next step.
The token comes from the unique device that is connecting to your platform. You can get the token by installing the Firebase Messaging sdk from https://pub.dev/packages/firebase_messaging and following the instructions to add the necessary dependencies to your pubsec.yaml and properly configure your Android manifest and iOS files for the changes.
This package will give you methods to grab your communicate and to receive the notifications that you have sent form your Node.JS server.
Here is an example of grabbing the token from your device on the frontend in flutter.
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
bool _initialized = false;
Future<void> init() async {
if (!_initialized) {
// For iOS request permission first.
_firebaseMessaging.requestNotificationPermissions();
_firebaseMessaging.configure(onMessage: (Map<String, dynamic> `enter code here`message) {
print('onMessage: $message');
Platform.isAndroid
? showNotification(message['notification'])
: showNotification(message['aps']['alert']);
return;
}, onResume: (Map<String, dynamic> message) {
print('onResume: $message');
return;
}, onLaunch: (Map<String, dynamic> message) {
print('onLaunch: $message');
return;
});
// For testing purposes print the Firebase Messaging token
String token = await _firebaseMessaging.getToken();
print("FirebaseMessaging token: $token");
_initialized = true;
}
}
At this point you would most likely save the token to your MongoDB database and associate the token with your user and that specific device. Of course you would have to also install the firebase core and for Flutter as well and do all of the necessary configurations.
You are still able to maintain your NodeJS API and MongoDB database and use free cloud messaging service to push your notifications for your server to your device.

How to I pass a Stripe Firebase Cloud Function Error To The Client

When I create a cloud function to process a charge on a user’s card (by writing a stripe token to firebase and using a cloud function to charge), how do I pass errors (like a declined card due to insufficient funds) to the client. If it’s important, I’m using the firebase web sdk to send the tokens.
write the errors to a firebase database so that you can read the errors from the database and show them where you need to.
I decided to use a Firebase HTTP cloud function and just send the token to the link firebase sets for the function. Like so,
exports.addSourceToCustomer = functions.https.onRequest((req, res) => {
const token = req.body.token // use the stripe token however you like here
// when an error occurs use res.status(errorCode).send(errorMessage);
// which sends the error back to the client that made the request
});

Resources