We have 2 Android apps in one Firebase project container, the first app has FCM implementation on Cloud Function and it works well, but the second app will received this notification as well so using restricted_package_name in messaging option is what we are looking for. However the question is, do we need to update the app as well or just the function in Cloud Function? Thus everything related to filtering of push notif. will be handled by its API and all we need is to provide the package name for the target app.
According to documentation of restrictedPackageName
The package name of the application which the registration tokens must match in order to receive the message.
Do we need to handle token as well? Do we need to update the code in the app or just add the option in the function with NodeJs?
const options = { priority: 'high' };
exports.announcement = functions.firestore.document("Announcement/{doc_id}").onCreate((added) => {
const title = added.data().title;
const description = added.data().description;
const bigImage = added.data().bigImage;
const link = added.data().link;
const environment = added.data().environment;
const payload = {
data: {
title: title,
description: description,
bigImage: bigImage,
link: link,
environment: environment,
}
};
return admin.messaging().sendToTopic("Announcement", payload, options)
.then(val => {
console.log("Success!\n" + JSON.stringify(payload), val);
return true;
})
.catch(error => {
console.error("Failed to send notification.", error);
return true;
});
});
From Firebase side it is not recommended to use same project for 2 different applications, which was also mentioned in this blog. If you want to use restricted_package_name you need to update the code so that the object sends it in notification. You can find a small example here.
Related
I'm starting my adventure with Firebase cloud functions in my adnroid app in Android Studio and I have no experience with it. What is more I have never used javascript before so everything seems to be new for me. I would like to know if I can make a scheduled function that works like this :
At first function checks if value from realtime databse isn't zero.
If not, function checks if another value from realtime database is not bigger than 7.
If not, the value in database is increased by 1.
And then the notification is send.
I made test function to check if data from database are taken corectly but it execute with error "Firebase is not defined".
exports.scheduledFunction = functions.pubsub.schedule('every 5 minutes').onRun((context) => {
var user = user.uid;
var myRef = firebase.database().ref(user + "/CurrentChallenge/numOfActiveChallenge");
myRef.on('value', (snapshot) => {
const data = snapshot.val();
console.log(data);
});
In a Cloud Function, if you want to interact with the Firebase services, you need to use the Admin SDK.
Also, if you want to read a database node in a Cloud Function, it is more appropriate to read once the node (with get() or once()) instead of setting a listener with on(). As a matter of fact the CF has a short life time and setting a listener is therefore not the correct approach.
It is nor clear how you get the value of the user variable. There is no user in a Scheduled Cloud Function. You need to adapt this line, because, as such it will not work.
Finally, it is important to note that you need to terminate a Cloud Function when all the asynchronous work is completed, see the doc. In the case of a background triggered Cloud Function (e.g. a Pub/Sub schedules Cloud Function) you must return the entire chain of promises returned by the asynchronous method calls. Another possibility is to use async/await, as shown below, and return a value (e.g. null) when all the asynchronous work is completed.
So, the following code skeleton should do the trick:
// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');
// The Firebase Admin SDK to access Firestore.
const admin = require('firebase-admin');
admin.initializeApp();
exports.scheduledFunction = functions.pubsub.schedule('every 5 minutes').onRun(async (context) => {
var user = ... // Set the value of user
const db = admin.database(); // Admin SDK
const snapshot1 = await db.database().ref("...").get();
if (snapshot1.val() !== 0) {
const snapshot2 = await db.database().ref("...").get();
if (snapshot2.val() <= 7) {
await db.ref("...").update({
fieldName: firebase.database.ServerValue.increment(1)
});
//send the notification
// See https://github.com/firebase/functions-samples/blob/main/fcm-notifications/functions/index.js
} else {
return null;
}
} else {
return null;
}
});
Cloud functions are secure environment just like any server. Generally you use the Firebase Admin SDK when using Firebase in Cloud functions or your own servers. To add firebase admin, open terminal and go to the function directory and run the following command:
npm install firebase-admin
The important thing to note is admin sdk doesn't obey any database security rules as the name says. It has privileged access.
You can try the following code.
const admin = require("firebase-admin")
admin.initializeApp()
exports.scheduledFunction = functions.pubsub.schedule('every 5 minutes').onRun(async (context) => {
const myRef1Value = (await admin.database().ref("path/to/resoures").once("value")).val()
if (myRef1Value > 0) {
//make another request
}
}
Similarly make multiple requests as needed (sorry for throwing bunch of JS concepts but feel free to ask any queries)
Another thing I noticed is you are trying to get user ID in it. Scheduled Cloud Functions are not invoked by any user so you can't get any UID in that Cloud function. Can you clarify what is your use case so we can figure out a work around for this?
But what you want to achieve is simple chain if else statements and doing stuff.
You'll need to import and initialize the Firebase Admin SDK as shown here:
// The Firebase Admin SDK to access the database
const admin = require('firebase-admin');
admin.initializeApp();
With that, you can then use it with:
var myRef = admin.database().ref(user + "/CurrentChallenge/numOfActiveChallenge");
myRef.once('value', (snapshot) => {
...
I am trying to measure the latency between having a message exit Firebase Servers and being received on an Android app via the Firebase SDK. I have BigQuery integrated with my Firebase project, and have tried adding the following code:
// In the manifest:
<meta-data android:name= "delivery_metrics_exported_to_big_query_enabled"
android:value="true"/>
// In my Application object:
FirebaseMessaging.getInstance().setDeliveryMetricsExportToBigQuery(true);
The code seems to be exporting data to BigQuery. However, to calculate what I want I need timestamps for two different types of events associated to the same message id, "MESSAGE_ACCEPTED" and "MESSAGE_DELIVERED". Then, all I have to do is run a simple query that calculates the timestamp difference between those two.
My problem is: I can never seem to get the "MESSAGE_DELIVERED" variant for a given message id. I only ever get the "MESSAGE_ACCEPTED" side of the equation.
I am sending messages to the Android device via my own JavaScript app, and the request I make is like so:
app.get('/triggerAnt', function(req, res){
axios.post('https://fcm.googleapis.com/fcm/send', {
to:<TOKEN_FOR_DEVICE_GOES_HERE>,
notification:{
"title":"TESTNOTIFICATIONLATENCY",
"body":"TESTINGLATENCY"
},
fcm_options: {
analytics_label:<LABEL_HERE>
}
}, {headers: headers})
.then((response) => {
console.log(response.status);
}, (error) => {
console.log(error);
});
})
I would like to point out that the notification does effectively reach the device and I can open it too.
Is this delay on BigQuery's side or am I doing something wrong?
Thank you.
I'd like for users to be able to share a link (e.g. app.com/SKFLA - this is primarily because deep links on their own aren't clickable) via Facebook etc. When clicked, this redirects to a deep link app://SKFLA. If the app is installed, this opens the app - this is all working fine so far. But if the app isn't installed, I'd like to open the app store on the relevant page. Is this achievable? Thanks!
You need UNIVERSAL LINKS
Please check
IOS https://developer.apple.com/library/archive/documentation/General/Conceptual/AppSearch/UniversalLinks.html
Android
https://developer.android.com/training/app-links/
It might also require some extra server-side setup.
Not sure about native behavior.
We used third-party service like https://branch.io/deepviews/.
There is a bunch of similar services.
If someone is still stuck in this issue and needs easiest solution, you will love node-deeplink
1.) If app is installed: Calling an app through deep linking will always call componentDidMount of root component. So you can attach a listener there. Like:
Linking.getInitialURL()
.then(url => {
if (url) {
this.handleOpenURL({ url });
}
})
.catch(console.error);
Linking.addEventListener('url', this.handleOpenURL);
handleOpenURL(event) {
if (event) {
console.log('event = ', event);
const url = event.url;
const route = url.replace(/.*?:\/\//g, '');
console.log('route = ', route);
if(route.match(/\/([^\/]+)\/?$/)) {
const id = route.match(/\/([^\/]+)\/?$/)[1];
const routeName = route.split('/')[0];
if (routeName === 'privatealbum') {
Actions.privateAlbum({ albumId: id });
}
}
}
}
2.) If app is not installed: Just set up a route in your server and node-deeplink package will handle the bridging between web browser to app store when a app is not installed in your mobile.
By this, both the cases will be handled without any struggle
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I've created an app similar to Instagram, using Firebase as my back-end database. The app has all the features i.e users can like your post, comment on your post etc. But, now I am stuck with notifications part. I've read some docs about FCM and followed some tutorials. However, I couldn't find any specific tutorial on how to create notification with the title as the name of the person who liked/commented on the post, and body of message as the content of the comment. Do I have to use PHP and mySQL to do this all? Or it can be done solely using JAVA?
Don't have enough rep to comment so I'll put this here.
Firebase released Firebase Functions recently.
Functions integrates the Firebase platform by letting you write code that responds to events and invokes functionality exposed by other Firebase features.
Lucky for you, the problem of sending notifications when one of your users follows another user is one of the example use cases for Firebase Functions.
You can check it out here.
Yes you'll need to make an app server to send notifications from device to another. Your app server will have the API of firebase FCM, and service account of Firebase database.
Following is a node.js code.The function listenForNotifications() is a listener attached to your database as to whenever you want to send lets say a follow request. On follow button click in your app you will add the an entry in your database in "Following" root node. Then as the entry is added from your mobile app the request.on("child_added"..) gets fired as there is an entry. Then the function routes the message to the person you want to send request to via the Token. i.e request.requestToToken
Database Structure of "Following" node:
+--Root
+-.
+--.
+----Following
+---------pushKey /auto-generated
+----------------requestToToken /token of device you want to send notification
+---------------- requestFromToken / token of device that sent the notification
var firebase = require('firebase-admin');
var request = require('request');
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.status(200).send('Hello, world!');
});
// Start the server
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}`);
console.log('Press Ctrl+C to quit.');
});
var API_KEY = ".......your key"; // Your Firebase Cloud Messaging Server API
// Fetch the service account key JSON file contents
var serviceAccount = require("....your database service account.json");
// Initialize the app with a service account, granting admin privileges
firebase.initializeApp({
credential: firebase.credential.cert(serviceAccount),
databaseURL: "https://dropit-b357a.firebaseio.com"
});
ref = firebase.database().ref();
process.stdout.write("I AM HERE... SERVER RUNNING MAYBE: ");
function listenForNotificationRequests() {
var requests = ref.child('Following');
requests.on('child_added', function(requestSnapshot) {
var request = requestSnapshot.val();
sendNotificationToUser(
request.requestToToken,
request.requestFrom,
function() {
return;
}
);
}, function(error) {
console.error(error);
});
};
function sendNotificationToUser(username, message, onSuccess) {
request({
url: 'https://fcm.googleapis.com/fcm/send',
method: 'POST',
headers: {
'Content-Type' :' application/json',
'Authorization': 'key='+API_KEY
},
body: JSON.stringify({
notification: {
title: message
},
to : username
})
}, function(error, response, body) {
if (error) { console.error(error); }
else if (response.statusCode >= 400) {
console.error('HTTP Error: '+response.statusCode+' '+response.statusMessage);
}
else {
onSuccess();
}
});
}
// start listening
listenForNotificationRequests();
I just had my first contacts with the ionic framework. I've worked with Phonegap and AngularJS before however, so it was not all that new to me.
I found out that there is this new feature to use Google Cloud Messaging push notifications in Ionic, through the Ionic Push feature (http://blog.ionic.io/announcing-ionic-push-alpha/).
Related lines of code from app.js
angular.module('starter', ['ionic','ionic.service.core', 'starter.controllers', 'starter.services'])
.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
cordova.plugins.Keyboard.disableScroll(true);
}
if (window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleLightContent();
}
// enable push notifications
Ionic.io();
// enable users (http://docs.ionic.io/docs/user-quick-start)
// this will give you a fresh user or the previously saved 'current user'
var user = Ionic.User.current();
// if the user doesn't have an id, you'll need to give it one.
if (!user.id) {
user.id = Ionic.User.anonymousId();
// user.id = 'your-custom-user-id';
}
console.log('user-id:' + user.id);
//persist the user
user.save();
var push = new Ionic.Push({
"debug": true,
"onNotification": function(notification) {
var payload = notification.payload;
console.log(notification, payload);
},
"onRegister": function(data) {
console.log(data.token);
}
});
push.register(function(token) {
console.log("Device token:",token.token);
});
push.addTokenToUser(user);
console.log('token added to user');
});
})
Log from ionic serve
ionic $ 0 361081 log Ionic Core:, init
1 361083 log Ionic Core:, searching for cordova.js
2 361085 log Ionic Core:, attempting to mock plugins
3 361155 log user-id:1cc3d21c-b687-4988-b944-ad07b1a677c8
4 361158 log Ionic Push:, a token must be registered before you can add it to a user.
5 361159 log Ionic Push:, token is not a valid Android or iOS registration id. Cannot save to user.
6 361159 log token added to user
7 361160 log Ionic Push:, register
8 361160 error ReferenceError: PushNotification is not defined, http://localhost:8100/lib/ionic-platform-web-client/dist/ionic.io.bundle.min.js, Line: 2
9 361526 log Ionic User:, saved user
Any input is welcome, I am also more than happy to provide more information if needed.
EDIT 10/05/2015:
found out that dev_push = false only works on physical devices, not in browser
I tried to add token to user before even registering the user
I'm having the same problem, seems not many answers online at the moment.
but even on real device, it won't save the token to user.
I just had to decide go live without push first, then use ionic deploy to follow up.
also I think you have to put this line
push.addTokenToUser(user);
inside the register callback according to this doc
http://docs.ionic.io/docs/push-usage
You also need to declare 'ionic.service.push' as a dependency in your angular module if you'd like to use it.
angular.module('starter', ['ionic','ionic.service.core', 'ionic.service.push'])
I have it like this and it works:
Ionic.io();
var user = Ionic.User.current();
if (!user.id) {
user.id = Ionic.User.anonymousId();
// save our newly created user
user.save();
}
var push = new Ionic.Push({});
push.register(function (token) {
console.log("Got Token:", token.token);
// now we have token, so add it to user
push.addTokenToUser(user);
// don't forget to save user to Ionic Platform with our new token
user.save();
});
// set this user as current, so we can acess him later
Ionic.User.current(user);
Did you use this
ionic config set dev_push true-if testing in emulator or laptop
ionic config set dev_pushfalse - if testing on the phone
ionic push --google-api-key Your API Key
ionic config set gcm_key Project Number
Your token is the registration id that is unique for a particular device. That is sent to you by android.
Your Phone (With the API Key)---------> to Google's GCM
Google GCM (recognises it's you via your Project number and API key) -----> Oh it's you let me make a note of it. (Save a token id in it's DB and send's one to you.)
You get a registration id unique for your device(will change if an app is uninstalled).
You call your server say hey it's me your user. Please Notify me if you get something.
Server obliges, says, okay dude, I got this. Saves the registration id with your details probably your username in it's DB.
Now from Server.
I need to inform my users about a great deal(or an accident or something).
Pull up all targeted registration Id's from DB(maybe on some condition)
registrationIds.push(regId) //in a loop
and sender.send(message, registration, function(err, result){
});
Send to Google. Google see's oh only these many people(not all maybe) from this API Key need a notification. no Problem I will notify them and you receive a notification, my dear friend.
As mentioned in the link , Adding token to the $ionicUser is done by doing , user.addPushToken(pushToken); .
For this to work you should first configure the app not to use developement pushes by ,
ionic config set dev_push true
After initialising Ionic.io and Ionic.push , load the user or create one with a new random id ,
Ionic.io();
var push = new Ionic.Push();
Ionic.User.load(localStorage.id).then(function (user) {
Ionic.User.current(user);
pushFactory.register(push, user);
}, function (error) {
/*the user with that id is not present , so create one with a random id and register the push */
});
The push factory is defined as below,
function pushFactory() {
return {
'register': function (push, user) {
push.register(function (pushToken) {
user.addPushToken(pushToken);
user.save().then(function (answer) {
console.log('user saved'+answer);
})
})
}
}
}