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

iOS开发:如何在前台显示本地通知?

iOS前台本地通知的实现与模拟方案

刚好之前研究过这类需求,明确给你说:iOS原生系统不允许App在前台直接弹出和后台一模一样的标准本地通知弹窗——这是苹果出于用户体验和隐私保护的硬性限制。不过也不是完全没办法,下面给你详细讲两种可行思路:

一、利用系统提供的有限前台通知支持

当App处于前台活跃状态时,系统不会自动弹出通知弹窗,但会触发UNUserNotificationCenterDelegate的userNotificationCenter(_:willPresent:withCompletionHandler:)方法。在iOS 14及以上版本,你可以通过这个方法的completionHandler指定.banner选项,让通知以横幅形式在屏幕顶部短暂展示,算是最接近原生通知的效果:

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    // iOS 14+ 支持横幅展示,iOS 13及以下只能播放声音/更新角标
    if #available(iOS 14.0, *) {
        completionHandler([.banner, .sound])
    } else {
        completionHandler([.sound])
    }
}

不过要注意,这种横幅只是短暂闪过,不会停留在屏幕上等待交互,也不会像后台通知那样直接出现在通知中心的显眼位置,只能算半满足需求。

二、自定义弹窗完全模拟前台通知效果

如果想要实现类似Android那种持久的前台通知弹窗,就得自己动手做一个自定义组件了。这种方式灵活性最高,完全可以复刻系统通知的样式,甚至做个性化定制:

  • 用UIWindow或者直接在当前窗口添加自定义UIView来实现弹窗,放在屏幕顶部(和系统通知位置一致)
  • 给弹窗加上标题、内容、图标、关闭按钮,支持点击跳转等交互
  • 可以设置自动消失时间,也可以让用户手动关闭

给你一个简单的实现思路代码参考:

// 自定义通知弹窗视图
class CustomForegroundNotification: UIView {
    private let titleLabel = UILabel()
    private let bodyLabel = UILabel()
    private let closeButton = UIButton(type: .system)
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupUI() {
        // 设置弹窗样式(圆角、阴影、背景色等)
        backgroundColor = .systemBackground
        layer.cornerRadius = 12
        layer.shadowColor = UIColor.black.cgColor
        layer.shadowOpacity = 0.2
        layer.shadowOffset = CGSize(width: 0, height: 2)
        layer.shadowRadius = 4
        
        // 添加子视图并配置样式
        addSubview(titleLabel)
        addSubview(bodyLabel)
        addSubview(closeButton)
        
        titleLabel.font = .systemFont(ofSize: 16, weight: .semibold)
        bodyLabel.font = .systemFont(ofSize: 14)
        bodyLabel.numberOfLines = 2
        closeButton.setTitle("×", for: .normal)
        closeButton.titleLabel?.font = .systemFont(ofSize: 20, weight: .bold)
        
        // 这里可补充AutoLayout约束代码,适配不同屏幕
    }
    
    func configure(title: String, body: String) {
        titleLabel.text = title
        bodyLabel.text = body
    }
}

// 展示自定义通知的方法
func showCustomForegroundNotification(title: String, body: String) {
    let screenWidth = UIScreen.main.bounds.width
    let notificationView = CustomForegroundNotification(frame: CGRect(x: 20, y: -100, width: screenWidth - 40, height: 100))
    notificationView.configure(title: title, body: body)
    
    // 获取当前活跃的keyWindow(iOS 13+适配多场景)
    guard let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else { return }
    keyWindow.addSubview(notificationView)
    
    // 添加入场动画
    UIView.animate(withDuration: 0.3) {
        notificationView.frame.origin.y = 80 // 避开状态栏/导航栏
    }
    
    // 设置3秒后自动消失
    DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
        UIView.animate(withDuration: 0.3, animations: {
            notificationView.frame.origin.y = -100
        }) { _ in
            notificationView.removeFromSuperview()
        }
    }
    
    // 给关闭按钮添加点击事件
    notificationView.closeButton.addTarget(self, action: #selector(hideNotification), for: .touchUpInside)
}

@objc private func hideNotification() {
    // 手动关闭弹窗的逻辑,可根据需求调整
}

最后提醒几点

  • 不管用哪种方式,都必须先向用户申请通知权限,调用UNUserNotificationCenter.current().requestAuthorization获取权限,否则一切白搭
  • 自定义弹窗要适配不同屏幕(比如灵动岛、刘海屏的布局),别出现内容被遮挡的情况
  • 别过度使用前台通知,苹果对打扰用户的行为审核很严,搞不好会被拒审

内容的提问来源于stack exchange,提问作者ndk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:45:25