You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 00:54:18