Ionic3 Firebase notification not received on device - firebase

In brief: Firebase Notifications sent via Firebase Cloud Functions shows that message is sent. However, message is not received in the device. (Only tested in Android. Don't know about iOS)
Hello, I'm on a Ionic 3 project which uses Firebase Cloud Firestore, Cloud Functions and other Firebase services.
App workflow:
Upon new document creation (as in new reservation), the admin SDK should send push notification to the particular device which should arrive in the device.
Problem:
When checking in the Cloud Functions log, it shows message is successfully sent and the Triggering functions finished without any error. But no message has been received yet. However, when sending message from Firebase Notification Console, each message arrives perfectly.
Code:
index.ts (Cloud Functions)
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp(functions.config().firebase);
exports.notifyOnNewBooking = functions.firestore
.document('users/{userId}/bookings/{bookingId}')
.onCreate( event => {
const bookingData = event.data.data();
// construct notification message here
const message = {
notification: {
title: 'Reservation confirmed!',
body: 'Your reservation at someplace at sometime is confirmed',
icon: 'https://image.ibb.co/iBwekx/icon.png'
}
};
// send notification with message right away
return admin.messaging().sendToDevice(bookingData.deviceFCMToken, message, {priority: 'high'})
.then(resp => {
console.log("sent successfully", resp);
})
.catch(err => {
console.error("could not send notification", err);
});
});
app.component.ts (Ionic)
...
// Ionic Native wrapper
import { FCM } from '#ionic-native/fcm';
....
#Component({
template: `
....
....
`
})
export class MyApp {
...
constructor(..., private fcm: FCM) {}
ngOnInit() {
this.fcm.onNotification()
.subscribe(resp => {});
}
}
Firebase Cloud Functions log shows this:
Ionic CLI info
cli packages: (/usr/local/lib/node_modules)
#ionic/cli-utils : 1.19.1
ionic (Ionic CLI) : 3.19.1
System:
Node : v9.3.0
npm : 5.5.1
OS : macOS High Sierra
Misc:
backend : pro
Cloud Functions package.json dependencies
"dependencies": {
"#google-cloud/functions-emulator": "^1.0.0-beta.3",
"firebase-admin": "~5.8.1",
"firebase-functions": "^0.8.1",
"firebase-tools": "^3.17.4",
"global": "^4.3.2"
},
config.xml
<plugin name="cordova-plugin-fcm" spec="^2.1.2">
<variable name="SENDER_ID" value="845539284400" />
</plugin>
Note: There is only one subscription which is at the root component in the app. And I'm on Firebase Spark plan which is free but often notifies in the log that - Billing account not configured. External network is not accessible and quotas are severely limited. Configure billing account to remove these restrictions.

Modified the function in Cloud Functions to this below and now notifications is being received in the Notification tray when the app is in Background and in the subscription response when the app is in Foreground.
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp(functions.config().firebase);
exports.notifyOnNewBooking = functions.firestore
.document('users/{userId}/bookings/{bookingId}')
.onCreate(event => {
const bookingData = event.data.data();
// construct notification message here
const message: admin.messaging.Message = {
token: bookingData.deviceFCMToken,
android: {
notification: {
title: 'Reservation successful',
body: `Your reservation at ${bookingData.restaurant_name} is confirmed.`,
icon: 'https://image.ibb.co/iBwekx/icon.png'
}
},
apns: {
headers: {
'apns-priority': '10'
},
payload: {
aps: {
alert: {
title: 'Reservation successful',
body: `Your reservation at ${bookingData.restaurant_name} is confirmed.`,
},
badge: 1
}
}
}
};
// send notification with message right away
return admin.messaging().send(message)
.then(resp => {
console.log("sent successfully", resp);
})
.catch(err => {
console.error("could not send notification", err);
});
});

Related

How to get React Native Push Notifications using FCM?

