Flutter未集成Firebase时如何获取APNS推送所需设备Token
Flutter 无Firebase场景获取APNS推送设备Token方案
注意:设备UDID是硬件级唯一标识,和APNS要求的推送Token完全不通用,无法通过UDID转换得到APNS Token,必须通过iOS系统接口在用户授权通知权限后获取专属推送Token。
一、iOS端前置原生配置
必须先完成Xcode端配置,否则无法收到Token回调:
- 打开iOS工程下的
Runner.xcworkspace,选中Runner靶标,进入Signing & Capabilities页 - 点击
+ Capability,添加Push Notifications能力 - 确认当前App的Bundle ID、签名证书和你生成的.pem文件所属环境(开发/生产)匹配,否则后续推送会鉴权失败
- 调试必须使用iOS真机,模拟器无法生成真实可用于推送的APNS Token
你当前实现的通知权限判断逻辑运行效果参考:
二、Flutter端快速实现(无Firebase依赖)
推荐使用纯APNS实现的维护库flutter_apns,不需要接入任何Firebase相关服务,适配你现有PHP后端+PEM证书的推送架构。
1. 添加依赖
在项目pubspec.yaml中添加依赖:
dependencies: flutter_apns: ^2.0.0 # 你项目中已有的通知权限相关依赖保留即可
2. 整合现有权限逻辑,实现Token获取
在你原有通知权限判断的代码基础上,当权限为授权状态时注册APNS并监听Token回调,完整代码如下:
import 'package:flutter_apns/flutter_apns.dart'; final ApnsPushConnector apnsConnector = ApnsPushConnector(); void initPush() async { // 复用你已有的权限判断逻辑 final status = await NotificationPermissions.getNotificationPermissionStatus(); print(status); switch (status) { case PermissionStatus.denied: // 自行处理权限拒绝逻辑,比如引导用户去设置开权限 return; case PermissionStatus.granted: case PermissionStatus.provisional: // 配置APNS回调 apnsConnector.configureApns( onLaunch: (Map<String, dynamic> payload) async {}, onResume: (Map<String, dynamic> payload) async {}, onMessage: (Map<String, dynamic> payload) async {}, ); // 核心:监听APNS设备Token下发 apnsConnector.token.addListener(() { final String? apnsToken = apnsConnector.token.value; if (apnsToken != null) { print('APNS设备Token:$apnsToken'); // 将获取到的Token上传到你的PHP后端即可,后端调用APNS接口时传入该Token作为推送目标 } }); // 触发通知权限申请+APNS注册 apnsConnector.requestNotificationPermissions( const IosNotificationSettings( alert: true, badge: true, sound: true, ), ); break; case PermissionStatus.unknown: // 处理权限未知状态,可触发首次权限申请 return; default: return; } }
三、关键注意事项
- 开发环境、生产环境生成的APNS Token不通用:本地调试安装包拿到的是开发环境Token,对应使用开发证书生成的.pem发推送;TestFlight、App Store安装的正式包拿到的是生产环境Token,对应使用生产证书生成的.pem发推送
- APNS Token不是固定值:App卸载重装、系统还原、用户关闭通知后重新授权、系统版本升级都可能导致Token变化,建议每次App冷启动时都获取最新Token同步到后端,避免旧Token失效导致推送失败
- 如果Token回调长时间不触发,优先检查Xcode中Push Notifications能力是否添加成功、签名是否和Bundle ID匹配、是否使用真机调试
四、零第三方依赖原生实现方案(可选)
如果不想引入第三方库,可以通过MethodChannel自行对接iOS原生接口实现:
- 在iOS工程的
AppDelegate.swift中添加APNS注册、Token回调逻辑,通过MethodChannel把Token传给Flutter层:
import UIKit import Flutter import UserNotifications @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { private var apnsToken: String? override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GeneratedPluginRegistrant.register(with: self) UNUserNotificationCenter.current().delegate = self application.registerForRemoteNotifications() let controller = window?.rootViewController as! FlutterViewController let channel = FlutterMethodChannel(name: "com.yourapp/apns", binaryMessenger: controller.binaryMessenger) channel.setMethodCallHandler { call, result in if call.method == "getApnsToken" { result(self.apnsToken) } else { result(FlutterMethodNotImplemented) } } return super.application(application, didFinishLaunchingWithOptions: launchOptions) } override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { apnsToken = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken) } override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { print("APNS注册失败:\(error.localizedDescription)") super.application(application, didFailToRegisterForRemoteNotificationsWithError: error) } }
- Flutter层通过MethodChannel获取Token:
const apnsChannel = MethodChannel('com.yourapp/apns'); Future<String?> fetchApnsToken() async { try { return await apnsChannel.invokeMethod<String>('getApnsToken'); } catch (e) { print("获取APNS Token失败:$e"); return null; } }
内容的提问来源于stack exchange,提问作者Soundhar Raj
相关产品推荐
相关产品推荐


