@nativescript/firebase-messaging
NativeScript Firebase - 消息
npm i --save @nativescript/firebase-messaging

@nativescript/firebase-messaging

内容

简介

此插件允许您在 NativeScript 应用中使用 Firebase 云消息

image

使用 FCM,您可以通知客户端应用有新的电子邮件或其他数据可供同步。您可以向客户端发送通知消息,以驱动用户重新参与和保留。对于即时消息等用例,消息可以传输最多 4 KB 的有效负载到客户端应用。

FCM 消息可以发送到真实的 Android/iOS 设备和 Android 模拟器。但是,iOS 模拟器无法处理云消息。

处理消息的常见用例可能包括

  • 显示通知(请参阅 在前景中监听通知消息)。
  • 在设备上静默同步消息数据(例如,通过 ApplicationSettings 类)。
  • 更新应用程序的用户界面。

为 Firebase 设置您的应用

在您启用 Firebase 消息之前,需要为 Firebase 设置您的应用。要为您的 NativeScript 应用设置和初始化 Firebase,请遵循 @nativescript/firebase-core 插件文档中的说明。

将 Firebase 云消息 SDK 添加到您的应用

要将 Firebase 云消息 SDK 添加到您的应用,请按照以下步骤操作

  1. 在项目的根目录中运行以下命令以安装 @nativescript/firebase-messaging 插件。
npm install @nativescript/firebase-messaging
  1. 通过导入 @nativescript/firebase-messaging 模块来添加 SDK。您应该在应用程序中只导入一次此模块,最好是在主文件中(例如 app.tsmain.ts)。
import '@nativescript/firebase-messaging';

iOS: 请求权限

iOS 阻止显示包含通知(或 'alert')负载的消息,除非您已从用户那里获得明确许可。

要请求许可,请调用由 firebase().messaging() 返回的 Messaging 类 实例上的 requestPermission 方法。此方法将触发一个原生许可对话框,请求用户的许可。用户可以选择允许或拒绝请求。

import { firebase } from '@nativescript/firebase-core';
import { AuthorizationStatus } from '@nativescript/firebase-messaging-core';

async function requestUserPermission() {
const authStatus = await firebase()
.messaging()
.requestPermission({
ios: {
alert: true,
},
});
const enabled = authStatus === AuthorizationStatus.AUTHORIZED || authStatus === AuthorizationStatus.PROVISIONAL;

if (enabled) {
console.log('Authorization status:', authStatus);

const didRegister = await firebase().messaging()
.registerDeviceForRemoteMessages();
}
}

Android: 请求权限

在 Android 上,您不需要请求用户许可。此方法可以在 Android 设备上调用;然而,它将始终成功解析。

Firebase 云消息类型以及用户应用程序对投递的影响

FCM 允许您发送以下两种类型的消息

这些消息的投递方式取决于应用程序是否处于前台或后台。

通知消息传递和应用程序状态

以下表格显示了根据应用程序状态,通知消息如何投递到用户应用程序。

通知消息类型 应用程序状态
前台 后台
仅通知 由 FCM SDK 显示给用户 传递给应用程序代码处理的通知处理程序
通知 + 可选数据 应用程序接收一个包含两个负载的消息对象。 应用程序在通知托盘中接收通知负载,当用户点击通知时,数据负载将被传递给 onMessage 处理程序

在前景中始终显示通知

如果您希望在应用程序前台时始终显示通知,而无需在发送推送通知时发送额外的参数/数据,请将 Messaging 实例的 showNotificationsWhenInForeground 属性设置为 true

import { firebase } from '@nativescript/firebase-core';
firebase().messaging().showNotificationsWhenInForeground = true;

在前景中监听通知消息