I'm using React Native Push notifications for my iOS version of my React Native app and I'm trying to send a test notification using Firebase Cloud Messaging.
Here's my code that I have in a PushController.js file that I import into my app.
import React, { Component } from "react";
import PushNotificationIOS from "#react-native-community/push-notification-ios";
import PushNotification from "react-native-push-notification";
// var PushNotification = require("react-native-push-notification");
export default class PushController extends Component {
componentDidMount() {
PushNotification.configure({
// (optional) Called when Token is generated (iOS and Android)
onRegister: function (token) {
console.log("TOKEN:", token);
},
// (required) Called when a remote is received or opened, or local notification is opened
onNotification: function (notification) {
console.log("NOTIFICATION:", notification);
// process the notification
// (required) Called when a remote is received or opened, or local notification is opened
notification.finish(PushNotificationIOS.FetchResult.NoData);
},
// (optional) Called when Registered Action is pressed and invokeApp is false, if true onNotification will be called (Android)
onAction: function (notification) {
console.log("ACTION:", notification.action);
console.log("NOTIFICATION:", notification);
// process the action
},
// (optional) Called when the user fails to register for remote notifications. Typically occurs when APNS is having issues, or the device is a simulator. (iOS)
onRegistrationError: function (err) {
console.error(err.message, err);
},
// IOS ONLY (optional): default: all - Permissions to register.
permissions: {
alert: true,
badge: true,
sound: true,
},
// Should the initial notification be popped automatically
// default: true
popInitialNotification: true,
/**
* (optional) default: true
* - Specified if permissions (ios) and token (android and ios) will requested or not,
* - if not, you must call PushNotificationsHandler.requestPermissions() later
* - if you are not using remote notification or do not have Firebase installed, use this:
* requestPermissions: Platform.OS === 'ios'
*/
requestPermissions: true,
});
}
render() {
return null;
}
}
It properly initializes and I get the token from onRegister().
But, I can't get the FCM to output a notification to my app; I've added the token to my test but I don't believe it works because it is an FCM token. So my question is how do I send a message using FCM and connect it to the React Native Push Notifications?

How to implement Firebase phone authentication with Ionic 4?

Is it possible to use phone authentication with Firebase and Ionic 4 in mobile apps?
I have seen some old tutorials implementing phone authorization with Ionic 3, but these seem to be outdated.
The firebaseui-web project does not support phone authentication for cordova apps, but I am unsure if that implies that Firebase phone authentication is impossible with ionic apps.
If you cannot use Firebase's phone authentication with Ionic 4, is there an alternative phone authentication service that does work with Ionic 4?
Yes. You can do it with Firebase's Javascript SDK, it will need the user to pass a CAPTCHA and then send the phone number a verification code which you can login and auth with, the process is explained here:
https://firebase.google.com/docs/auth/web/phone-auth#send-a-verification-code-to-the-users-phone
The problem is that the firebase auth sms service will only send messages when the app is in production mode (uploaded to the store). But to be able to test the methods from test mode, it is adding a test number in the white list of firebase.
In my case, I try these:
sms-verification.page.ts
sendSmsVerification(phoneNumber): Promise <firebase.auth.UserCredential> {
return new Promise((resolve, reject) => {
firebase.auth().useDeviceLanguage();
var verificationId;
var code;
const timeOutDuration = 60;
const tell = '+54' + phoneNumber;
this.FireBase.verifyPhoneNumber(tell, timeOutDuration).then(async (credential) => {
// alert(credential.instantVerification);
if (credential.verificationId) {
console.log("Android credential: ", credential);
verificationId = credential.verificationId;
} else {
console.log("iOS credential: ", credential);
verificationId = credential;
}
if (credential.instantVerification) {
code = credential.code;
this.verifySms(verificationId, code)
.then( resp => {
resolve(resp);
})
.catch( err => {
reject(err);
});
} else {
let prompt = await this.alertCtrl.create({
backdropDismiss: false,
header: 'Ingrese el codigo de confirmación del SMS.',
inputs: [{ name: 'confirmationCode', placeholder: 'Código de confirmación' }],
buttons: [
{ text: 'Cancelar',
handler: data => {
console.log('Cancel clicked');
resolve(data);
}
},
{ text: 'Verificar',
handler: data => {
code = data.confirmationCode;
this.verifySms(verificationId,code)
.then( resp => {
resolve(resp);
})
.catch( err => {
reject(err);
}); }
}
]
});
prompt.present();
}
}).catch(error => {
console.log('Error! Catch SMSVerificacion', error);
reject(error);
});
})
}
verifySms(verificationId, code): Promise <any> {
console.log('parametros de verifySms ', verificationId +' ', code);
const signInCredential = firebase.auth.PhoneAuthProvider.credential(verificationId,code);
return firebase.auth().signInAndRetrieveDataWithCredential(signInCredential);
}
Yes, it's possible to use firebase phone authentication using Cordova plugin,
cordova-plugin-firebase-authentication
Add this plugin to your ionic 4 project
cordova plugin add cordova-plugin-firebase-authentication --save
With this we can verify phone without using reCaptcha.
Note that this only work on real android device, not emulator or browser.
Function implementation
verifyPhoneNumber(phoneNumber, timeout)
cordova.plugins.firebase.auth.verifyPhoneNumber("+123456789", 30000)
.then(function(verificationId) {
// pass verificationId to signInWithVerificationId
});
or
AngularFire (With reCaptcha)
https://github.com/angular/angularfire
First, install angularfire lib into your project
npm install firebase #angular/fire --save
then import this lib into your class
import * as firebase from 'firebase/app';
code example:
firebase.auth().signInWithPhoneNumber(phoneNumber,recaptchaVerifier)
.then(confirmationResult => {
this.windowRef.confirmationResult = confirmationResult;
})

