相同React Native推送通知代码在新应用触发Promise拒绝问题排查
问题分析与解决方案
你的代码在新项目中触发Promise拒绝,核心问题集中在错误捕获缺失、环境变量写法错误以及无效令牌处理不当这几点:
1. 未全面捕获Promise错误
原代码仅捕获了AWS操作环节的错误,但未处理registerForPushNotificationsAsync自身可能抛出的Promise拒绝(比如getDevicePushTokenAsync调用失败);同时当该函数返回undefined(权限未授予、模拟器环境)时,后续AWS操作传入无效令牌也会触发拒绝。
2. 环境变量写法错误
你把process.env.XXX包裹在字符串引号内(比如"process.env.AWS_REGION"),这会直接将字符串字面量传给AWS配置,而非读取实际环境变量值,导致AWS SDK初始化失败,触发Promise拒绝。
3. 无效令牌未做拦截
当权限未授予或在模拟器运行时,registerForPushNotificationsAsync返回undefined,后续直接用这个值调用AWS的createPlatformEndpoint,会因参数缺失抛出错误。
修正后的完整代码
import { useState, useEffect } from "react"; import { Text, View, Platform } from "react-native"; import * as Device from "expo-device"; import * as Notifications from "expo-notifications"; import AWS from "aws-sdk"; Notifications.setNotificationHandler({ handleNotification: async () => ({ shouldShowAlert: true, shouldPlaySound: false, shouldSetBadge: false, }), }); export default function App() { const [deviceToken, setDeviceToken] = useState(""); useEffect(() => { // 封装所有异步操作,统一用try/catch捕获错误 const initPushNotifications = async () => { try { // 修复环境变量写法:直接引用process.env,不要包裹在字符串中 AWS.config.update({ region: process.env.AWS_REGION, accessKeyId: process.env.AWS_ACCESS, secretAccessKey: process.env.AWS_SECRET, }); const token = await registerForPushNotificationsAsync(); if (!token) { console.log("未获取到有效设备令牌,终止注册流程"); return; } setDeviceToken(token); const SNS = new AWS.SNS({ correctClockSkew: true }); const platformApplicationArn = Platform.OS === "android" ? process.env.FIREBASE_ARN : process.env.IOS_ARN; // 创建平台端点 const endpointParams = { PlatformApplicationArn: platformApplicationArn, Token: token, }; const createEndpointResponse = await SNS.createPlatformEndpoint(endpointParams).promise(); const endpointArn = createEndpointResponse.EndpointArn; // 订阅主题 const subscribeParams = { TopicArn: process.env.TOPIC_ARN, Protocol: "Application", Endpoint: endpointArn, }; await SNS.subscribe(subscribeParams).promise(); console.log("设备已成功注册到AWS SNS"); } catch (err) { console.error("推送通知初始化失败:", err); } }; initPushNotifications(); }, []); return ( <View style={{ flex: 1, alignItems: "center", justifyContent: "space-around", marginHorizontal: 25, }} > <Text>你的Expo推送令牌: {deviceToken} </Text> </View> ); } async function registerForPushNotificationsAsync() { if (!Device.isDevice) { alert("必须使用物理设备测试推送通知"); return null; } // 检查并请求权限 let { status: existingStatus } = await Notifications.getPermissionsAsync(); if (existingStatus !== "granted") { const { status } = await Notifications.requestPermissionsAsync(); existingStatus = status; } if (existingStatus !== "granted") { alert("获取推送通知权限失败!"); return null; } // 获取设备令牌,调用失败会抛出错误,被上层try/catch捕获 const tokenData = await Notifications.getDevicePushTokenAsync(); console.log("设备令牌:", tokenData.data); return tokenData.data; }
额外注意事项
- 环境变量配置: 确保新项目已正确配置环境变量,比如使用
expo-env或dotenv,在项目根目录创建.env文件存放AWS相关配置。 - 设备要求: 测试时必须使用物理设备,模拟器无法获取有效推送令牌。
- AWS权限验证: 确认AWS账号的AccessKey拥有SNS的
CreatePlatformEndpoint和Subscribe权限,避免因权限不足触发错误。
内容的提问来源于stack exchange,提问作者Dan Cruz
相关产品推荐
相关产品推荐

