Expo 推送通知设置

编辑页面

了解如何设置推送通知、获取开发和生产环境的凭据,以及发送测试推送通知。


For the complete documentation index, see llms.txt. Use this Use this file to discover all available pages.

若要使用 Expo 推送通知服务,你必须通过安装一组库来配置应用,实现处理通知的函数,并为 Android 和 iOS 设置凭据。

请完成本指南中概述的步骤,或者观看下面更详细的视频。最后,你将能够发送一条推送通知并在设备上收到它。

使用 EAS 的 Expo 通知 | 完整指南
使用 EAS 的 Expo 通知 | 完整指南

了解如何在 Expo 项目中设置推送通知。本视频涵盖了为 Android 上的 FCM v1 配置 Firebase、在 EAS 上设置 Android 和 iOS 凭据、使用 EAS Build 构建,以及使用 Expo Notifications 工具进行测试。


要让客户端为推送通知做好准备,需要以下内容:

  • 用户允许向其发送推送通知。
  • 应用的 ExpoPushToken

你想直接使用 FCM / APNs,而不是 Expo 推送通知服务吗?

如果你需要对通知进行更细粒度的控制,可能需要直接与 FCM 和 APNs 通信。Expo 不会强制你使用 Expo Application Services,expo-notifications API 也与推送服务无关。了解如何通过 "使用 FCM 和 APNs 发送通知"

前置条件

重要: Android 模拟器和 iOS 模拟器不支持推送通知。需要使用真机。

本指南中描述的以下步骤使用 EAS Build。这是设置通知的最简单方式,因为你的 EAS 项目还会包含通知凭据。不过,你也可以在不使用 EAS Build 的情况下使用 expo-notifications 库,通过在本地构建你的项目来完成。

1

安装库

运行以下命令安装 expo-notificationsexpo-deviceexpo-constants 库:

Terminal
npx expo install expo-notifications expo-device expo-constants
  • expo-notifications 库用于请求用户权限以及获取用于发送推送通知的 ExpoPushToken
  • expo-device 用于检查应用是否运行在真机上。
  • expo-constants 用于从应用配置中获取 projectId 值。

2

添加配置插件

expo-notifications 插件添加到你的应用配置plugins 数组中:

app.json
{ "expo": { %%placeholder-start%%... %%placeholder-end%% "plugins": [ %%placeholder-start%%... %%placeholder-end%% "expo-notifications" ] } }

3

添加一个最小可运行示例

下面的代码展示了一个在 React Native 应用中注册、发送和接收推送通知的可运行示例。将其复制并粘贴到你的项目中:

