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
相关产品推荐
相关产品推荐

