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

@nativescript-asharghi/firebase-messaging

内容

简介

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

image

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

FCM 消息可以发送到实际的 Android/iOS 设备和 Android 模拟器。然而,iOS 模拟器不处理云消息。

处理消息的常见用例包括

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

为 Firebase 配置您的应用

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

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

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

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

iOS:请求权限

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

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

import { firebase } from '@nativescript-asharghi/firebase-core';
import { AuthorizationStatus } from '@nativescript-asharghi/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 处理程序来处理
通知 + 可选数据 应用接收到包含两个有效负载的消息对象。 应用在通知托盘中接收到通知有效负载,当用户点击通知时,数据有效负载会传递给 onMessage 处理程序

始终在前景显示通知

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

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

在前景中监听通知消息

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

例如,每次投递消息时,您可以显示一个新的警告

import { alert } from '@nativescript/core';
import { firebase } from '@nativescript-asharghi/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提供了多种语言(如Node.JSJavaPythonC#Go)的SDK,用于此目的。它还支持通过HTTP发送消息。这些方法允许您通过FCM服务器直接将消息发送到用户设备。

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

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

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

保存令牌

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

import { firebase } from '@nativescript-asharghi/firebase-core';
import '@nativescript-asharghi/firebase-messaging';
import { FieldValue } from '@nativescript-asharghi/firebase-auth';
import '@nativescript-asharghi/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方法删除令牌时,它会立即并且永久地无效。

通过主题发送消息

主题是一种机制,允许设备订阅和取消订阅命名PubSub 通道,所有这些操作都通过 FCM 管理。您可以通过发送消息到主题,而不是通过 FCM 令牌向特定设备发送消息,任何订阅该主题的设备都将接收到该消息。

主题可以帮助您简化 FCM 服务器集成,因为您不需要存储设备令牌。然而,关于主题还有一些注意事项:

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

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

订阅主题

要将设备订阅到主题,请调用 subscribeToTopic 方法,在 Messsaging 实例上使用主题名称(不得包含 ´/´)

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

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

取消订阅主题

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

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

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

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

主题是一种机制,允许设备订阅和取消订阅命名PubSub 通道,所有这些操作都通过 FCM 管理。您可以通过发送消息到主题,而不是通过 FCM 令牌向特定设备发送消息,任何订阅该主题的设备都将接收到该消息。

主题可以帮助您简化 FCM 服务器集成,因为您不需要存储设备令牌。然而,关于主题还有一些注意事项:

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

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

订阅主题

要将设备订阅到主题,请调用 subscribeToTopic 方法,在 Messaging 实例上使用主题名称(不得包含 /

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

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

取消订阅主题

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

import { firebase } from '@nativescript-asharghi/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 的 ApnsConfig 选项设置 apns 属性

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 (!) 并转到您项目的目标,然后转到 "Capabilities" 以切换此功能(如果尚未启用):push-xcode-config

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

复制权限文件

上一步创建了文件 platforms/ios/您的应用名称/Resources/您的应用名称.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-asharghi/firebase-core';

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

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


ios

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

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

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


app

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

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


isAutoInitEnabled

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

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


showNotificationsWhenInForeground

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

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


isDeviceRegisteredForRemoteMessages

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

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


getToken()

import { firebase } from '@nativescript-asharghi/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-asharghi/firebase-core';
aPNSToken: string | null = firebase().messaging().getAPNSToken()

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


hasPermission()

import { firebase } from '@nativescript-asharghi/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-asharghi/firebase-core';
firebase().messaging().onMessage(listener);

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

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

onNotificationTap()

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

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

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

onToken()

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

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

参数 类型 描述
listener (token: string) => any 当发生时被调用的回调函数

registerDeviceForRemoteMessages()

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

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


许可

Apache License 版本 2.0