我们在使用苹果的APN推送通知时遇到了一个令人困惑的问题。我们有以下场景(我想这是相当标准的):
当我们的应用程序,让我们称之为"MyApp",第一次安装并启动时,我们会要求用户允许我们通过"MyApp"向他发送推送通知。
在这个例子中,AppDelegate看起来像这样:
所以用户安装并启动应用程序时会被问及是否允许"MyApp"发送Push通知。如果用户接受Push通知,就会调用
现在让我感到困惑的部分是:用户还可以稍后通过iPhone设置关闭Push通知,具体操作如下:设置 > "MyApp" > 通知 > 允许通知 > 关闭开关
我们的API现在拥有了APN的设备令牌,但用户通过iPhone设置关闭了Push通知。
“问题”:
当用户关闭Push通知后,我们仍然能够向设备发送静默的Push通知,并且"MyApp"没有任何问题地获得正确的数据。
但在另一种情况下:用户安装并启动"MyApp",并在第一次启动时拒绝Push通知,就无法从Apple获取设备令牌。即使像这样尝试从Apple获取设备令牌,即使用户拒绝Push通知提示,它也无效(我猜测苹果不会提供任何帮助):
似乎无论用户在第一次启动时是否接受了推送通知,都不会影响用户的操作。我的意思是,我们不能通过横幅或其他方式向用户显示信息,但即使用户稍后关闭了此设置,我们仍然可以使用APN将数据传输到设备(但是如果他在应用程序启动时拒绝了,我们无法发送任何东西 - 我们需要获得一个设备标记)。 我是否存在误解?这对我来说似乎是不一致的。
我试图澄清我的问题,以便每个人都能理解我所要求的内容。请原谅我的“糟糕”英语,作为非母语人士,在这里提出具有大量上下文的特定问题并不容易。无论如何,如果您需要进一步的信息,或者您没有理解我的一个或多个点,请让我知道,我将提供详细信息并澄清我的问题。
我不知道这是否重要,但目前我们正在使用APN开发证书(尚未使用分发证书)。
当我们的应用程序,让我们称之为"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"发送Push通知。如果用户接受Push通知,就会调用
application(_:didRegisterForRemoteNotificationsWithDeviceToken:)
方法,并将接收到的设备令牌提供给我们的API。现在让我感到困惑的部分是:用户还可以稍后通过iPhone设置关闭Push通知,具体操作如下:设置 > "MyApp" > 通知 > 允许通知 > 关闭开关
我们的API现在拥有了APN的设备令牌,但用户通过iPhone设置关闭了Push通知。
“问题”:
当用户关闭Push通知后,我们仍然能够向设备发送静默的Push通知,并且"MyApp"没有任何问题地获得正确的数据。
但在另一种情况下:用户安装并启动"MyApp",并在第一次启动时拒绝Push通知,就无法从Apple获取设备令牌。即使像这样尝试从Apple获取设备令牌,即使用户拒绝Push通知提示,它也无效(我猜测苹果不会提供任何帮助):
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将数据传输到设备(但是如果他在应用程序启动时拒绝了,我们无法发送任何东西 - 我们需要获得一个设备标记)。 我是否存在误解?这对我来说似乎是不一致的。
我试图澄清我的问题,以便每个人都能理解我所要求的内容。请原谅我的“糟糕”英语,作为非母语人士,在这里提出具有大量上下文的特定问题并不容易。无论如何,如果您需要进一步的信息,或者您没有理解我的一个或多个点,请让我知道,我将提供详细信息并澄清我的问题。
我不知道这是否重要,但目前我们正在使用APN开发证书(尚未使用分发证书)。