Filter web notifications by client-side - javascript

When I send a notification to some topic like...
const message = {
data: { cost: 49 },
topic: 'apple'
}
admin.messaging().send(message)
Question is about preventing/filtering notifications if user set something like >= 50 ? (Firestore/localStorage?)
How can I do that?
As I can think it should be filtered with messaging-sw.js but how and it's possible?
Or any better idea or I am missing something?

Case 1: When your app is in the foreground
Case 2: When your app is in background
Save the user's data in IndexedDB, since users can access IndexedDB data in the service worker
You have to customize the function setBackgroundMessageHandler in the firebase-messaging-sw.js file as this guideline to handle the user's options
Note: If you set notification fields in your message payload, your setBackgroundMessageHandler callback is not called, and instead the SDK displays a notification based on your payload.
Anyway, using a filter on the client-side is not a good approach, it should be done in server-side

Related

React Native with Expo - Schedule a notification to be sent globally at 8pm to all users for all time zones

I am using React native with Expo and i want to schedule a notification. I want it to be sent globally at 8pm to all users for all time zones. Can i achieve this with expo? If so, how i can i achieve this? Should i use a local or a push notification? Can someone please point me in the right direction? Thanks in advance!
You have two approaches to achieve this:
send notification locally
send notification using server
Local notifications
You can very easily schedule recurring local notification. This means that all users who gives you permission to send them notifications will receive notification at the time you select. Here are some code snippets that should help you:
/**
* Get permissions from user.
* This needs to be done both for local and server notifications.
* Call this method after user click some 'Allow notifications' button
*/
const getPermission = async () => {
if ( Platform.OS !== 'web' ) {
const { status: existingStatus } = await Notifications.getPermissionsAsync();
if ( existingStatus !== 'granted' ) {
__DEV__ && console.log( 'Requesting notification permission' );
const { status } = yield Notifications.requestPermissionsAsync();
if ( status !== 'granted' )
throw new Error( "Didn't receive permission to save notifications" );
__DEV__ && console.log( 'Permission for notifications granted' );
// This code is needed for Android to work
if ( Platform.OS === 'android' ) {
Notifications.setNotificationChannelAsync( 'default', {
name: 'default',
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: '#FF231F7C',
} );
}
}
After you receive permissions you need, you can schedule recuring notifications very easily:
const scheduleDailyNotifications = async () => {
if ( self.gotPermission ) {
// It's useful to save notification id so that you can edit/delete notification later
const idOfNotification = await Notifications.scheduleNotificationAsync( {
content: {
title: "App Name - Daily Remainder",
body: "Text you want to show in your notification",
sound: 'default'
},
trigger: {
hour: 14, // show this notification every day, 14:00
repeats: true
},
} );
}
And that's it! Now your users will receive notification every day.
As you probably see from this example, local notifications have quite a few shortcommings, the biggest is that you need to know which notification you want to send at build time of your app and that you can't really manipulate with them well.
Use this approach if you want for example to remind users to open your app once a day and do something (good for education apps). For more complicated use cases, you need to use server notifications, which are a lot of harder to implement.
Server notifications
Server notifications are not set in the app, instead, you configure your app as 'receiver' of notifications you send from your server. To do this, you need to configure some third party services.
On Android, you won't avoid using Firebase, as this is the only way for Android devices to receive notifications from your server.
As this requires a lot of code, I will only provide you with directions in this answer. I will stick with Expo Push Notifications as you already use Expo and it's free (but note that there are other services you can use)
Get permissions from user (same as with local notifications)
When gettings permissions from user (point 1), also get Expo Push token and save it to your database (provided code is from Expo documentation https://docs.expo.dev/versions/latest/sdk/notifications/)
import * as Notifications from 'expo-notifications';
// .. rest of getPermission method
const expoPushToken = await Notifications.getExpoPushTokenAsync({
experienceId: '#username/example',
});
// .. save expoPushToken under user in your database. It is preferable to allow one user to have multiple tokens
Configure app to receive notifications. See https://docs.expo.dev/versions/latest/sdk/notifications/, specifically check API/Push Notifications and how to use Notifications.setNotificationHandler and useEffect method that they use to configure listeners in their App.tsx file
Register your app on Firebase. Follow this guide to acquire ./google-services.json and configure your app.json https://docs.expo.dev/push-notifications/using-fcm/
Now devices are configured to receive notifications. Last thing you need to do is actually to send it.
I assume your app have some kind of server side. You need to configure this server to send notifications to your users. As you want recuring notifications, this will be a CRON task that runs once a day. Setting up a CRON task depends on your backend, but should be straightforward in major coding languages.
In CRON task, send notifications. There is a lot of documentation about how to do it here: https://docs.expo.dev/push-notifications/sending-notifications/, but it can actually be pretty easy if you are using coding language for your server that is supported by Expo Push Notifications SDK. If you visit the documentation, there is a section dedicated to links various SDKs (Node.js, Python, Java, C#, Go...), you can find example app for your language under these links
And that's it! Quite a lot of steps for server notifications, but they are more powerful than local as you have complete control over them.
Yes, it is possible. I can't tell from your question if you've already implemented push notifications for your app and what provider you used. I'll assume you haven't at all, so start there.
OneSignal, Firebase, Expo-notifications etc. There are many providers that allow scheduling of push notifications.
OneSignal-Expo documentation:
https://documentation.onesignal.com/docs/react-native-expo-sdk-setup
Expo-server-sdk example:
https://github.com/expo/expo-server-sdk-node#usage

Send Notifications using target feeds with getstream.io

I've been working with getstream.io for a while
and currently I'm facing an issue with the notifications.
To start using notifications I thought it was easier to implement in reactions due to having the targetFeeds property, but I'm facing an access error. I'm trying achieve it doing the next.
UserA commenting in UserB publication
// Client is initialized with UserA info
const comment = await client.reactions.add('comment', activity.id, { data }, { targetFeeds: [`notifications:UserB.ID`] });
My question is how to send a notification to UserB notification feed.
The result I expect is userB receiving a notification like "userA has commented in your publication" or alike.
I believe the default feed for notifications is 'notification' (no s.)
Also I'm not fully aware of what you are tying to accomplish, but just a heads up there is also the TO field for targeting.
https://getstream.io/docs/targeting/?language=js
The issue as first pointed by Sanchaz was that I was using notifications as slug for the notification feed instead of notification, I thought that wasn't the case because I created the notification feed with notifications slug.
StreamIO support stated that if the notification feed doesn't match notification slug, the default permissions doesn't apply, therefore the solution was to rename the slug from notifications to notification.

track message reports using Multicast ID on google firebase in php

Is there a way to track delivery report of a particular message that have been sent via FCM to android device, i found we can add delivery_receipt_requested to track delivery and i have added that my json data as follows,
{"to":"KEY",
"data":{
"data":{
"title":"test message",
"message":"sent",
"image":null}
},
"notification":{
"delivery_receipt_requested":true
}
}
and i receive a response
{"multicast_id":6417448921485349071,"success":1,"failure":0,"canonical_ids":0,"results":[{"error":"false"}]}
In php or javascript i need something like if we pass that multicast_id need to get the current status of the text. I found it was almost nightmare to get the desired result, but its not impossible is there anyway guys?
There is currently no way to manually ask the FCM server about the status of the sent message.
Based from your post, it seems you already did your homework on checking the FCM service. Implementing the delivery receipts is the only way (AFAIK) that you could attain the behavior you mentioned in your post.
Implementing the delivery receipt not only needs the delivery_receipt_requested parameter in your payload, you have to implement an XMPP server protocol as well. Along with the Upstream Messaging part on your client app (for the acknowledgement part).

Send FCM Notification to multiple users using their UID through cloud functions

i have users Uid in an 'users' array as ['uid1','uid2'] now i will be sending notifications to these users in cloud function?
exports.sendNotificationFromCr = functions.database.ref('/cr/{crUid}/notifications/{notificationid}/').onWrite(event => {
const uid = ['uid1','uid2']; // some how i get this.
// some work to send notifications
// to all tokens of uid1 and uid2.
}
here is the database structure:
users/
uid1/
name:{name}
FCM-key/
token1:true
token2:true
uid2/
...
FCM-key/
token3:true
using ['uid1','uid2'] i want to send notification to all 3 tokens in my database. how to do that?
If you're using something like firebase. Then you would want to have a notifications database model, that has the userId, the notification title, body and perhaps image, also a seen flag (true or false).
You would then post notifications either from your clients or from your cloud server code into the database. One per client/notification. If you have thousands of users you would use some sort of server-side cronjob, to offload this so that it runs outside of say your client to server API.
On the clients, you would be listening for new rows in that model filtering on the userId and when they appear, display them to the client in your UI. Once the client has seen the notification you would mark it as seen on the client.
Without knowing what platforms, code base, DB you are using it's impossible to explain in code terms how this would be done.
There are various API's for IOS and Android and Firebase that resolve this.

What should I use as the document key to maintain idempotency?

What should I use as the document key to maintain idempotency?
I'm building a text messaging application that uses CouchDB (with PouchDB on the client) to store messages locally. Twilio (SMS provider) generates an ID for each message, and I use that as the CouchDB document ID. This way fetching messages from Twilio's API is idempotent -- if I come across the same message twice, it will only store one copy in my database.
// twilio API /messages
[
{smsid: 123, body: 'foo'},
{smsid: 456, body: 'bar'}
]
// transformed into couchdb docs
[
{id: 123, doc: {_id: 123, body: 'foo'}},
{id: 456, doc: {_id: 456, body: 'bar'}}
]
This is easy to do when fetching messages from twilio. But when the user sends an outbound message from the client application, there is no twilio ID yet because it hasn't been sent to twilio yet.
A traditional approach would involve POSTing the message to some endpoint on my server, and have the server send it to twilio, then add the record to the database once it has the smsid from twilio's response. The problem with this is (a) there's a noticeable delay from when the user presses "send" and when the message shows up in the UI, and (b) we can't take advantage of couchdb's auth system.
Instead, I have it setup so the client generates a random ID, and inserts it into the database (via pouchdb w/sync). The server then watches for new outbound records added and dispatches them to twilio.
This approach works fine, but if I GET /messages again, it's no longer idempotent -- it would create an additional record for the outbound message because I don't have a couchdb document with that message's smsid as its key (it didn't have an smsid when it was added to couchdb).
Is there a way around this or a better approach?
An idea to make this work is that you must rely on other data from each message, and ignore Twilio's smsid.
Perhaps hashing together the user id, the message body and an abrangent version of the timestamp (for example, int(UNIX-TIMESTAMP-IN-SECONDS/100) will tolerate a delay of 100 seconds between the time your server gets the message and Twilio acknowledges it).
Thanks for your replies. This was a tough one. #rnewson from #couchdb in freenode was kind enough to spend some time thinking about this one and proposed a solution that worked out great:
Message documents in couchdb use an arbitrary _id that can be generated by the server or the client
When the client sends a message, it generates an arbitrary _id and puts it into the database. The server observes this and dispatches it to twilio, then updates the database document by adding a twilio_id property to the document
I created a view to index the documents by twilio_id
When the server starts, it fetches the latest messages from twilio. In order to prevent adding duplicate records to the database, it queries the above view for each twilio id. For each match, it uses the match's _id and _rev to perform an update. For records with no matches, it generates a new arbitrary _id to perform an insert.
For anyone curious, here's the code.
Thanks again for your responses!

Categories