一、前言远程推送通知是iOS开发中高频必备功能绝大多数App都需要实现推送消息提醒、点击通知跳转指定业务页面。iOS推送分为三种运行状态开发中必须全部兼容前台运行App处于打开状态直接接收推送弹窗后台挂起App未关闭、退至后台点击通知唤起App并跳转进程杀死App彻底关闭、进程销毁点击通知冷启动App并跳转本文基于Swift iOS 10依托UserNotifications框架提供一套企业级可直接复用的完整推送代码包含权限注册、DeviceToken获取、三种状态推送监听、统一页面跳转逻辑代码经过真机测试开箱即用。二、前期工程配置必看2.1 开启推送能力Xcode -gt; Targets -gt; Signing amp; Capabilities添加以下能力Push Notifications推送权限Background Modes后台模式勾选Remote notifications2.2 依赖库说明本文解析推送Json数据使用SwiftyJSON若无该依赖可手动使用原生字典解析。2.3 证书配置远程推送必须配置APNs推送证书开发环境使用开发证书生产环境使用发布证书否则无法获取DeviceToken、接收不到推送。三、完整代码实现3.1 引入依赖、遵守代理importUIKitimportUserNotificationsimportSwiftyJSONmainclassAppDelegate:UIResponder,UIApplicationDelegate,UNUserNotificationCenterDelegate{varwindow:UIWindow?funcapplication(_application:UIApplication,didFinishLaunchingWithOptions launchOptions:[UIApplication.LaunchOptionsKey:Any]?)-Bool{// 1. 注册推送权限registerForPushNotifications(application:application)// 2. 处理App被杀死状态下点击通知冷启动跳转handlePushWhenAppKilled(launchOptions:launchOptions)returntrue}}3.2 推送权限注册兼容iOS10前后版本申请弹窗、声音、角标权限授权成功后注册远程推送获取设备Token。// MARK: - 注册推送权限extensionAppDelegate{funcregisterForPushNotifications(application:UIApplication){if#available(iOS10.0,*){letcenterUNUserNotificationCenter.current()center.delegateself// 申请通知权限提示框、声音、角标center.requestAuthorization(options:[.sound,.alert,.badge]){granted,erroringuardgrantedelse{print(用户拒绝通知权限)return}// 权限授权成功获取通知配置并注册Tokenself.getNotificationSettings()}}else{// iOS10 以下低版本适配letsettingsUIUserNotificationSettings(types:[.sound,.alert,.badge],categories:nil)application.registerUserNotificationSettings(settings)application.registerForRemoteNotifications()}}// 获取通知授权状态注册远程推送funcgetNotificationSettings(){if#available(iOS10.0,*){UNUserNotificationCenter.current().getNotificationSettings{settingsinguardsettings.authorizationStatus.authorizedelse{return}DispatchQueue.main.async{UIApplication.shared.registerForRemoteNotifications()}}}}}3.3 获取DeviceTokenDeviceToken是设备唯一推送标识需要上传至服务端用于精准推送。// MARK: - DeviceToken 回调extensionAppDelegate{// 注册成功获取设备Tokenfuncapplication(_application:UIApplication,didRegisterForRemoteNotificationsWithDeviceToken deviceToken:Data){lettokendeviceToken.map{String(format:%02.2hhx,$0)}.joined()print(推送DeviceToken\(token))// 此处上传Token至后端服务器}// 注册推送失败回调funcapplication(_application:UIApplication,didFailToRegisterForRemoteNotificationsWithError error:Error){print(推送注册失败\(error.localizedDescription))}}3.4 处理App杀死状态推送跳转App进程彻底销毁时点击通知会触发冷启动通过launchOptions获取推送载荷实现页面跳转。// MARK: - App被杀死 点击通知冷启动跳转extensionAppDelegate{funchandlePushWhenAppKilled(launchOptions:[UIApplication.LaunchOptionsKey:Any]?){guardletoptionslaunchOptionselse{return}// 获取远程推送数据ifletnotificationoptions[.remoteNotification]as?[String:Any]{print(APP杀死状态点击通知启动\(notification))letuserInfonotification// 解析自定义推送字段letkeyuserInfo[key]as?String??letvalueuserInfo[value]as?Int??0// 根据业务key判断跳转页面ifkey通知传过来的key值{handlePushForNavigationTo(key:value)}}}}3.5 通用页面跳转工具方法适配所有推送场景自动获取当前顶层控制器避免页面栈覆盖问题采用Present方式跳转同时标记通知来源。// MARK: - 推送通用跳转方法extensionAppDelegate{funchandlePushForNavigationTo(key:Int){guardkey0else{return}// 获取根控制器guardletrootVCwindow?.rootViewControllerelse{return}vartopVCrootVC// 循环遍历拿到当前最顶层控制器whileletpresentedVCtopVC.presentedViewController{topVCpresentedVC}// 实例化跳转目标控制器根据自身项目修改ifletnextViewControllerUIStoryboard(name:Main,bundle:nil).instantiateViewController(withIdentifier:ViewController)as?ViewController{nextViewController.key值key// 标记来源通知跳转nextViewController.isFromNotificationtrueletnavControllerUINavigationController(rootViewController:nextViewController)navController.modalPresentationStyle.fullScreen// 顶层控制器弹出新页面topVC.present(navController,animated:true,completion:nil)}}}3.6 推送代理方法前台/后台处理App前台接收推送、后台点击推送两种场景统一解析推送参数、执行跳转逻辑。// MARK: - UNUserNotificationCenter 推送代理extensionAppDelegate:UNUserNotificationCenterDelegate{// 后台、挂起状态点击通知触发available(iOS10.0,*)funcuserNotificationCenter(_center:UNUserNotificationCenter,didReceive response:UNNotificationResponse,withCompletionHandler completionHandler:escaping()-Void){letuserInforesponse.notification.request.content.userInfoletjsonJSON(userInfo)letkeyjson[key].stringValueletvaluejson[value].intValueprint(后台点击通知key\(key)value\(value))// 根据key跳转对应页面switchkey{case通知传过来的key值:handlePushForNavigationTo(key:value)breakdefault:break}completionHandler()}// 前台运行状态收到推送即时触发available(iOS10.0,*)funcuserNotificationCenter(_center:UNUserNotificationCenter,willPresent notification:UNNotification,withCompletionHandler completionHandler:escaping(UNNotificationPresentationOptions)-Void){letuserInfonotification.request.content.userInfoletjsonJSON(userInfo)print(前台收到推送\(userInfo))print(推送key\(json[key].stringValue))// 前台展示弹窗、声音、角标completionHandler([.alert,.badge,.sound])}}四、推送三种状态逻辑总结App运行状态触发方法使用场景前台运行willPresentApp打开状态直接弹窗展示推送后台挂起didReceive退到后台点击通知唤起App并跳转进程杀死launchOptions彻底关闭App冷启动解析推送跳转五、开发注意事项避坑指南5.1 权限相关iOS13 需要在Info.plist添加权限描述NSUserNotificationUsageDescription否则安装直接崩溃必须用户手动授权静默授权无法实现。5.2 DeviceToken问题模拟器无法获取DeviceToken必须使用真机调试重装App、更换设备、还原手机DeviceToken会改变后端需做兼容处理。5.3 页面跳转坑点禁止直接获取根控制器跳转必须循环遍历拿到当前最顶层控制器防止页面被遮挡、跳转无反应推送跳转建议使用Present模态弹出不破坏原有项目导航栈。5.4 推送载荷规范后端推送JSON必须包含aps标准字段自定义业务字段放置同级杀死状态下iOS10及以上不再走代理方法只能通过launchOptions解析数据。5.5 后台推送限制未开启后台推送权限App后台无法接收静默推送系统会限制推送频率频繁推送会被系统节流拦截。六、总结本文完整实现了iOS Swift远程推送全套功能适配iOS10所有机型覆盖前台、后台、杀死三种核心场景。代码封装简洁、耦合度低跳转逻辑通用可直接接入企业项目。开发中重点注意真机调试、证书配置、顶层控制器跳转、杀死状态数据解析四大关键点规避推送常见Bug。
iOS Swift 推送通知完整实现教程(前台/后台/杀死状态 全覆盖跳转)
一、前言远程推送通知是iOS开发中高频必备功能绝大多数App都需要实现推送消息提醒、点击通知跳转指定业务页面。iOS推送分为三种运行状态开发中必须全部兼容前台运行App处于打开状态直接接收推送弹窗后台挂起App未关闭、退至后台点击通知唤起App并跳转进程杀死App彻底关闭、进程销毁点击通知冷启动App并跳转本文基于Swift iOS 10依托UserNotifications框架提供一套企业级可直接复用的完整推送代码包含权限注册、DeviceToken获取、三种状态推送监听、统一页面跳转逻辑代码经过真机测试开箱即用。二、前期工程配置必看2.1 开启推送能力Xcode -gt; Targets -gt; Signing amp; Capabilities添加以下能力Push Notifications推送权限Background Modes后台模式勾选Remote notifications2.2 依赖库说明本文解析推送Json数据使用SwiftyJSON若无该依赖可手动使用原生字典解析。2.3 证书配置远程推送必须配置APNs推送证书开发环境使用开发证书生产环境使用发布证书否则无法获取DeviceToken、接收不到推送。三、完整代码实现3.1 引入依赖、遵守代理importUIKitimportUserNotificationsimportSwiftyJSONmainclassAppDelegate:UIResponder,UIApplicationDelegate,UNUserNotificationCenterDelegate{varwindow:UIWindow?funcapplication(_application:UIApplication,didFinishLaunchingWithOptions launchOptions:[UIApplication.LaunchOptionsKey:Any]?)-Bool{// 1. 注册推送权限registerForPushNotifications(application:application)// 2. 处理App被杀死状态下点击通知冷启动跳转handlePushWhenAppKilled(launchOptions:launchOptions)returntrue}}3.2 推送权限注册兼容iOS10前后版本申请弹窗、声音、角标权限授权成功后注册远程推送获取设备Token。// MARK: - 注册推送权限extensionAppDelegate{funcregisterForPushNotifications(application:UIApplication){if#available(iOS10.0,*){letcenterUNUserNotificationCenter.current()center.delegateself// 申请通知权限提示框、声音、角标center.requestAuthorization(options:[.sound,.alert,.badge]){granted,erroringuardgrantedelse{print(用户拒绝通知权限)return}// 权限授权成功获取通知配置并注册Tokenself.getNotificationSettings()}}else{// iOS10 以下低版本适配letsettingsUIUserNotificationSettings(types:[.sound,.alert,.badge],categories:nil)application.registerUserNotificationSettings(settings)application.registerForRemoteNotifications()}}// 获取通知授权状态注册远程推送funcgetNotificationSettings(){if#available(iOS10.0,*){UNUserNotificationCenter.current().getNotificationSettings{settingsinguardsettings.authorizationStatus.authorizedelse{return}DispatchQueue.main.async{UIApplication.shared.registerForRemoteNotifications()}}}}}3.3 获取DeviceTokenDeviceToken是设备唯一推送标识需要上传至服务端用于精准推送。// MARK: - DeviceToken 回调extensionAppDelegate{// 注册成功获取设备Tokenfuncapplication(_application:UIApplication,didRegisterForRemoteNotificationsWithDeviceToken deviceToken:Data){lettokendeviceToken.map{String(format:%02.2hhx,$0)}.joined()print(推送DeviceToken\(token))// 此处上传Token至后端服务器}// 注册推送失败回调funcapplication(_application:UIApplication,didFailToRegisterForRemoteNotificationsWithError error:Error){print(推送注册失败\(error.localizedDescription))}}3.4 处理App杀死状态推送跳转App进程彻底销毁时点击通知会触发冷启动通过launchOptions获取推送载荷实现页面跳转。// MARK: - App被杀死 点击通知冷启动跳转extensionAppDelegate{funchandlePushWhenAppKilled(launchOptions:[UIApplication.LaunchOptionsKey:Any]?){guardletoptionslaunchOptionselse{return}// 获取远程推送数据ifletnotificationoptions[.remoteNotification]as?[String:Any]{print(APP杀死状态点击通知启动\(notification))letuserInfonotification// 解析自定义推送字段letkeyuserInfo[key]as?String??letvalueuserInfo[value]as?Int??0// 根据业务key判断跳转页面ifkey通知传过来的key值{handlePushForNavigationTo(key:value)}}}}3.5 通用页面跳转工具方法适配所有推送场景自动获取当前顶层控制器避免页面栈覆盖问题采用Present方式跳转同时标记通知来源。// MARK: - 推送通用跳转方法extensionAppDelegate{funchandlePushForNavigationTo(key:Int){guardkey0else{return}// 获取根控制器guardletrootVCwindow?.rootViewControllerelse{return}vartopVCrootVC// 循环遍历拿到当前最顶层控制器whileletpresentedVCtopVC.presentedViewController{topVCpresentedVC}// 实例化跳转目标控制器根据自身项目修改ifletnextViewControllerUIStoryboard(name:Main,bundle:nil).instantiateViewController(withIdentifier:ViewController)as?ViewController{nextViewController.key值key// 标记来源通知跳转nextViewController.isFromNotificationtrueletnavControllerUINavigationController(rootViewController:nextViewController)navController.modalPresentationStyle.fullScreen// 顶层控制器弹出新页面topVC.present(navController,animated:true,completion:nil)}}}3.6 推送代理方法前台/后台处理App前台接收推送、后台点击推送两种场景统一解析推送参数、执行跳转逻辑。// MARK: - UNUserNotificationCenter 推送代理extensionAppDelegate:UNUserNotificationCenterDelegate{// 后台、挂起状态点击通知触发available(iOS10.0,*)funcuserNotificationCenter(_center:UNUserNotificationCenter,didReceive response:UNNotificationResponse,withCompletionHandler completionHandler:escaping()-Void){letuserInforesponse.notification.request.content.userInfoletjsonJSON(userInfo)letkeyjson[key].stringValueletvaluejson[value].intValueprint(后台点击通知key\(key)value\(value))// 根据key跳转对应页面switchkey{case通知传过来的key值:handlePushForNavigationTo(key:value)breakdefault:break}completionHandler()}// 前台运行状态收到推送即时触发available(iOS10.0,*)funcuserNotificationCenter(_center:UNUserNotificationCenter,willPresent notification:UNNotification,withCompletionHandler completionHandler:escaping(UNNotificationPresentationOptions)-Void){letuserInfonotification.request.content.userInfoletjsonJSON(userInfo)print(前台收到推送\(userInfo))print(推送key\(json[key].stringValue))// 前台展示弹窗、声音、角标completionHandler([.alert,.badge,.sound])}}四、推送三种状态逻辑总结App运行状态触发方法使用场景前台运行willPresentApp打开状态直接弹窗展示推送后台挂起didReceive退到后台点击通知唤起App并跳转进程杀死launchOptions彻底关闭App冷启动解析推送跳转五、开发注意事项避坑指南5.1 权限相关iOS13 需要在Info.plist添加权限描述NSUserNotificationUsageDescription否则安装直接崩溃必须用户手动授权静默授权无法实现。5.2 DeviceToken问题模拟器无法获取DeviceToken必须使用真机调试重装App、更换设备、还原手机DeviceToken会改变后端需做兼容处理。5.3 页面跳转坑点禁止直接获取根控制器跳转必须循环遍历拿到当前最顶层控制器防止页面被遮挡、跳转无反应推送跳转建议使用Present模态弹出不破坏原有项目导航栈。5.4 推送载荷规范后端推送JSON必须包含aps标准字段自定义业务字段放置同级杀死状态下iOS10及以上不再走代理方法只能通过launchOptions解析数据。5.5 后台推送限制未开启后台推送权限App后台无法接收静默推送系统会限制推送频率频繁推送会被系统节流拦截。六、总结本文完整实现了iOS Swift远程推送全套功能适配iOS10所有机型覆盖前台、后台、杀死三种核心场景。代码封装简洁、耦合度低跳转逻辑通用可直接接入企业项目。开发中重点注意真机调试、证书配置、顶层控制器跳转、杀死状态数据解析四大关键点规避推送常见Bug。