Sendgrid & Firebase Functions: Error Sending Transactional Email with Dynamic Template Data

Once a new vendor is registered on my Firebase Realtime Database, I want to send the new vendor a welcome email via Sendgrid. I've constructed a Firebase function newVendorEmail() to do this in my app's functions/src/index.ts folder and configured everything there as per https://app.sendgrid.com/guide/integrate/langs/nodejs/verify. I'm also able to retrieve vendor details from Firebase via onCreate() in newVendorEmail() and pass them to the dynamic_template_data part of the msg object without any problem. But when the newVendorEmail() function was triggered in Firebase Functions the email was not sent and I got this response instead in my Firebase Functions Console: TypeError: Object.values is not a function at Mail.setDynamicTemplateData (/user_code/node_modules/#sendgrid/mail/node_modules/#sendgrid/helpers/classes/mail.js:342:12). Help, please?
I've tried upgrading to the latest #sendgrid/mail npm package v6.4.0, tried switching to a new Sendgrid API key, tried storing this new API key in process.env as per Sendgrid's github example https://github.com/sendgrid/sendgrid-nodejs/blob/master/use-cases/kitchen-sink.md instead of functions.config(), but to no avail.
in node/process.env:
{ SENDGRID_API_KEY:
'SG....E',
...
}
in functions/src/index.ts:
'use strict'
const functions = require('firebase-functions')
const admin = require('firebase-admin')
const sendgrid = require('#sendgrid/mail')
// init function
admin.initializeApp()
//init firebase ref const
const ref = admin.database().ref()
// set sendgrid api from process env
sendgrid.setApiKey(process.env.SENDGRID_API_KEY)
export const newVendorEmail = functions.database
.ref('users/{userId}/profile')
.onCreate((snapshot, context) => {
// call field data using snapshot.val()
let msg
const userData = snapshot.val()
if (userData.type === 'vendor') {
// set email data
msg = {
to: userData.email,
from: {
name: 'Blk. Party',
email: '...#blkparty.com'
},
// custom templates
templateId: '...',
dynamic_template_data: {
subject: 'Welcome to Blk. Party!',
name: userData.name,
regLink: userData.regLink
},
}
}
// send email via sendgrid
return sendgrid.send(msg)
})
in package.json:
...
"dependencies": {
"#sendgrid/mail": "^6.4.0",
"firebase-admin": "~6.0.0",
"firebase-functions": "^2.1.0"
},
"devDependencies": {
"#sendgrid/mail": "^6.4.0",
...
}
...
I expect emails to be sent without any error.
I had the same problem. In my case, the solution was to switch from node6 to node8 in firebase functions.

Flutter: Firebase Pushnotification On Data Change

