React Native中如何通过PushNotificationIOS判断推送通知是否被禁用
这确实是个很实用的需求!PushNotificationIOS的checkPermissions方法只能告诉你当前通知权限是开还是关,没法区分用户首次请求时直接拒绝和之前授权后手动去设置里禁用这两种场景。要实现这个区分,我们得结合iOS原生的UNUserNotificationCenter API,再加上本地存储来记录权限的历史状态,下面是具体的实现步骤:
方案一:原生模块+本地存储 精准区分场景
1. 实现iOS原生自定义模块(Swift)
首先在Xcode项目里创建一个Swift文件NotificationPermissionModule.swift,用来获取更详细的原生权限状态:
import Foundation import UserNotifications import React @objc(NotificationPermissionModule) class NotificationPermissionModule: NSObject, RCTBridgeModule { // 模块名称,RN端会通过这个名称调用 static func moduleName() -> String! { return "NotificationPermissionModule" } // 标记模块需要在主线程初始化 static func requiresMainQueueSetup() -> Bool { return true } // 定义RN端可调用的异步方法,返回详细权限状态 @objc func getDetailedPermissionStatus(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) { UNUserNotificationCenter.current().getNotificationSettings { settings in DispatchQueue.main.async { let statusData: [String: Any] = [ "authorizationStatus": settings.authorizationStatus.rawValue, "alertSetting": settings.alertSetting.rawValue, "soundSetting": settings.soundSetting.rawValue, "badgeSetting": settings.badgeSetting.rawValue ] resolve(statusData) } } } }
然后在项目的桥接文件(比如YourApp-Bridging-Header.h)中添加React Native模块的引用:
#import <React/RCTBridgeModule.h>
2. React Native端调用+历史状态记录
在RN端,我们需要在首次请求权限时记录用户的选择,后续检查权限时结合历史记录来区分场景:
import { NativeModules, AsyncStorage, PushNotificationIOS } from 'react-native'; const { NotificationPermissionModule } = NativeModules; // 对应iOS原生的UNAuthorizationStatus枚举 const AuthorizationStatus = { NOT_DETERMINED: 0, // 用户还没收到权限请求 DENIED: 1, // 权限被拒绝 AUTHORIZED: 2, // 权限已授权 PROVISIONAL: 3, // 临时授权(仅iOS 12+) EPHEMERAL: 4 // 临时授权(仅用于临时应用) }; // 存储权限历史的AsyncStorage键名 const PERMISSION_HISTORY_KEY = '@notification_permission_history'; /** * 请求通知权限并记录结果到本地存储 */ const requestNotificationPermission = async () => { try { const permissions = await PushNotificationIOS.requestPermissions(); // 记录是否请求过权限、以及当时的授权状态 await AsyncStorage.setItem(PERMISSION_HISTORY_KEY, JSON.stringify({ hasRequested: true, wasAuthorized: !!permissions.alert // alert为0表示禁用,非0表示启用 })); return permissions; } catch (error) { console.error('请求通知权限失败:', error); throw error; } }; /** * 检查详细权限状态并区分场景 */ const checkDetailedPermissionStatus = async () => { try { // 获取原生端返回的详细权限数据 const nativeStatus = await NotificationPermissionModule.getDetailedPermissionStatus(); const currentAuthStatus = nativeStatus.authorizationStatus; // 读取本地存储的权限历史 const historyStr = await AsyncStorage.getItem(PERMISSION_HISTORY_KEY); const history = historyStr ? JSON.parse(historyStr) : { hasRequested: false, wasAuthorized: false }; let scenario = ''; switch (currentAuthStatus) { case AuthorizationStatus.NOT_DETERMINED: scenario = '用户尚未收到通知权限请求'; break; case AuthorizationStatus.DENIED: if (history.hasRequested && history.wasAuthorized) { scenario = '用户曾经授权过通知,后来在系统设置中禁用了'; } else if (history.hasRequested) { scenario = '用户首次请求通知权限时直接拒绝了'; } else { scenario = '未知状态(未请求权限但权限被拒)'; } break; case AuthorizationStatus.AUTHORIZED: scenario = '通知权限已正常启用'; break; default: scenario = '其他特殊权限状态(临时授权等)'; } return { currentNativeStatus: nativeStatus, scenario, permissionHistory: history }; } catch (error) { console.error('检查权限状态失败:', error); throw error; } }; // 使用示例:调用检查方法 checkDetailedPermissionStatus().then(result => { console.log('当前权限场景:', result.scenario); });
注意事项
- 如果用户卸载重装应用,AsyncStorage会被清空,此时无法区分两种拒绝场景。如果需要处理这种边缘情况,可以把历史状态存储到iOS的Keychain中(需要在原生端实现Keychain读写逻辑,RN端调用),Keychain在应用卸载后可能保留(取决于系统版本和设备)。
- 确保Xcode项目中正确链接了React Native的库,原生模块能被RN正常调用。
方案二:仅原生模块判断(局限性)
如果不需要严格区分两种拒绝场景,只是想确认用户是否曾经和权限请求交互过,可以通过authorizationStatus判断:
NOT_DETERMINED:用户从未收到过权限请求DENIED:用户已经拒绝过权限(不管是首次拒绝还是后来禁用)
但这种方法无法区分两种拒绝场景,所以更推荐方案一。
内容的提问来源于stack exchange,提问作者Eric Conner
相关产品推荐
相关产品推荐

