In this step we are going to implement push notifications using Google's Firebase Cloud Messaging
(FCM
). Whenever a user will send you a message, if you don't have our application in the foreground you will get a push notification.
First we will have to create google-services.json
in our project's root directory:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{
"project_info": {
"project_number": "152311690748",
"firebase_url": "https://meteor-c069e.firebaseio.com",
"project_id": "meteor-c069e",
"storage_bucket": "meteor-c069e.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:152311690748:android:25f0ec3806cf1f01",
"android_client_info": {
"package_name": "io.ionic.starter"
}
},
"oauth_client": [
{
"client_id": "152311690748-2ht8fdqhlnv8lsrrvnd7u521j9rcgi3h.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyD9CKsY6bC_a4Equ2HpbcrSErgJ2pheDS4"
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 2
}
}
}
],
"configuration_version": "1"
}
Then we need to install the FCM
Cordova
plug-in:
$ ionic cordova plugin add cordova-plugin-fcm --save
$ npm install --save @ionic-native/fcm
Then let's add it to app.module.ts
:
10
11
12
13
14
15
16
78
79
80
81
82
83
84
85
import { Camera } from '@ionic-native/camera';
import { Crop } from '@ionic-native/crop';
import { Contacts } from "@ionic-native/contacts";
import { FCM } from "@ionic-native/fcm";
import { AgmCoreModule } from '@agm/core';
import { MomentModule } from 'angular2-moment';
import { ChatsPage } from '../pages/chats/chats';
...some lines skipped...
SmsReceiver,
Camera,
Crop,
Contacts,
FCM
]
})
export class AppModule {}
Now we can start adding some FCM
logic into ChatsPage
:
7
8
9
10
11
12
13
21
22
23
24
25
26
27
28
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { MessagesPage } from '../messages/messages';
import { ChatsOptionsComponent } from './chats-options';
import { NewChatComponent } from './new-chat';
import { FCM } from "@ionic-native/fcm";
@Component({
templateUrl: 'chats.html'
...some lines skipped...
private popoverCtrl: PopoverController,
private modalCtrl: ModalController,
private alertCtrl: AlertController,
private platform: Platform,
private fcm: FCM) {
this.senderId = Meteor.userId();
}
...some lines skipped...
this.chats = this.findChats();
});
});
// Notifications
if (this.platform.is('cordova')) {
//this.fcm.subscribeToTopic('news');
this.fcm.getToken().then(token => {
console.log("Registering FCM token on backend");
MeteorObservable.call('saveFcmToken', token).subscribe({
next: () => console.log("FCM Token saved"),
error: err => console.error('Impossible to save FCM token: ', err)
});
});
this.fcm.onNotification().subscribe(data => {
if (data.wasTapped) {
console.log("Received FCM notification in background");
} else {
console.log("Received FCM notification in foreground");
}
});
this.fcm.onTokenRefresh().subscribe(token => {
console.log("Updating FCM token on backend");
MeteorObservable.call('saveFcmToken', token).subscribe({
next: () => console.log("FCM Token updated"),
error: err => console.error('Impossible to update FCM token: ' + err)
});
});
}
}
findChats(): Observable<Chat[]> {
We used the saveFcmToken
Meteor
method, so we need to create it first:
2
3
4
5
6
7
8
95
96
97
98
99
100
101
102
103
104
105
106
import { Messages } from './collections/messages';
import { MessageType, Profile } from './models';
import { check, Match } from 'meteor/check';
import { Users } from "./collections/users";
const nonEmptyString = Match.Where((str) => {
check(str, String);
...some lines skipped...
},
countMessages(): number {
return Messages.collection.find().count();
},
saveFcmToken(token: string): void {
if (!this.userId) throw new Meteor.Error('unauthorized', 'User must be logged-in to call this method');
check(token, nonEmptyString);
Users.collection.update({_id: this.userId}, {$set: {"fcmToken": token}});
}
});
Since we will soon need the node-fetch
package, we will need to install it first:
$ npm install --save node-fetch
$ npm install --save-dev @types/node-fetch
Let's implement our server side service which will actually send the notification:
4
5
6
7
8
9
10
11
12
13
"verificationRetriesWaitTime": 0,
"adminPhoneNumbers": ["+9721234567", "+97212345678", "+97212345679"],
"phoneVerificationMasterCode": "1234"
},
"private": {
"fcm": {
"key": "AIzaSyBnmvN5WNv3rAaLra1RUr9vA5k0pNp0KuY"
}
}
}
Now we should edit the AddMessage
Meteor
method to use our just-created service to send the notification:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import fetch from 'node-fetch';
export interface FcmNotification {
title: string;
text: string;
}
export class FcmService {
private key: string = Meteor.settings.private.fcm.key;
sendNotification(notification: FcmNotification, destination: string) {
const body = {
notification: notification,
to: destination
};
const options = {
method: 'POST',
body: JSON.stringify(body),
headers: {
"Content-Type": "application/json",
Authorization: `key=${this.key}`
},
};
return fetch("https://fcm.googleapis.com/fcm/send", options);
}
}
export const fcmService = new FcmService();
Before the Typescript
compiler complains, let's update our models
:
3
4
5
6
7
8
9
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import { MessageType, Profile } from './models';
import { check, Match } from 'meteor/check';
import { Users } from "./collections/users";
import { fcmService } from "./services/fcm";
const nonEmptyString = Match.Where((str) => {
check(str, String);
...some lines skipped...
'Chat doesn\'t exist');
}
const userId = this.userId;
const senderName = Users.collection.findOne({_id: userId}).profile.name;
const memberIds = Chats.collection.findOne({_id: chatId}).memberIds;
const tokens: string[] = Users.collection.find(
{
_id: {$in: memberIds, $nin: [userId]},
fcmToken: {$exists: true}
}
).map((el) => el.fcmToken);
for (let token of tokens) {
console.log("Sending FCM notification");
fcmService.sendNotification({"title": `New message from ${senderName}`, "text": content}, token);
}
return {
messageId: Messages.collection.insert({
chatId: chatId,