【问题标题】:Getting local notifications to show while app is in foreground Swift 3当应用程序处于前台 Swift 3 时获取本地通知
【发布时间】:2017-02-04 10:23:13
【问题描述】:

显然,现在这可以通过 ios10 实现:

optional func userNotificationCenter(_ center: UNUserNotificationCenter, 
                 willPresent notification: UNNotification, 
  withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void)

这个答案基本上说明了执行此操作所需的工具:

Displaying a stock iOS notification banner when your app is open and in the foreground?

我只是不太了解如何将它们组合在一起。

我不知道这有多重要,但我无法保留可选的 func 并且 xcode 希望我将其切换为私有。

我正在尝试展示徽章,文档提供

static var badge: UNNotificationPresentationOptions { get }

这里有点迷失。

然后我假设如果我想从获取这些徽章中排除某个视图控制器并且我没有使用导航控制器,我发现这个代码会起作用吗? : var window:UIWindow?

if let viewControllers = window?.rootViewController?.childViewControllers {
for viewController in viewControllers {
    if viewController.isKindOfClass(MyViewControllerClass) {
        print("Found it!!!")
        }
    }
}

【问题讨论】:

  • 当应用在后台并且我们收到通知时,哪个方法会被执行??

标签: ios swift swift3 uilocalnotification unusernotificationcenter


【解决方案1】:

在 iOS 10 中,有一个委托方法可以在应用打开时显示通知。您必须实现此方法才能在应用打开时获得丰富的通知。

extension ViewController: UNUserNotificationCenterDelegate {

    //for displaying notification when app is in foreground
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

        //If you don't want to show notification when app is open, do something here else and make a return here. 
        //Even you you don't implement this delegate method, you will not see the notification on the specified controller. So, you have to implement this delegate and make sure the below line execute. i.e. completionHandler.

        completionHandler([.alert, .badge, .sound]) 
    }

    // For handling tap and user actions
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {

        switch response.actionIdentifier {
        case "action1":
            print("Action First Tapped")
        case "action2":
            print("Action Second Tapped")
        default:
            break
        }
        completionHandler()
    }

}

为了在 iOS 10 中安排通知并提供徽章

override func viewDidLoad() {
    super.viewDidLoad()

    // set UNUserNotificationCenter delegate to self
    UNUserNotificationCenter.current().delegate = self
    scheduleNotifications()
}

func scheduleNotifications() {

    let content = UNMutableNotificationContent()
    let requestIdentifier = "rajanNotification"

    content.badge = 1
    content.title = "This is a rich notification"
    content.subtitle = "Hello there, I am Rajan Maheshwari"
    content.body = "Hello body"
    content.categoryIdentifier = "actionCategory"
    content.sound = UNNotificationSound.default

    // If you want to attach any image to show in local notification
    let url = Bundle.main.url(forResource: "notificationImage", withExtension: ".jpg")
    do {
        let attachment = try? UNNotificationAttachment(identifier: requestIdentifier, url: url!, options: nil)
        content.attachments = [attachment!]
    }      

    let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 3.0, repeats: false)

    let request = UNNotificationRequest(identifier: requestIdentifier, content: content, trigger: trigger)
    UNUserNotificationCenter.current().add(request) { (error:Error?) in

        if error != nil {
            print(error?.localizedDescription ?? "some unknown error")
        }     
        print("Notification Register Success")
    }
}

为了在 AppDelegate 中注册,我们必须在 didFinishLaunchingWithOptions 中编写这段代码

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        registerForRichNotifications()
        return true
    }

我在这里也定义了动作。你可以跳过它们

func registerForRichNotifications() {

       UNUserNotificationCenter.current().requestAuthorization(options: [.alert,.badge,.sound]) { (granted:Bool, error:Error?) in
            if error != nil {
                print(error?.localizedDescription)
            }
            if granted {
                print("Permission granted")
            } else {
                print("Permission not granted")
            }
        }

        //actions defination
        let action1 = UNNotificationAction(identifier: "action1", title: "Action First", options: [.foreground])
        let action2 = UNNotificationAction(identifier: "action2", title: "Action Second", options: [.foreground])

        let category = UNNotificationCategory(identifier: "actionCategory", actions: [action1,action2], intentIdentifiers: [], options: [])

        UNUserNotificationCenter.current().setNotificationCategories([category])

    }

如果您希望您的通知横幅应在整个应用程序的任何位置显示,那么您可以在AppDelegate 中编写UNUserNotificationDelegate 的委托,并将UNUserNotificationCenter 当前委托为AppDelegate

extension AppDelegate: UNUserNotificationCenterDelegate {

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        print(response.notification.request.content.userInfo)
        completionHandler()
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler([.alert, .badge, .sound]) 
    }
}

查看此链接了解更多详情
https://www.youtube.com/watch?v=Svul_gCtzck

Github 示例
https://github.com/kenechilearnscode/UserNotificationsTutorial

这是输出

