I want to Send push notifications from meteor website to android application using Google cloud messaging.
The way I've done it is to use the package raix:push.
To do this, first install the package, then set up a config.push.json file in your root directory. This file contains the settings for the push notifications. The most basic file you can have that allows you to use Google cloud messaging is just:
{
"gcm":{
"apiKey":"yourApiKey",
"projectNumber": 000000000
}
}
Then you can send a push notification by calling a meteor method:
Meteor.methods({
"sendPush": function(title, text, userId){
Push.send({
from: 'yourName',
title: title,
text: text,
query:{userId: userId}
});
}
});
and also calling:
Push.allow({
// Change this to determine whether the user with id userId can send
// the notification
send: function(userId, notification) {
return true; // Allow all users to send
}
});
on the server.
The above method would send a push notification to a user with _id equal to userId. You can make the query more complicated to send multiple notifications at once, just keep in mind that the field with the user's id is called userId, since this package creates a new collection to emit notifications.
This package is documented quite well: https://github.com/raix/push. Just follow the instructions for android, and take a look at the simple example.
If you don't have an api key or project number, you can follow the instructions in the documentation to set up Google cloud messaging.
Related
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
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
So I'm creating a basic jackpot betting site for fun and it allows users to put money into a pot and then based on the percentage of money each user puts in it randomly picks a winner. It's working fine at the moment but I feel like the way I'm updating the jackpot page with ajax is really bad. At the moment I have javascript that makes an ajax request each second to get the pot info (size of the pot, players, etc..). I feel like there is a much better way to do this. Is it possible to only make an ajax call when the database is updated? Thanks!
My javascript at the moment:
setInterval(update, 1000);
function update() {
getPotID();
$.ajax({
type: "POST",
url: "/jackpot/update/" + potID,
complete: function(response) {
$('.live-jackpot').html(response.responseText);
getPotInfo();
},
error: function(xhr, status,error) {
console.log("Error");
}
});
}
as said from 7urkm3n, ActionCable has great advantage for this functionality.
Right now you are writing Javascript code that is executed on the client side. Every user that will start a GET http request to your site, will load that javascript files. They will start performing POST request every second to your backend server.
ActionCable is a websocket preinstalled in Rails 5. This means that to configure the notifications with ActionCable and Rails 5, you already have installed everything in your app (if you are using rails 5), you just need to install Redis on your local machine for testing the app in development.
I am not an expert, my understanding is that you use a specific database called redis to store the information about the subscription. I quote a useful article
So PubSub is this concept that Redis and Postgres and a few other things supports, and basically you have this ability to have Channels and the ability to subscribe (and receive those messages) and publish to those channels and anyone listening will then receive those messages.
An example of this is a ChatroomChannel, you could have people publishing messages to the ChatroomChannel and anyone who was subscribed to the ChatroomChannel would receive the broadcast from the channel with the websocket.
This is something you are missing, this way you could only find which users are actually on the playing page and which users are just browsing around, based on this ActionCable creates a channel to communicate between server and client and then creates a subscription to distinguish users that are actually on the playing page and those that left and should not be anymore notified
I quote another useful article
Before we dive into some code, let's take a closer look at how Action Cable opens and maintains the WebSocket connection inside our Rails 5 application.
Action Cable uses the Rack socket hijacking API to take over control of connections from the application server.
For every instance of your application that spins up, an instance of Action Cable is created, using Rack to open and maintain a persistent connection, and using a channel mounted on a sub-URI of your main application to stream from certain areas of your application and broadcast to other areas.
so every user that connects, ActionCable creates a channel that uses a specific url localhost:3000/cable to communicate between server and client (browser)
Action Cable offers server-side code to broadcast certain content (think new messages or notifications) over the channel, to a subscriber. The subscriber is instantiated on the client-side with a handy JavaScript function that uses jQuery to append new content to the DOM.
This means that the server can call the client with parameters and change the page with jquery functions. For ex. appending a div, with a new message.
In my app https://sprachspiel.xyz I do the following in the MessagesController#create
ActionCable.server.broadcast 'messages',
message: message.content,
user: message.user.name,
chatroom_id: message.chatroom_id,
lastuser: chatroom.messages.last(2)[0].user.name
head :ok
so basically, I have my message in my controller and I can update the client by using the ActionCable.server.broadcast function
then in my asset pipeline file /app/assets/javascripts/channels/messages.js I have the following code that trigger the change in the browser adding the message
App.messages = App.cable.subscriptions.create('MessagesChannel', {
received: function(data) {
$('#messages').append(this.renderMessage(data));
},
renderMessage: function(data) {
return "<br><p> <strong>" + data.user + ": </strong>" + data.message + "</p>";
}
});
I build an app called https://sprachspiel.xyz that is an actioncable app, this is the github page for the project, on my portfolio you can read more info about my app, so please ask me anything, I'll be happy to look into it!
Good luck
Fabrizio
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.
I have Firebase storage bucket and I would like to use Node.js Google-cloud notification API in order to listen to changes in the storage.
What I have so far:
const gcloud = require('google-cloud');
const storage = gcloud.storage({
projectId: 'projectId',
credentials: serviceAccount
});
const storageBucket = storage.bucket('bucketId');
Now from what I understand I have to create a channel in order to listen to storage changes.
So I have:
const storageBucketNotificationChannel = storage.channel('channelId', 'resourceId');
This is the threshold where the docs stop being clear, as I can't figure out what channelId a resourceId stand for.
Nor do I understand how to declare listening to channel changes itself. Are there any lifecycle-type methods to do so?
Can I do something like?
storageBucketNotificationChannel.onMessage(message => { ... })
Based on the existing documentation of the Google Cloud Node.js Client and the feedback from this Github issue, there is presently no way for the node client to create a channel or subscribe to object change notifications.
One of the reasons being that the machine using the client may not necessarily be the machine on which the application runs, and thus a security risk. One can still however, subscribe to object change notifications for a given bucket and have notifications received a Node.js GAE application.
Using Objects: watchAll JSON API
When using gsutil to subscribe, gsutil sends a POST request to https://www.googleapis.com/storage/v1/b/bucket/o/watch where bucket is the name of the bucket to be watched. This is essentially a wrapper around the JSON API Objects: watchAll. Once a desired application/endpoint has been authorized as described in Notification Authorization, one can send the appropriate POST request to said API and provide the desired endpoint URL in address. For instance, address could be https://my-node-app.example.com/change.
The Node/Express application service would then need to listen to POST requests to path /change for notifications resembling this. The application would then act upon that data accordingly. Note, the application should respond to the request as described in Reliable Delivery for Cloud Storage to retry if it failed or stop retrying if it succeeded.