App.tsx
import { useState, useEffect, useRef } from 'react'; import { Text, View, Button, Platform } from 'react-native'; import * as Device from 'expo-device'; import * as Notifications from 'expo-notifications'; import Constants from 'expo-constants'; Notifications.setNotificationHandler({ handleNotification: async () => ({ shouldPlaySound: true, shouldSetBadge: true, shouldShowBanner: true, shouldShowList: true, }), }); async function sendPushNotification(expoPushToken: string) { const message = { to: expoPushToken, sound: 'default', title: '原始标题', body: '这里是正文!', data: { someData: 'goes here' }, }; await fetch('https://exp.host/--/api/v2/push/send', { method: 'POST', headers: { Accept: 'application/json', 'Accept-encoding': 'gzip, deflate', 'Content-Type': 'application/json', }, body: JSON.stringify(message), }); } function handleRegistrationError(errorMessage: string) { alert(errorMessage); throw new Error(errorMessage); } async function registerForPushNotificationsAsync() { if (Platform.OS === 'android') { await Notifications.setNotificationChannelAsync('default', { name: '默认', importance: Notifications.AndroidImportance.MAX, vibrationPattern: [0, 250, 250, 250], lightColor: '#FF231F7C', }); } if (Device.isDevice) { const { status: existingStatus } = await Notifications.getPermissionsAsync(); let finalStatus = existingStatus; if (existingStatus !== 'granted') { const { status } = await Notifications.requestPermissionsAsync(); finalStatus = status; } if (finalStatus !== 'granted') { handleRegistrationError('未授予获取推送通知推送令牌的权限!'); return; } const projectId = Constants?.expoConfig?.extra?.eas?.projectId ?? Constants?.easConfig?.projectId; if (!projectId) { handleRegistrationError('未找到项目 ID'); } try { const pushTokenString = ( await Notifications.getExpoPushTokenAsync({ projectId, }) ).data; console.log(pushTokenString); return pushTokenString; } catch (e: unknown) { handleRegistrationError(`${e}`); } } else { handleRegistrationError('推送通知必须使用真机'); } } export default function App() { const [expoPushToken, setExpoPushToken] = useState(''); const [notification, setNotification] = useState<Notifications.Notification | undefined>( undefined ); useEffect(() => { registerForPushNotificationsAsync() .then(token => setExpoPushToken(token ?? '')) .catch((error: any) => setExpoPushToken(`${error}`)); const notificationListener = Notifications.addNotificationReceivedListener(notification => { setNotification(notification); }); const responseListener = Notifications.addNotificationResponseReceivedListener(response => { console.log(response); }); return () => { notificationListener.remove(); responseListener.remove(); }; }, []); return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'space-around' }}> <Text>你的 Expo 推送令牌:{expoPushToken}</Text> <View style={{ alignItems: 'center', justifyContent: 'center' }}> <Text>标题:{notification && notification.request.content.title} </Text> <Text>正文:{notification && notification.request.content.body}</Text> <Text>数据:{notification && JSON.stringify(notification.request.content.data)}</Text> </View> <Button title="按下以发送通知" onPress={async () => { await sendPushNotification(expoPushToken); }} /> </View> ); }

配置 projectId

使用前面的示例时,在注册推送通知时,你需要使用 projectId。此属性用于将 Expo 推送令牌关联到特定项目。对于使用 EAS 的项目,projectId 属性表示该项目的通用唯一标识符(UUID)。

在创建开发构建时,projectId 会自动设置。不过,我们建议在项目代码中手动设置它。为此,你可以使用 expo-constants 从应用配置中获取 projectId 值。

const projectId = Constants?.expoConfig?.extra?.eas?.projectId ?? Constants?.easConfig?.projectId; const pushTokenString = (await Notifications.getExpoPushTokenAsync({ projectId })).data;

将 Expo 推送令牌归属于项目 ID 的一个好处是,当项目在不同账户之间转移,或者现有账户重命名时,它不会改变。

4

获取开发构建的凭据

对于 Android 和 iOS,设置凭据有不同的要求。

对于 Android,你需要配置 Firebase Cloud Messaging (FCM) 来获取凭据并设置你的 Expo 项目。

按照 添加 Android FCM V1 凭据 中的步骤设置你的凭据。

生成凭据需要付费的 Apple Developer 账户。

对于 iOS,请确保你在首次运行 eas build 命令之前,已经注册了你要测试的 iOS 设备

如果你第一次创建开发构建,系统会要求你启用推送通知。当 EAS CLI 提示时,对以下问题回答 yes:

  • 为你的项目设置推送通知
  • 生成新的 Apple Push Notifications service 密钥

如果你不使用 EAS Build,请手动运行 eas credentials

5

构建应用

Terminal
eas build

6

使用推送通知工具进行测试

在创建并安装开发构建后,你可以使用 Expo 推送通知工具 快速向你的设备发送测试通知。

  1. 为你的项目启动开发服务器:

    Terminal
    npx expo start
  2. 在你的设备上打开开发构建。

  3. 在生成 ExpoPushToken 后,将该值及其他详细信息(例如消息标题和正文)输入 Expo 推送通知工具中。

  4. 点击 发送通知 按钮。

从工具发送通知后,你应该会在设备上看到该通知。下面是一个 Android 设备接收推送通知的示例。