由于通知消息在应用程序处于后台时自动显示(请参阅 通知消息投递和应用程序状态),有时您可能想手动处理消息的显示。为了在应用程序处于前台时监听收到的消息,或手动处理应用程序处于后台时的消息显示,请将回调函数传递给 onMessage 方法,该方法属于 Messaging 类 的实例。此回调将。通过此处理程序执行的代码可以与您的应用程序交互(例如更新状态或 UI)。

例如,您可以在每次消息投递时显示新的警报

import { alert } from '@nativescript/core';
import { firebase } from '@nativescript/firebase-core';

firebase()
.messaging()
.onMessage(async (remoteMessage) => {
alert('A new FCM message arrived!', JSON.stringify(remoteMessage));
});

数据消息传递和应用程序状态

以下表格显示了根据应用程序状态,数据消息如何投递到用户应用程序。

前台 后台
应用程序在传递给 onMessage 方法的回调函数中接收数据负载。 应用程序在传递给 onMessage 方法的回调函数中接收数据负载。
  • 当客户端应用程序不在前台时,Android 和 iOS 都将消息视为低优先级,并将忽略它(即不会发送事件)。为了允许仅数据消息触发,请将 Android 的负载 priority 属性设置为 high,并将 iOS 的 contentAvailable 属性设置为 true

例如,如果您使用 Node.js 的 firebase-admin 包发送消息,则应将负载设置如下

admin.messaging().sendToDevice(
[], // device fcm tokens...
{
data: {
owner: JSON.stringify(owner),
user: JSON.stringify(user),
picture: JSON.stringify(picture),
},
},
{
// Required for background/quit data-only messages on iOS
contentAvailable: true,
// Required for background/quit data-only messages on Android
priority: 'high',
}
);
  • 对于 iOS,除了将 contentAvailable 属性设置为 true 之外,负载还必须包含适当的 APNs 标头。有关 APN 标头的更多信息,请参阅 向 APNs 发送通知请求。例如,如果您使用 Node.js 的 firebase-admin 包发送消息,则负载将如下所示
admin.messaging().send({
data: {
//some data
},
apns: {
payload: {
aps: {
contentAvailable: true,
},
},
headers: {
'apns-push-type': 'background',
'apns-priority': '5',
'apns-topic': '', // your app bundle identifier
},
},
//must include token, topic, or condition
//token: //device token
//topic: //notification topic
//condition: //notification condition
});

从您的服务器发送消息

云消息模块提供了所需的工具,让您可以直接从您的服务器发送自定义消息。例如,当新的聊天消息保存到您的数据库时,您可以发送一个 FCM 消息到特定的设备,并显示通知,或更新本地设备存储,以便消息立即可用。

Firebase为不同语言提供了多个SDK,例如Node.JSJavaPythonC#Go,以满足该目的。它还支持通过HTTP发送消息。这些方法允许您通过FCM服务器直接向用户的设备发送消息。

使用用户设备令牌发送消息

要向设备发送消息,您必须获取其唯一的令牌。令牌由设备自动生成,可以通过云消息模块访问。令牌应该保存在您的服务器上,并在需要时易于访问。

以下示例使用Cloud Firestore数据库来存储和管理令牌,并使用Firebase Authentication来管理用户的身份。但是,您可以使用任何您选择的数据存储或身份验证方法。

保存令牌

一旦您的应用程序启动,您就可以在Messaging实例上调用getToken方法以获取唯一的设备令牌。如果您使用的是不同的推送通知提供程序,例如Amazon SNS,您需要在iOS上调用getAPNSToken

import { firebase } from '@nativescript/firebase-core';
import '@nativescript/firebase-messaging';
import { FieldValue } from '@nativescript/firebase-auth';
import '@nativescript/firebase-firestore';

async function saveTokenToDatabase(token) {
// Assume user is already signed in
const userId = firebase().auth().currentUser.uid;

// Add the token to the users datastore
await firebase().firestore()
.collection('users')
.doc(userId)
.update({
tokens: FieldValue.arrayUnion(token),
});
}

// Get the device token
firebase().messaging()
.getToken()
.then(token => {
return saveTokenToDatabase(token);
});

