如何在Swift中利用Combine Publisher实时检测推送通知开启状态?
实时检测iOS推送通知状态的Combine实现方案
问题背景
现有检测推送通知开关状态的Swift函数仅能在应用启动时获取一次状态,用户在系统设置中修改通知权限后,需重启应用才能更新状态,无法实时同步变化。原代码如下:
var isRegister : Bool = false func isEnabled() -> Bool { let center = UNUserNotificationCenter.current() center.getNotificationSettings { (settings) in if(settings.authorizationStatus == .authorized) { isRegister = true print("Push notification is enabled") } else { isRegister = false print("Push notification is not enabled") } } return isRegister }
原代码问题分析
getNotificationSettings是异步方法,函数同步返回的isRegister值始终是初始默认值,无法正确反映实时状态- 没有监听系统通知权限变化或应用前后台切换的机制,无法触发状态重新检测
Combine实时解决方案
通过Combine的CurrentValueSubject维护状态,并监听应用进入前台的事件,每次应用从后台回到前台时重新获取通知权限状态,实现实时更新。
1. 创建状态管理类
实现一个遵循ObservableObject的类,封装状态检测和监听逻辑:
import Combine import UserNotifications class PushNotificationStatusMonitor: ObservableObject { // 用于实时发布状态变化的Subject @Published var isNotificationEnabled: Bool = false private var cancellables = Set<AnyCancellable>() init() { // 初始化时获取一次初始状态 updateNotificationStatus() // 监听应用进入前台的通知,触发状态更新 NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification) .sink { [weak self] _ in self?.updateNotificationStatus() } .store(in: &cancellables) } // 异步获取通知权限状态并更新Subject private func updateNotificationStatus() { UNUserNotificationCenter.current().getNotificationSettings { [weak self] settings in DispatchQueue.main.async { self?.isNotificationEnabled = settings.authorizationStatus == .authorized print("Push notification status updated: \(self?.isNotificationEnabled ?? false)") } } } }
2. 在SwiftUI中使用
直接将状态管理类作为@StateObject注入视图,实时绑定状态:
import SwiftUI struct NotificationStatusView: View { @StateObject private var statusMonitor = PushNotificationStatusMonitor() var body: some View { VStack(spacing: 20) { Text("推送通知状态") .font(.title) Text(statusMonitor.isNotificationEnabled ? "已开启" : "已关闭") .font(.largeTitle) .foregroundColor(statusMonitor.isNotificationEnabled ? .green : .red) } .padding() } }
3. 在UIKit中使用
通过订阅isNotificationEnabled的变化来更新UI:
import UIKit import Combine class NotificationStatusViewController: UIViewController { private let statusMonitor = PushNotificationStatusMonitor() private var cancellables = Set<AnyCancellable>() override func viewDidLoad() { super.viewDidLoad() // 订阅状态变化,更新UI statusMonitor.$isNotificationEnabled .receive(on: DispatchQueue.main) .sink { [weak self] isEnabled in self?.updateUI(with: isEnabled) } .store(in: &cancellables) } private func updateUI(with isEnabled: Bool) { // 根据状态更新界面元素,比如标签文本和颜色 let statusLabel = UILabel(frame: CGRect(x: 50, y: 100, width: 300, height: 50)) statusLabel.text = isEnabled ? "推送通知已开启" : "推送通知已关闭" statusLabel.textColor = isEnabled ? .green : .red statusLabel.font = .systemFont(ofSize: 20) view.addSubview(statusLabel) } }
方案说明
- 使用
@Published包装状态,自动发布变化给订阅者 - 监听
UIApplication.willEnterForegroundNotification,确保用户从设置返回应用时重新检测状态 - 所有UI更新都切换到主队列,避免线程问题
内容的提问来源于stack exchange,提问作者EN_Tech
相关产品推荐
相关产品推荐