【讨论】:

  • 真棒,真棒的答案。谢谢。
  • 现在假设我想从 NSURL 设置图像意味着 web 那么我该如何设置呢?
  • 非常好的答案!!
  • 在 iOS 10 中运行良好,但在 iOS 9 中如何在应用程序上显示通知?
  • @Rajesh 你必须使用一些自定义横幅或 BannerView 或任何第三方,只要通知到达,就会从顶部删除视图。
【解决方案2】:

斯威夫特 3 | iOS 10+

假设您知道如何安排本地通知:

func scheduleLocalNotification(forDate notificationDate: Date) {

    let calendar = Calendar.init(identifier: .gregorian)

    let requestId: String = "123"
    let title: String = "Notification Title"
    let body: String = "Notification Body"

    // construct notification content
    let content = UNMutableNotificationContent()
    content.title = NSString.localizedUserNotificationString(forKey: title, arguments: nil)
    content.body = NSString.localizedUserNotificationString(forKey: body, arguments: nil)
    content.sound = UNNotificationSound.default()
    content.badge = 1
    content.userInfo = [
        "key1": "value1"
    ]

    // configure trigger
    let calendarComponents: [Calendar.Component] = [.year, .month, .day, .hour, .minute]
    let dateComponents = calendar.dateComponents(calendarComponents, from: notificationDate)
    let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)

    // create the request
    let request = UNNotificationRequest.init(identifier: requestId, content: content, trigger: trigger)

    // schedule notification
    UNUserNotificationCenter.current().add(request) { (error: Error?) in
        if let error = error {
            // handle error
        }
    }
}

您需要使您的AppDelegate 实现UNUserNotificationCenterDelegate 协议,并将其设置为UNUserNotificationCenter.current().delegate = self 的通知中心的委托。

// AppDelegate.swift

import UIKit
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions 
        launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        // set app delegate as notification center delegate
        UNUserNotificationCenter.current().delegate = self
    }
}

extension AppDelegate: UNUserNotificationCenterDelegate {

    // called when user interacts with notification (app not running in foreground)
    func userNotificationCenter(_ center: UNUserNotificationCenter, 
        didReceive response: UNNotificationResponse, withCompletionHandler 
        completionHandler: @escaping () -> Void) {

        // do something with the notification
        print(response.notification.request.content.userInfo)

        // the docs say you should execute this asap
        return completionHandler()
    }

    // called if app is running in foreground
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent 
        notification: UNNotification, withCompletionHandler completionHandler: 
        @escaping (UNNotificationPresentationOptions) -> Void) {

        // show alert while app is running in foreground
        return completionHandler(UNNotificationPresentationOptions.alert)
    }
}

现在,当您的应用在前台时,您的本地通知将出现。

请参阅 UNUserNotificationCenterDelegate 文档以供参考。

【讨论】:

  • 太棒了兄弟太棒了!查理辛会说你是摇滚明星!如果您有前台通知,只需复制并粘贴此 sn-p 代码即可!
  • 当应用在后台并且应用收到通知时会执行哪个方法??
  • @ArgaPK 如果您的应用程序在后台并且用户设备上出现通知,则不会调用任何方法。只有当用户与通知交互时,userNotificationCenter(didReceive response) 方法才会被调用。
  • 是的,分配 NUserNotificationCenter.current().delegate 将中断后台推送通知(不再调用 UIApplicationDelegate.didReceiveRemoteNotification())
【解决方案3】:

在您的应用处于前台时显示通知的关键也是设置:

content.setValue(true, forKey: "shouldAlwaysAlertWhileAppIsForeground")

在您的UNNotificationRequest 中。至于其他的,请看Rajan Maheshwari的精彩回答。

【讨论】:

  • 如果UNUserNotificationCenterDelegate 的委托和操作类别的注册设置正确,则不必设置此选项。委托中的第一个方法是处理这个应用程序在前台的情况。设置此值未记录在案,可能会违反应用商店指南。
  • @James,谢谢,我一直在 ObjC+iOS12 场景中对此进行调查,大多数答案实际上并没有说明代码的正确性,假设该行是必要的并修复该行工作,而不是确定是否需要或实际上是推荐的方法。
  • 这个东西不再有效 - 应用程序崩溃并出现错误 - SetValueForUndefinedKey: "shouldAlwaysAlertWhileAppIsForeground"
【解决方案4】:

当你的应用在前台打开时调用 userNotificationCenter 方法

func userNotificationCenter(_ center: UNUserNotificationCenter,
   willPresent notification: UNNotification, 
   withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) 
{
    completionHandler(.alert)
}

【讨论】:

    【解决方案5】:

    这些答案都不适用于最新的 IOS 版本

    1. shouldAlwaysAlertWhileAppIsForeground 将在 >= IOS 12 上崩溃

    2. 分配 UNUserNotificationCenter.current().delegate 会改变后台推送通知的行为。 UIApplicationDelegate.didReceiveRemoteNotification() 不再被调用,当收到推送通知并且应用程序处于后台时(直到用户单击通知)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-21
      相关资源
      最近更新 更多