ios - Apple 推送通知 (APN) 不一致?

标签 ios swift push-notification apple-push-notifications swift4

在通过 APN 使用 Apple 的推送通知时,我们遇到了一个令人困惑的问题。我们有以下场景(我想很标准):

当我们的应用程序(在这里我们称它为“MyApp”)首次安装和启动时,我们会请求用户允许通过“MyApp”向他发送推送通知。

在此示例中,AppDelegate 如下所示:

import UIKit
import UserNotifications

class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

    var window: UIWindow?

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

        // Register Remote Notifications
        UNUserNotificationCenter.current().delegate = self
        self.registerForPushNotifications()

        return true
    }

    // MARK: - Remote Notifications

    func registerForPushNotifications() {
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
            guard granted else {
                return
            }
            self.getNotificationSettings()
        }
    }

    func getNotificationSettings() {
        UNUserNotificationCenter.current().getNotificationSettings { (settings) in
            guard settings.authorizationStatus == .authorized else {
                return
            }
            DispatchQueue.main.async {
                UIApplication.shared.registerForRemoteNotifications()
            }
        }
    }

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let tokenParts = deviceToken.map { (data) -> String in
            return String(format: "%02.2hhx", data)
        }
        let token = tokenParts.joined()
        print("ApnToken: \(token)")
    }

    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("did Fail to Register for RemoteNotifications")
    }

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

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        print("UserDidResponseToNotification!")
        completionHandler()
    }

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        print("DidReceiveRemoteNotification!")
        completionHandler(.newData)
    }
}

因此用户安装并启动应用程序并询问是否允许“MyApp”向用户发送推送通知。如果用户接受推送通知 application(_:didRegisterForRemoteNotificationsWithDeviceToken:) 被调用,我们将收到的 deviceToken 提供给我们的 API。

现在是让我感到困惑的部分:

用户还可以选择稍后通过 iPhone 设置关闭推送通知,如下所示:设置 >“我的应用程序”> 通知 > 允许通知 > 关闭开关

我们的 API 现在有 APN 的 deviceToken,但用户通过 iPhone 设置关闭了推送通知。

“问题”:

在用户关闭推送通知后,我们仍然能够向设备发送静默推送通知,并且“MyApp”可以毫无问题地获取正确的数据。

但在另一种情况下:用户安装并启动“MyApp”并在第一次启动时拒绝推送通知,因此无法从 Apple 获取 deviceToken。即使用户拒绝了这样的推送通知警报,我也尝试从 Apple 获取 deviceToken:(但这不起作用 - 我猜如果用户拒绝,Apple 不会提供我的任何信息)

func registerForPushNotifications() {
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
            self.getNotificationSettings()
        }
    }

    func getNotificationSettings() {
        UNUserNotificationCenter.current().getNotificationSettings { (settings) in
            DispatchQueue.main.async {
                UIApplication.shared.registerForRemoteNotifications()
            }
        }
    }

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let tokenParts = deviceToken.map { (data) -> String in
            return String(format: "%02.2hhx", data)
        }
        let token = tokenParts.joined()
        print("ApnToken: \(token)")
    }

如果用户在第一次启动时接受推送通知,那么他做什么似乎并不重要。我的意思是好的,我们无法通过横幅或任何方式向用户显示信息,但我们可以使用 APN 将数据传输到设备,即使用户后来确实关闭了此设置。 (但如果他在应用程序启动时拒绝,我们将无法发送任何内容 - 我们需要一次 deviceToken)

我是不是误解了什么?这对我来说似乎不一致。

我试图澄清我的问题,以便每个人都能理解我的要求。请原谅我的“糟糕”英语,作为一个非母语人士,在这里提出具有大量上下文的具体问题并不容易。无论如何,如果您需要更多信息,或者您不理解我所问内容中的一个或多个要点,请告诉我,我将提供详细信息并澄清我的问题。

我不知道这是否重要,但目前我们正在使用 APN-Development-Certificate(还不是分发证书)

最佳答案

好问题,

问题是,如果用户允许您发送推送通知(给您他/她的设备 token ),您就可以发送推送。通过通知推送的数据可以在不通知用户的情况下发送(静默通知),您可以在这里阅读更多相关信息:https://medium.com/@m.imadali10/ios-silent-push-notifications-84009d57794c

这就是为什么即使用户阻止显示通知,您也可以发送推送。该设置仅控制显示外观,但由于他/她给了您 token ,您仍然可以向他们发送数据。实际上,用户无法在授予该 token 后禁用该 token 。

关于ios - Apple 推送通知 (APN) 不一致?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51055491/

相关文章:

c - UnsafeMutablePointer<Int8> 到 UTF8 字符串

ios - 添加到 subview 的 UIbutton 导致应用程序快速崩溃

ios - UIWebView 显示 UIActivityIndi​​cator 用于加载,但在页面初始加载后忽略其他加载请求(例如 javascript 加载的广告)

ios - 将从iPad/iPhone拍摄的图像保存到sql server数据库base64

swift - 为什么在类中需要声明 self 的结构中不需要声明 self ?

cordova - 当应用程序打开或应用程序在后台时,Phonegap Firebase 推送通知不会触发事件监听器

google-chrome - 如何使用 chrome devtools 推送调试功能?

macos - 无法在 Mac 上注册 Apple 推送通知服务

ios - 检测 uiswitch 更改并相应地运行代码

ios - 输入对话框中的 UITextField 未显示