// If using other push notification providers (ie Amazon SNS, etc)
// you may need to get the APNs token instead for iOS:
// if (global.isIOS) {
// saveTokenToDatabase(firebase().messaging().getAPNSToken());
// }


// Listen to whether the token changes
firebase().messaging().onToken(token => {
saveTokenToDatabase(token);

}

上述代码片段将设备FCM令牌存储在远程数据库中。

saveTokenToDatabase方法内部,我们将令牌存储在当前用户的文档中。请注意,令牌是通过FieldValue.arrayUnion方法添加的。用户可以有多个令牌(例如使用2个设备),因此确保我们将所有令牌存储在数据库中非常重要,而FieldValue.arrayUnion允许我们做到这一点。

使用存储的令牌

在安全数据存储中存储令牌后,我们现在可以通过FCM向这些设备发送消息。

注意:以下示例使用Node.JS的firebase-admin包向我们的设备发送消息。但是,您可以使用上面列出的任何SDK。

请继续在您的服务器环境中设置firebase-tools库。一旦设置完毕,我们的脚本需要执行两个操作

  1. 获取发送消息所需的令牌。
  2. 向注册了令牌的设备发送数据有效负载。想象一下我们的应用程序类似于Instagram。用户可以上传图片,其他用户可以“点赞”这些图片。每次帖子被点赞时,我们希望向上传图片的用户发送消息。下面的代码模拟了一个在图片被点赞时被调用的函数,它包含所有必要的信息
// Node.js
var admin = require('firebase-admin');

// ownerId - who owns the picture someone liked
// userId - id of the user who liked the picture
// picture - metadata about the picture

async function onUserPictureLiked(ownerId, userId, picture) {
// Get the owners details
const owner = admin.firestore().collection('users').doc(ownerId).get();

// Get the users details
const user = admin.firestore().collection('users').doc(userId).get();

await admin.messaging().sendToDevice(
owner.tokens, // ['token_1', 'token_2', ...]
{
data: {
owner: JSON.stringify(owner),
user: JSON.stringify(user),
picture: JSON.stringify(picture),
},
},
{
// Required for background/quit data-only messages on iOS
contentAvailable: true,
// Required for background/quit data-only messages on Android
priority: 'high',
}
);
}

在验证用户时处理令牌

Firebase云消息令牌与已安装的应用实例相关联。默认情况下,只有令牌过期或卸载/重新安装应用才会生成新的令牌。

这意味着默认情况下,如果两个用户从同一设备登录您的应用,将使用相同的FCM令牌为两个用户。通常,这不是您想要的,因此您必须注意在处理用户注销/登录时同时轮换FCM令牌。

如何以及何时使令牌无效并生成新令牌将根据您的项目具体而定,但一种常见的模式是在注销期间删除FCM令牌,并更新您的后端以删除它。然后,您在登录期间获取FCM令牌,并更新您的后端系统以将新令牌与已登录的用户关联。

请注意,当通过调用deleteToken方法删除令牌时,它立即且永久无效。

通过主题发送消息

主题是一种机制,允许设备通过FCM(Firebase Cloud Messaging)订阅和取消订阅命名的PubSub频道。您可以通过主题而不是通过FCM令牌发送消息到特定设备,而是向主题发送消息,所有订阅该主题的设备都将接收到该消息。

主题可以使您简化FCM服务器集成,因为您不需要保存设备令牌。但是,关于主题有一些注意事项需要考虑。

  • 发送到主题的消息不应包含敏感或私人信息。
  • 不要为特定用户创建一个主题进行订阅。
  • 主题消息支持每个主题无限订阅。
  • 一个应用实例最多可以订阅2000个主题。
  • 每个项目的新的订阅频率是有限制的。如果您在短时间内发送过多的订阅请求,FCM服务器将响应一个429 RESOURCE_EXHAUSTED("配额超出")响应。请使用指数退避策略重试。
  • 服务器集成可以同时向多个主题发送单一消息。但是,这限制为5个主题。

要了解如何向订阅主题的设备发送消息的更多信息,请参阅Android上的主题消息在Apple平台上发送主题消息

订阅主题

要将设备订阅到主题,请在Messaging实例上调用subscribeToTopic方法,并传入主题名称(不能包含'/')。

import { firebase } from '@nativescript/firebase-core';

firebase()
.messaging()
.subscribeToTopic('weather')
.then(() => console.log('Subscribed to topic!'));

取消主题订阅

要取消订阅主题,请使用主题名称调用unsubscribeFromTopic方法。

import { firebase } from '@nativescript/firebase-core';

firebase()
.messaging()
.unsubscribeFromTopic('weather')
.then(() => console.log('Unsubscribed fom the topic!'));

通过主题向用户设备发送消息

主题是一种机制,允许设备通过FCM(Firebase Cloud Messaging)订阅和取消订阅命名的PubSub频道。您可以通过主题而不是通过FCM令牌发送消息到特定设备,而是向主题发送消息,所有订阅该主题的设备都将接收到该消息。

主题可以使您简化FCM服务器集成,因为您不需要保存设备令牌。但是,关于主题有一些注意事项需要考虑。

  • 发送到主题的消息不应包含敏感或私人信息。
  • 不要为特定用户创建一个主题进行订阅。
  • 主题消息支持每个主题无限订阅。
  • 一个应用实例最多可以订阅2000个主题。
  • 每个项目的新的订阅频率是有限制的。如果您在短时间内发送过多的订阅请求,FCM服务器将响应一个429 RESOURCE_EXHAUSTED("配额超出")响应。
  • 服务器集成可以同时向多个主题发送单一消息。但是,这限制为5个主题。

要了解如何向订阅主题的设备发送消息的更多信息,请参阅Android上的主题消息在Apple平台上发送主题消息

订阅主题

要将设备订阅到主题,请在Messaging实例上调用subscribeToTopic方法,并传入主题名称(不能包含/)。

import { firebase } from '@nativescript/firebase-core';

firebase()
.messaging()
.subscribeToTopic('weather')
.then(() => console.log('Subscribed to topic!'));

取消订阅主题

要取消订阅主题,请使用主题名称调用unsubscribeFromTopic方法。

import { firebase } from '@nativescript/firebase-core';

firebase()
.messaging()
.unsubscribeFromTopic('weather')
.then(() => console.log('Unsubscribed fom the topic!'));

通过主题向用户设备发送消息

以firebase-admin Admin SDK为例,我们可以向订阅主题(例如weather)的设备发送消息。

const admin = require('firebase-admin');

const message = {
data: {
type: 'warning',
content: 'A new weather warning has been created!',
},
topic: 'weather',// topic name
};

admin
.messaging()
.send(message)
.then((response) => {
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});

使用条件同时发送消息到多个主题

要向多个主题的组合发送消息,请指定一个条件,它是一个布尔表达式,用于指定目标主题。例如,以下条件将向订阅weathernewstraffic主题的设备发送消息。

condition: "'weather' in topics && ('news' in topics || 'traffic' in topics)";

要向此条件发送消息,请将主题键替换为条件。

const admin = require('firebase-admin');

const message = {
data: {
content: 'New updates are available!',
},
condition: "'weather' in topics && ('news' in topics || 'traffic' in topics)",
};

admin
.messaging()
.send(message)
.then((response) => {
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});

在通知有效负载中发送图片

通知编辑器和FCM API都支持在消息负载中使用图片链接。

特定于 iOS 的选项

要使用Admin SDK成功发送图片,请为iOS设置带有apns属性的ApnsConfig选项。

const payload = {
notification: {
body: 'This is an FCM notification that displays an image!',
title: 'FCM Notification',
},
apns: {
payload: {
aps: {
'mutable-content': 1,
},
},
fcmOptions: {
imageUrl: 'image-url',
},
},
};

注意:要查看iOS上可用的配置列表,请参阅官方Firebase文档

特定于 Android 的选项

类似于iOS,Android需要一些特定的配置。

const payload = {
notification: {
body: 'This is an FCM notification that displays an image!',
title: 'FCM Notification',
},
android: {
notification: {
image: 'image-url',
},
},
};

注意:有关在Android上发送图片的更多信息,请参阅在通知负载中发送图片

同时向iOS和Android发送一个图片通知

使用Admin SDK,可以发送一个通知,该通知将同时发送到两个平台。

const admin = require('firebase-admin');

// Create a list containing up to 500 registration tokens.
// These registration tokens come from the client FCM SDKs.
const registrationTokens = ['YOUR_REGISTRATION_TOKEN_1', 'YOUR_REGISTRATION_TOKEN_2'];

const message = {
tokens: registrationTokens,
notification: {
body: 'This is an FCM notification that displays an image!',
title: 'FCM Notification',
},
apns: {
payload: {
aps: {
'mutable-content': 1,
},
},
fcmOptions: {
imageUrl: 'image-url',
},
},
android: {
notification: {
imageUrl: 'image-url',
},
},
};

admin
.messaging()
.send(message)
.then((response) => {
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});

Android: 配置推送通知图标和颜色

如果您想要为推送通知使用特定的图标和颜色,请在App_Resources/Android/src/main/AndroidManifest.xml文件中进行配置。

<meta-data android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/your_drawable_name" />

<meta-data android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/ns_primary" />

iOS:在Xcode中启用后台推送通知的支持。

打开 /platforms/ios/yourproject.xcworkspace (!) 并转到您的项目目标,然后转到“能力”以启用此功能(如果尚未启用):push-xcode-config

注意:如果没有启用此功能,您将在前台收到推送消息,但不会在后台收到

复制权限文件

上一步创建了文件 platforms/ios/YourAppName/Resources/YourAppName.entitlements。为了防止在运行 ns clean 时删除该文件,将其移动并重命名为 app/App_Resources/iOS/app.entitlements(如果尚不存在,则合并其内容)。该文件中有关后台推送的相关内容为

	<key>aps-environment</key>
<string>development</string>

允许处理接收到的后台推送通知

打开 app/App_Resources/iOS/Info.plist 并在底部添加以下代码

<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>

API

消息类

android

import { firebase } from '@nativescript/firebase-core';

messagingAndroid: com.google.firebase.messaging.FirebaseMessaging = firebase().messaging().android;

一个返回 Android 消息类实例的只读属性。


ios

import { firebase } from '@nativescript/firebase-core';

messagingIos: MessagingCore = firebase().messaging().ios;

一个返回 iOS 消息类实例的只读属性。


app

import { firebase } from '@nativescript/firebase-core';
messageApp: FirebaseApp = firebase().messaging().app;

一个返回与此云消息实例关联的 FirebaseApp 类实例的只读属性。


isAutoInitEnabled

import { firebase } from '@nativescript/firebase-core';
isAutoInitEnabled: boolean = firebase().messaging().isAutoInitEnabled;
// or
firebase().messaging().isAutoInitEnabled = true;

确定是否启用或禁用 Firebase 云消息的自动初始化。有关 iOS 中此属性的更多信息,请参阅 autoInitEnabled


showNotificationsWhenInForeground

import { firebase } from '@nativescript/firebase-core';
showNotificationsWhenInForeground: boolean = firebase().messaging().showNotificationsWhenInForeground;
// or
firebase().messaging().showNotificationsWhenInForeground = true;

允许您在应用在前台运行时始终显示通知,而无需在发送推送通知时发送额外的参数/数据。


isDeviceRegisteredForRemoteMessages

import { firebase } from '@nativescript/firebase-core';
isDeviceRegisteredForRemoteMessages: boolean = firebase().messaging().isDeviceRegisteredForRemoteMessages;

一个返回布尔值,指示应用是否已注册接收远程通知。


getToken()

import { firebase } from '@nativescript/firebase-core';
firebase().messaging().getToken()
.then((token: string) => {
console.log('Token: ', token);
}).catch((error: Error) => {
console.log('Error: ', error);
});

获取用户的设备令牌。有关更多信息,请参阅 getToken()


getAPNSToken()

import { firebase } from '@nativescript/firebase-core';
aPNSToken: string | null = firebase().messaging().getAPNSToken()

返回应用当前设备的 Apple 推送通知服务 (APNs) 令牌。有关更多信息,请参阅 apnsToken


hasPermission()

import { firebase } from '@nativescript/firebase-core';
firebase().messaging().hasPermission()
.then((status: AuthorizationStatus) => {
console.log('Authorization status: ', status);
}).catch((error: Error) => {
console.log('Error: ', error);
});

检查 iOS 上的应用是否有权限向用户发送通知。


onMessage()

import { firebase } from '@nativescript/firebase-core';
firebase().messaging().onMessage(listener);

注册一个回调函数,当接收到新消息时调用。

参数 类型 描述
listener (message: RemoteMessage) => any 当接收到新消息时调用的回调函数

onNotificationTap()

import { firebase } from '@nativescript/firebase-core';
firebase().messaging().onNotificationTap(listener);

注册一个回调函数,当用户点击通知时调用。

参数 类型 描述
listener (message: RemoteMessage) => any 当接收到新消息时调用的回调函数

onToken()

import { firebase } from '@nativescript/firebase-core';
firebase().messaging().onToken(listener);

注册一个回调函数,当用户的设备更改其注册令牌时调用。

参数 类型 描述
listener (token: string) => any 当调用

registerDeviceForRemoteMessages()

import { firebase } from '@nativescript/firebase-core';
firebase().messaging().registerDeviceForRemoteMessages()
.then(() => {
console.log('Device registered for remote messages');
}).catch((error: Error) => {
console.log('Error: ', error);
});

requestPermission()

import { firebase } from '@nativescript/firebase-core';
firebase().messaging().requestPermission(permissions)
.then((status: AuthorizationStatus) => {
console.log('Authorization status: ', status);
}).catch((error: Error) => {
console.log('Error: ', error);
});
参数 类型 描述
permissions 权限 包含要请求的权限的对象。

subscribeToTopic()

import { firebase } from '@nativescript/firebase-core';
firebase().messaging().subscribeToTopic(topic)
.then(() => {
console.log('Subscribed to topic');
}).catch((error: Error) => {
console.log('Error: ', error);
});

有关此方法的描述,请访问 Firebase 网站上的 subscribeToTopic()

参数 类型 描述
topic string 要订阅的议题名称。

unsubscribeFromTopic()

import { firebase } from '@nativescript/firebase-core';
firebase().messaging().unsubscribeFromTopic(topic)
.then(() => {
console.log('Unsubscribed from topic');
}).catch((error: Error) => {
console.log('Error: ', error);
});

有关此方法的描述,请访问 Firebase 网站上的 unsubscribeToTopic()

参数 类型 描述
topic string 要取消订阅的议题名称。

unregisterDeviceForRemoteMessages()

import { firebase } from '@nativescript/firebase-core';
firebase().messaging().unregisterDeviceForRemoteMessages()
.then(() => {
console.log('Device unregistered for remote messages');
}).catch((error: Error) => {
console.log('Error: ', error);
});

deleteToken()

import { firebase } from '@nativescript/firebase-core';
firebase().messaging().deleteToken()
.then(() => {
console.log('Token deleted');
}).catch((error: Error) => {
console.log('Error: ', error);
});

有关 deleteToken 方法的描述,请访问 Firebase 网站上的 deleteToken()


许可证

Apache License Version 2.0