Fork me on GitHub

WhatsApp Clone with Meteor and Ionic 2 CLI

https://github.com/Urigo/Ionic2CLI-Meteor-WhatsApp

Ionic 3 Version (Last Update: 2017年06月15日)

FCM Push Notifications

Note: If you skipped ahead to this section, click here to download a zip of the tutorial at this point.

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:

16.1 Add google-services.json FCM config google-services.json
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:

16.3 Add FCM to app.module.ts src/app/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:

16.4 Add FCM logic to ChatsPage src/pages/chats/chats.ts
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:

16.5 Create the saveFcmToken Meteor method api/server/methods.ts
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:

16.7 Store credentials in settings.json api/private/settings.json
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:

16.8 Create server side fcm service api/server/services/fcm.ts
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:

16.9 Update addMessage Meteor method to send fcm notifications api/server/methods.ts
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,


[フレーム]

AltStyle によって変換されたページ (->オリジナル) /