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 git+https://github.com/darkbasic/cordova-plugin-fcm.git --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,