After getting the comment, i have deployed this folowing code to my firebase project and it was successfully deploed!.But there is no notifications been send to me.
Please check my Firebase Realtime database Screenshot here for better understanding.
[ITS SOLVED NOW:IT WILL SEND NOTIFICATIONS TO ONLY ONE ID ie My Admin Device]
WORKING CODE:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firbase);
exports.codeformypeople = functions.database.ref('items/{id}').onWrite(evt => {
const payload = {
notification: { title: 'New Customer Requested', body: 'Touch to Open The App', badge: '1', sound: 'default', }
};
const token ="Lsn-bHfBWC6igTfWQ1-h7GoFMxaDWayKIpWCrzC";//replace with ur token
if (token) {
console.log('Toke is availabel .');
return admin.messaging().sendToDevice(token, payload);
} else {
console.log('token error');
}
});
[
SEE THIS VIDEO LINK FOR MORE DETAILS
note:If your app is opened and minmized then it will show notification,but if the app is opened and you are using,or if the app is terminated force close then it will not work!!
You can use firebase cloud function to trigger notification. Here is snippet of cloud functions which i am using to trigger notification:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.pushNotification = functions.database.ref('/Notifications/{pushId}')
.onWrite(( change,context) => {
console.log("Push Notification event triggered");
var request = change.after.val();
var payload = {
data:{
username: request.userName,
}
};
admin.messaging().sendToDevice(request.userTokenId, payload)
.then(function(response){
console.log("Successfully sent message: ",response);
console.log(response.results[0].error);
})
.catch(function(error){
console.log("Error sending message: ", error)
})
})
Below i have provided my notification structure, you can see below.This function will trigger if any new data is being pushed in database notification node. To see what is output/error you are getting when this function is trigger go to firebase admin panel > Functions > Logs.
You have deployed function code perfectly, but you forgot to add refresh tokenId in your database as you can see in above picture i am saving userTokenId in my database and in function admin.messaging().sendToDevice(request.userTokenId, payload) i am using that tokenId, this tokenId is used to send notification to particular device, you can get this tokenId using FirebaseInstanceId.getInstance().getToken() and save this in your fbproject1 > items database sturcture. please refer this & this

Firebase functions nodemailer: gmail and oauth2 fails on the free plan

I am using Firebase functions with nodemailer to send email from a contact form on my website.
I am on the free plan, and as I understood Gmail API is considered to be a Google service and not general internet request, so it should work fine.
Here is my Typescript code
import * as functions from 'firebase-functions';
import * as nodemailer from 'nodemailer';
import { DocumentSnapshot } from 'firebase-functions/lib/providers/firestore';
export const sendMessage = functions.firestore.document('/emails/{pushKey}').onCreate((snap: DocumentSnapshot) => {
const form = snap.data();
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
type: 'OAuth2',
user: 'myemail#gmail.com',
clientId: 'xxxxxxxxxxxxx',
clientSecret: 'xxxxxxxxx',
refreshToken: 'xxxxxxxxx'
},
debug: true
});
const mailOptions = {
from: 'sender#gmail.com',
to: 'receiver#gmail.com',
subject: `Message from ${form.name} <${form.email}>`,
html: form.message
};
return transporter.sendMail(mailOptions)
.then(() => {
console.log('Email sent.');
}).catch((err) => {
console.log(err);
});
});
However, I get in the console log
sendMessage Function execution took 2908 ms, finished with status: 'ok'
sendMessage Function returned undefined, expected Promise or value
sendMessage Billing account not configured. External network is not accessible and quotas are severely limited. Configure billing account to remove these restrictions
sendMessage Function execution started
Am I using any external network here!
The following code works
import * as functions from 'firebase-functions';
import * as nodemailer from 'nodemailer';
import { DocumentSnapshot } from 'firebase-functions/lib/providers/firestore';
const gmailEmail = encodeURIComponent(functions.config().gmail.email);
const gmailPassword = encodeURIComponent(functions.config().gmail.password);
const mailTransport = nodemailer.createTransport(`smtps://${gmailEmail}:${gmailPassword}#smtp.gmail.com`);
export const sendMessage = functions.firestore.document('/emails/{pushKey}').onCreate((snap: DocumentSnapshot) => {
const form = snap.data();
const mailOptions = {
to: 'receiver#gmail.com',
subject: `Message from ${form.name} <${form.email}>`,
html: form.message
};
return mailTransport.sendMail(mailOptions)
.then(() => console.log('worked!'))
.catch(e => console.log(e));
});
But this way is unsecured, and It requires me to allow less secure apps on my Gmail account.
How can I use Gmail and OAuth2 with the free Firebase plan?
So you cannot make outbound requests on the Firebase free plan. You need to upgrade your plan to make outbound requests, and I believe since you are using 'nodemailer' that is the part trying to make an outbound request. Here is another question with comments about upgrading to use a mail service: How can I use nodemailer with Cloud Functions for Firebase?
I believe Firebase also made the Blaze plan free until you go past the quota of the free plan, so it really won't cost anything until you step past the free quota specified in the pricing (https://firebase.google.com/pricing/).

Resources