推送通知入门教程

原文:Push Notifications Tutorial: Getting Started

iOS 开发者喜欢想象人们一直在使用他们的应用。但是,当然,用户也会不得不关闭应用并处理其他事务。毕竟衣服不会自己叠,你知道的! 令人高兴的是,推送通知允许开发者向用户发送消息,即使用户当前没有在使用应用!在本教程中,您将学习如何:

  • 配置您的应用程序以接收推送通知;
  • 将其显示给您的用户或执行其他任务。

开始

什么是推送通知?它们是通过 Apple 推送通知服务 (APNs) 发送给应用程序的消息,即使应用程序没有运行或手机处于睡眠状态。那么,你可以使用推送通知做什么?

  • 显示一条简短的消息,称为 "Alert",以引起人们对应用程序中新内容的关注。
  • 播放通知声音。
  • 在应用程序的图标上设置一个角标数字,让用户知道应用中有新的内容。
  • 让用户可以在不打开应用的情况下进行操作。
  • 显示一个媒体附件。
  • 发送静默推送通知,让应用程序在后台执行任务。
  • 将通知分组到线程中。
  • 编辑或删除已发送的通知。
  • 在显示通知前运行代码以更改通知。
  • 为你的通知显示一个自定义的可交互式 UI。
  • 可能还有更多。

本教程涵盖了许多方面,以帮助您开始在您的应用程序中创建推送通知。要完成本教程,您需要以下条件:

  • Xcode 11.4 或更高版本。早期版本的 Xcode 不支持使用模拟器推送通知。
  • 一个 Apple Developer Program 账号,以便能够开启推送通知功能并编译应用程序。

注:在后面的教程中,您将学习 Sending to a Real Device 向真实设备发送推送通知。

要发送和接收推送通知,您必须执行三项主要任务:

  1. 配置您的应用程序并将其注册到 APNs。
  2. 通过 APNs 从服务器向特定设备发送推送通知。你将用 Xcode 来模拟。
  3. 在应用程序中使用回调来接收和处理推送通知。

发送推送通知消息是你的应用程序的服务端的任务。许多应用程序使用第三方服务来发送推送通知。其他应用程序则使用自定义解决方案或流行的库(如 houston)。在本教程中,您将只触及到发送推送消息,所以一定要查看 Where to Go From Here? 部分,以建立您对推送通知的概念知识。

要开始本教程,请使用本教程顶部或底部的下载材料按钮下载 WenderCast 初始化项目。WenderCast 是大家获取 raywenderlich.com 播客和突发新闻的首选来源。

starter 文件夹中,打开 WenderCast.xcodeproj 。在项目导航中选择 WenderCast,然后选择 WenderCast target。在 General & Capabilities 选项卡中,修改为你的开发帐户。构建并在模拟器中运行。

WenderCast 会显示 raywenderlich.com 播客的列表,并让用户播放它们。但它不会让用户知道什么时候有新的播客,而且 "News" 选项卡是空的! 你很快就会通过推送通知的力量来解决这些问题。

发送和接收推送通知

配置 App

安全性对于推送通知来说是非常重要的。您不希望其他人通过您的应用程序向您的用户发送推送通知。您需要执行几个任务来配置您的应用程序以安全地接收推送通知。

开启推送通知服务

首先,你必须修改应用程序 bundle ID(bundle identifier)。在 Xcode 项目导航栏中高亮选中 WenderCast ,然后选择 WenderCast target。选择 General ,然后将 Bundle Identifier 改为独特的东西,这样 Apple 的推送通知服务器就可以直接推送到这个应用程序。

接下来,你需要在你的开发者账户中创建一个App ID,并开启推送通知权限。Xcode 有一个简单的方法来实现这一点。在 WenderCast target 仍然被选中的情况下,点击 Signing & Capabilities 选项卡,然后点击 + Capability 按钮。在过滤器字段中输入 "push",然后按 Enter 键。

添加推送通知权限后,你的项目应该是这样的:

注意:如果出现任何问题,请访问 Apple Developer Center。你可能需要同意苹果喜欢更新的开发者授权,然后再试一次。

在以上操作的背后,会自动创建 App ID,然后为其添加推送通知权限。你可以登录苹果开发者中心查看验证:

这就是你现在需要配置的所有内容。你可以开始增强应用程序了。

向用户请求通知权限

注册推送通知时,你需要执行两个步骤。首先,您必须向用户申请并获得显示通知的权限。然后,你可以注册设备来接收远程(推送)通知。如果一切顺利,系统就会给你提供一个设备令牌(device token),你可以把它看作是这个设备的"地址"。

在 WenderCast 中,你会在应用启动后立即注册推送通知。先询问用户权限。

打开 AppDelegate.swift,在文件顶部添加以下内容。

swift 复制代码
import UserNotifications

然后,在 AppDelegate 的末尾添加以下方法:

swift 复制代码
func registerForPushNotifications() {
    // 1. 注册推送通知,向用户请求通知权限
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, _) in
        print("Perission granted: \(granted)");
    }
}

这段代码的作用:

  1. UNUserNotificationCenter 处理应用程序中所有与通知相关的活动,包括推送通知。
  2. 你调用 requestAuthorization(options:completionHandler:) 向用户请求授权以显示通知。传递的选项表示您希望您的应用程序要使用的通知类型--这里您请求的是警报、声音和角标。
  3. 完成处理程序会收到一个 Bool 类型的返回值,表示授权是否成功。在这种情况下,你只需打印结果。

注意 :您传递给 requestAuthorization(options:completionHandler:) 的参数可以包括 UNAuthorizationOptions 枚举类型的任意组合。

  • .badge: 在应用程序图标的角落上显示一个数字。
  • .sound: 播放一个声音。
  • .alert: 显示一个文本通知。
  • .carPlay:在CarPlay中显示通知。
  • .provisional:临时通知。发布不间断的通知。如果你只使用这个选项,用户不会收到权限请求,你的通知只会静静地显示在通知中心。
  • .providesAppNotificationSettings。表示应用有自己的 UI 进行通知设置。
  • .criticalAlert:紧急通知,忽略系统静音开关和勿扰模式。你需要苹果公司的特殊授权才能使用这个选项,因为它只针对非常特殊的用例(🤔 盲猜,地震警报?台风?海啸?火山爆发紧急通知,家人之间的 SOS 通知)。

application(_:didFinishLaunchingWithOptions:) 的结尾处,在 return 之前添加以下内容:

swift 复制代码
registerForPushNotifications()

在这里调用 registerForPushNotifications() 方法可以确保应用程序在任何时候启动时都会尝试注册推送通知。

构建并运行应用。当应用程序启动时,您应该收到一个提示,要求允许向您发送通知。

点击允许,然后,该应用现在可以显示通知了。很好!但是如果用户拒绝了这个权限怎么办?在 AppDelegate 中添加这个方法:

swift 复制代码
// 获取通知设置
func getNotificationSettings() {
    UNUserNotificationCenter.current().getNotificationSettings { (settings) in
        print("Notification settings: \(settings)")
    }
}

首先,你指定了你想要的设置。这个方法返回用户已经授予的设置。现在,你正在打印它们,但你很快就会回到这里,用这个来做更多的事情。

registerForPushNotifications() 方法中,将调用 requestAuthorization(options:completionHandler:) 替换为以下内容:

swift 复制代码
func registerForPushNotifications() {
    // 1. 注册推送通知,向用户请求通知权限
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { [weak self] (granted, _) in
        print("Perission granted: \(granted)");

        guard granted else { return }
        self?.getNotificationSettings()
    }
}

你在完成处理程序中添加了对 getNotificationSettings() 方法的调用。这一点很重要,因为用户可以在任何时候进入系统设置中更改他们的通知权限。guard 可以避免在没有授予权限的情况下调用该方法。

向 APNs 注册

现在你有了推送通知权限,你就可以注册远程通知了!

getNotificationSettings() 方法中,在闭包中的 print 下面添加以下内容:

swift 复制代码
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async {
    UIApplication.shared.registerForRemoteNotifications()
}

在这里,你要验证 authorizationStatus.authorized。表面用户已经授予了通知权限。如果是,你调用UIApplication.shared.registerForRemoteNotifications() 来启动 Apple Push Notification 服务的注册。你需要在主线程上调用这个,否则你会收到一个运行时警告。

AppDelegate 的结尾添加以下内容。

swift 复制代码
// 向 APNs 注册成功时调用,返回设备标识符
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
    let token = tokenParts.joined()
    print("Device Token: \(token)")
}

每当调用 registerForRemoteNotifications() 成功时,iOS 就会调用这个方法。这段代码可能看起来很神秘,但它只是将接收到的 deviceToken 转换为字符串。设备令牌是这个过程的成果。它由 APNs 提供,并在这个特定的设备上唯一地标识这个应用。

当发送推送通知时,服务器使用令牌作为目标 "地址" 来传递给正确的设备。在你的应用中,你现在会将这个令牌发送到服务器上保存,并在以后用于发送通知。

现在添加以下代码:

swift 复制代码
// 向 APNs 注册失败时调用
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
    print("Failed to register:\(error)")
}

如果 registerForRemoteNotifications() 方法执行失败,iOS 会调用这个方法。你现在只是在打印错误。

就是这样!构建并运行。因为你是在模拟器上,你会看到一个注册失败的错误。你可以暂时忽略它。稍后,当你在真实设备上运行时,你应该会在控制台输出中收到一个 token。下面是一个例子:

注意:注册失败可能有多种原因。大多数情况下,这是因为 App ID 没有正确配置。错误信息通常会带有很好的提示,说明问题所在。

发送模拟推送通知

使用文本编辑器创建一个名为 first.apn 的文件,你将把它传递给 Xcode 的 simctl 工具。粘贴以下 JSON 文本并保存文件。

json 复制代码
{
  "aps": {
    "alert": "Breaking News!",
    "sound": "default",
    "link_url": "https://raywenderlich.com"
  }
}

这个 JSON 的结构将在下一节解释。请耐心点,小蚂蚱。

在模拟器上再次构建并运行应用,然后将应用切换到后台或锁定设备。应用在前台时还不能处理推送通知。

要使用 simctl ,你需要知道你正在运行应用的模拟器的设备标识符。如果模拟器中只运行一个设备,你可以使用 booted 代替标识符。要获得标识符,在 Xcod e中,选择 WindowsDevices and Simulators ,然后选择顶部的 Simulators 选项卡,并从左侧的列表中选择你正在使用的模拟器。使用鼠标复制标识符。您可能需要扩大对话框才能完全看到它。

打开 Terminal 应用程序,使用 booted 或 Xcode 中的设备标识符代替 device_identifier 键入以下命令:xcrun simctl push device_identifier bundle_identifier first.apn。将 device_identifier 替换为你从 Xcode 中复制的设备标识符,将 bundle_identifier 替换为应用程序的 bundle 标识符--你第一次设置项目时使用的标识符。下面是一个例子。

运行该命令,你会看到推送通知出现在模拟器上!

点击通知,应用程序就会启动。

这难道不是很酷吗?

查看基本的推送通知

在你继续处理推送通知之前,先看看你发送的通知消息:

json 复制代码
{
  "aps": {
    "alert": "Breaking News!",
    "sound": "default",
    "link_url": "https://raywenderlich.com"
  }
}

有效载荷是一个 JSON 字典,其中至少包含一个 aps 项,它也是一个字典。在这个例子中,aps 包含字段 alertsoundlink_url。当设备收到这个推送通知时,会显示一个带有 "Breaking News!" 文字的警报弹窗视图,并播放标准的音效。

link_url 实际上是一个自定义字段。你可以像这样在有效载荷中添加自定义字段,它们会被传递到你的应用程序中。因为你还没有在应用内部处理它,所以这个键值对目前没有任何作用。

更正 :一位敏锐的读者指出,苹果公司的文档 中规定,link_url 等自定义内容应该与 aps 字典条目处于同级,而不是在其内部。虽然你把它放在里面,它也仍然可以工作,但我们总是建议遵守苹果的文档,并将在我们下一次更新本教程时纠正这一点。

有八个内置的 key 可以添加到 aps 字典中(更多信息请参见官方的 Payload Key Reference):

  • alert: 这可以是一个字符串,就像前面的例子,也可以是一个字典。作为一个字典时,它可以将 text 本地化或改变通知的其他方面。
  • badge:这是一个数字,将显示在应用程序图标右上角(角标)。您可以通过将其设置为0来删除角标标记。
  • sound:这是自定义通知声音的文件名。位于应用程序中的自定义通知声音的文件名。这些声音必须短于 30 秒。
  • thread-id:使用此键对通知进行分组。
  • category:这定义了通知的类别,用于在通知上显示自定义操作。你将很快探索这个问题。
  • content-available:静默通知,通过将此键设置为 1,推送通知就会变得无声。你将在下面的 "静默推送通知" 部分了解到这一点。
  • mutable-content:通过将这个键设置为 1,你的应用程序可以在显示之前修改通知。
  • target-content-id:这是带来的窗口的标识符。

除此之外,你可以添加尽可能多的自定义数据,只要有效载荷不超过 4,096 字节。

一旦你有足够的乐趣,尝试这些选项并发送推送通知到你的模拟器,然后开启下一节!

处理推送通知

在本节中,您将学习当应用程序收到通知并且用户点击通知时如何执行操作。

理解当推送通知到达时发生了啥

当你的应用收到推送通知时,iOS 会调用 UIApplicationDelegate 中的一个方法。

你需要根据「收到通知时你的应用处于什么状态」来处理通知。

  • 如果你的应用没有运行,用户通过点击推送通知来启动它,iOS 会在 application(_:didFinishLaunchingWithOptions:)launchOptions 中把通知传递给你的应用。
  • 如果你的应用是在前台或后台运行,系统会通过调用 application(_:didReceiveRemoteNotification:fetchCompletionHandler:) 来通知你的应用。当用户通过点击推送通知打开应用时,iOS 可能会再次调用这个方法,这样你就可以更新 UI 并显示相关信息。

在第一种情况下,WenderCast 会创建新闻项目,并直接打开新闻标签。在 AppDelegate.swift 中,在application(_:didFinishLaunchingWithOptions:) 的末尾,在返回语句之前添加以下代码:

swift 复制代码
// 当收到推送通知时,如果应用没有运行,用户点击推送通知消息
// 推送消息内容从此方法传递进来
func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    UITabBar.appearance().barTintColor = UIColor.themeGreenColor
    UITabBar.appearance().tintColor = UIColor.white

    // 注册推送通知
    registerForPushNotifications()

    // 检查是否通过通知启动
    let notificationOption = launchOptions?[.remoteNotification]

    // 1
    if let notification = notificationOption as? [String: AnyObject],
       let aps = notification["aps"] as? [String: AnyObject] {

        // 2
        NewsItem.makeNewsItem(aps)

        // 3
        (window?.rootViewController as? UITabBarController)?.selectedIndex = 1
    }

    return true
}

这就是你正在做的事情:

  1. 检查 UIApplication.LaunchOptionsKey.remoteNotification 的值是否存在于 launchOptions 中。如果存在,那么你的应用是从通知中启动的。这里面就会包含你发送的推送通知的有效载荷。
  2. 由于 aps 字典存在,用它创建一个 NewsItem
  3. 将标签控制器的 selectedIndex 索引定位到新闻页面。

为了测试,你需要编辑 WenderCast 项目的 scheme 。首先,在模拟器上构建并运行以安装最新的代码。然后,点击 WenderCast 的 schema,选择 Edit Scheme... 编辑方案。

从侧边栏选择 Run ,然后在 Info 选项卡中选择 Wait for executable to be launched(等待可执行文件启动)。

这个选项会在安装应用时,等待应用第一次启动后(应用不会自启动),再让 debugger 调试器附加到应用上。

构建并运行。安装完成后,像之前一样用 xcrun simctl 发送更多的突发新闻。点开通知,应用就会打开新闻。

要处理您的应用程序在收到推送通知时正在运行的情况,请向 AppDelegate 添加以下内容:

swift 复制代码
// 当应用收到推送通知时,处理收到的推送通知内容
// 无论应用此时处于前台还是后台,都会调用此方法!
// 默认情况下,如果应用收到推送通知时处于前台状态,则会丢弃通知内容
// 这里可以截获推送内容,并更新应用页面
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    guard let aps = userInfo["aps"] as? [String: AnyObject] else {
        completionHandler(.failed)
        return
    }

    NewsItem.makeNewsItem(aps)
}

以上代码尝试从返回参数的 userInfo 对象中提取 aps,如果成功,则创建一个新的 NewsItem

由于 iOS 会在应用运行时调用这个方法,所以你需要将 scheme 改回自动启动应用来测试。在 Scheme 方案编辑器中,在 Launch 下,选择 Automatically

构建并运行。保持应用在前台运行状态,将页面停留在新闻标签上。发送另一个新闻推送通知,并观察它是否出现在 feed 中。

就是这样!你的应用程序现在可以神奇地接收突发新闻的发生 :]

注意:推送通知不能保证到达。这对于 WenderCast 来说是可接受的,因为拥有完整的新闻列表对于这个应用来说并不太重要。不过一般来说,你不应该将推送通知作为传递内容的唯一方式。相反,推送通知应该发出有新内容可用的信号,并让应用程序从源头(例如,从REST API)下载内容。

添加可操作的通知

可操作的通知可以让你在通知本身上添加自定义按钮。你可能已经注意到了这一点,在电子邮件通知或推特上,可以直接在通知上 "回复 "或 "收藏"。

当你注册通知时,你的应用可以通过使用 categories 来定义可操作通知。每个类别的通知都可以有一些预设的自定义动作。

注册后,你的服务器可以设置推送通知的类别。当用户收到通知时,就可以进行相应的操作。

对于 WenderCast 应用来说,你会定义一个 News 类别,并有一个名为 View 的自定义动作。如果用户选择这个动作,它将允许用户在应用中查看新闻文章。

registerForPushNotifications() 方法中,在 guard 和调用 getNotificationSettings()方法之间插入以下内容:

swift 复制代码
func registerForPushNotifications() {
    // 1. 注册推送通知,向用户请求通知权限
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { [weak self] (granted, _) in
        print("Perission granted: \(granted)");

        guard granted else { return }

        // 1 创建一个新的通知动作,标题为 "View" 按钮,当被触发时就会在前台打开应用程序。
        // 该动作有一个唯一标识符,iOS 用它来区分同一个通知上的其他动作。
        let viewAction = UNNotificationAction(identifier: Identifiers.viewAction,
                                              title: "View",
                                              options: [.foreground])

        // 2 定义新闻类别,它将包含动作按钮。这也有一个独特的标识符,您的有效载荷将需要包含该标识符,以指定推送通知属于该类别。
        let newCategory = UNNotificationCategory(identifier: Identifiers.newsCategory,
                                                 actions: [viewAction],
                                                 intentIdentifiers: [],
                                                 options: [])

        // 3 通过调用 setNotificationCategories 来注册新的可操作通知。
        UNUserNotificationCenter.current().setNotificationCategories([newCategory])

        self?.getNotificationSettings()
    }
}

在这里,逐步分解:

  1. 创建一个新的通知动作,标题为 "View" 按钮,当被触发时就会在前台打开应用程序。该动作有一个唯一标识符,iOS 用它来区分同一个通知上的其他动作。
  2. 定义新闻类别,它将包含动作按钮。这也有一个独特的标识符,您的有效载荷将需要包含该标识符,以指定推送通知属于该类别。
  3. 通过调用 setNotificationCategories 来注册新的可操作通知。

构建并运行应用程序以注册新的通知设置。

后台应用程序,然后通过 xcrun simctl 命令行发送以下有效载荷:

json 复制代码
{
  "aps": {
    "alert": "Breaking News!",
    "sound": "default",
    "link_url": "https://raywenderlich.com",
    "category": "NEWS_CATEGORY"
  }
}

当通知出现时,将其下拉以显示并查看操作:

很好! 点击 View 会启动 WenderCast,但它还没有做任何令人兴奋的事情。要让它显示新闻项目,你需要在代表中做更多的事件处理。

处理通知动作

每当一个通知动作被触发时,UNUserNotificationCenter 就会通知其委托对象。回到 AppDelegate.swift 文件中,在文件底部添加以下类扩展:

swift 复制代码
// MARK: - UNUserNotificationCenterDelegate

extension AppDelegate: UNUserNotificationCenterDelegate {
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        // 1. 获取 userInfo 字典。
        let userInfo = response.notification.request.content.userInfo;
        
        // 2. 从 aps 字典中创建一个 NewsItem,然后导航到 News 标签页选项卡。
        if let aps = userInfo["aps"] as? [String: AnyObject],
           let newItem = NewsItem.makeNewsItem(aps) {
            (window?.rootViewController as? UITabBarController)?.selectedIndex = 1
            
            // 3. 检查 actionIdentifier。如果是 "View" 动作,并且链接是有效的 URL,那么它就会在一个 SFSafariViewController 中显示链接。
            if response.actionIdentifier == Identifiers.viewAction,
               let url = URL(string: newItem.link) {
                let safari = SFSafariViewController(url: url)
                window?.rootViewController?.present(safari, animated: true, completion: nil)
            }
        }
        
        // 4. 调用系统传递给你的完成处理程序。
        completionHandler()
    }
}

这是当应用程序因自定义操作而打开时,你得到的回调。它可能看起来有很多事情要做,但这里没有太多的新东西:

  1. 获取 userInfo 字典。
  2. aps 字典中创建一个 NewsItem,然后导航到 News 标签页选项卡。
  3. 检查 actionIdentifier。如果是 "View" 动作,并且链接是有效的 URL,那么它就会在一个 SFSafariViewController 中显示链接。
  4. 调用系统传递给你的完成处理程序。

还有最后一点。你必须在 UNUserNotificationCenter 上设置委托。在 application(_:didFinishLaunchingWithOptions:) 的顶部添加这一行:

swift 复制代码
UNUserNotificationCenter.current().delegate = self

构建并运行。再次关闭应用程序,然后发送另一个有效负载如下的新闻通知:

json 复制代码
{
  "aps": {
    "alert": "New Posts!",
    "sound": "default",
    "link_url": "https://raywenderlich.com",
    "category": "NEWS_CATEGORY"
  }
}

下拉通知,然后点击 "View" 操作,你会看到 WenderCast 在启动后会立即呈现一个 Safari View 控制器:

恭喜!你已经实现了一个可操作的通知。发送更多的通知,并尝试以不同的方式打开通知,看看它是如何表现的。

发送到真机设备

如果你不想向真机设备发送推送通知,或者你还不需要静默推送通知,你可以跳过本节,转到 Where to Go From Here?

然而,如果你想了解如何将推送通知发送到真机设备并想要尝试静默推送,那么你需要做一些额外的设置。下载 PushNotifications 开源工具。你将使用该工具向真机设备发送通知。要安装它,请按照 How to install 中的说明进行安装。要特别注意如何打开应用程序,因为你必须改变一些设置才能运行这个实用程序。

前往苹果开发者中心并登录。

发送推送通知需要一个认证密钥 (Authentication Key)。在会员中心,选择 Certificates, Identifiers & Profiles ,然后在左侧窗格中找到 Keys 。在 Keys 标题上有一个 "+" 按钮。点击它来创建一个新的密钥。

给密钥设置名称,比如 "Push Notification Key"。在 Key Services 下,勾选 Apple Push Notifications service (APNs)

点击 Continue ,然后在下一个屏幕上注册,以创建你的新密钥。点击 Download 。下载的文件会有一个类似 AuthKey_4SVKWF966R.p8 的名字。注意这个文件--你需要用它来发送通知。文件名中的 4SVKWF966R 部分是 Key ID。你也需要这个。

最后一点你需要的是你的 Team ID 。导航到苹果开发者中心的 Membership Details 页面找到它。

您成功了!有了新密钥,您现在可以发送您的第一个推送通知了,您只需要再做一件事。

在您的真机设备上运行应用程序,并从 Xcode 调试器控制台复制设备令牌(Device Token),等会需要将其复制粘贴到 PushNotification 工具中。

启动 PushNotifications 并执行以下步骤:

  1. Authentication 选项中,选择 TOKEN
  2. 点击 SELECT P8 按钮,在 Mac 文件中找到并选择之前下载的 .p8 文件。
  3. 在相关字段中输入您的 Key IDTeam ID
  4. Body 中,输入你的应用程序的 Bundle ID 和你的 Device Token。
  5. 将 body 内容更改为如下:
json 复制代码
{
  "aps": {
    "alert": "Breaking News!",
    "sound": "default",
    "link_url": "https://raywenderlich.com"
  }
}

点击 PushNotifications 工具右侧的 Send 按钮通过 APNs 发送推送通知。

你应该能收到推送通知:

处理常见问题

这里有几个你可能遇到的问题。

  1. 部分推送通知发送成功了,但不是全部:如果你同时发送许多推送通知,但你只收到了几个,不要害怕!这就是这样设计的。APNs 为每个设备维护一个 QoS(服务质量)队列。这个队列的大小是1,所以如果你发送多个通知,最后一个通知会被覆盖。
  2. 连接到推送通知服务(Push Notification Service)的问题。一种可能是防火墙封锁了 APNs 使用的端口。确保你解除了这些端口的封锁。

使用静默通知

静音推送通知可以静默唤醒你的应用,在后台执行一些任务。WenderCast 可以使用这个功能来悄悄刷新播客列表。

如果有一个合适的服务器组件,这可以是非常高效的。你的应用程序将不需要不断地轮询数据。每当有新数据时,你可以向它发送一个无声的推送通知。

要开始,再次选择 WenderCast 项目 target。现在点击 Signing & Capabilities 选项卡,添加 Background Modes capability。然后勾选其中的 Remote notifications 选项:

现在,当您的应用程序收到这些推送通知时,它将在后台唤醒。

AppDelegate.swift 文件中,找到application(_:didReceiveRemoteNotification:fetchCompletionHandler:)。将对 NewsItem.makeNewsItem() 的调用替换为以下内容:

swift 复制代码
// 当应用收到推送通知时,处理收到的推送通知内容
// 默认情况下,如果应用收到推送通知时处于前台状态,则会丢弃通知内容
// 这里可以截获推送内容,并更新应用页面
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    guard let aps = userInfo["aps"] as? [String: AnyObject] else {
        completionHandler(.failed)
        return
    }

    // 1. 检查 `content-available` 值是否为 1,如果是,这是一个静默通知标志。
    if aps["content-available"] as? Int == 1 {
        let podcastStore = PodcastStore.sharedStore
        // 2. 刷新播客列表,这是一个异步网络调用。
        podcastStore.refreshItems { (didLoadNewItems ) in
            // 3.当刷新完成后,调用完成处理程序,让系统知道应用程序是否加载了任何新数据。
            completionHandler(didLoadNewItems ? .newData : .noData)
        }
    } else {
        // 4. 如果不是静默通知,那么它就是一个新闻项目,所以要创建一个新闻项目。
        NewsItem.makeNewsItem(aps)
        completionHandler(.newData)
    }
}

查看以上代码:

  1. 你检查 content-available 值是否为 1,如果是,这是一个静默通知标志。
  2. 你刷新播客列表,这是一个异步网络调用。
  3. 当刷新完成后,调用完成处理程序,让系统知道应用程序是否加载了任何新数据。
  4. 如果不是静默通知,那么它就是一个新闻项目,所以要创建一个新闻项目。 一定要用诚实的结果来调用完成处理程序。系统会测量你的应用在后台使用的电池消耗和时间,如果需要的话,可能会对你的应用进行节制。

这就是它的全部内容。要测试它,请构建和运行,将应用切换到前台并通过 PushNotifications 实用程序推送以下有效载荷:

json 复制代码
{
  "aps": {
    "content-available": 1
  }
}

如果一切顺利,应该不会发生任何事情,除非刚刚有新的播客被添加到远程数据库中。为了确认代码按预期运行,在application(_:didReceiveRemoteNotification:fetchCompletionHandler:) 中设置一个断点,并在通知发送后跳过它(step through it)。

何去何从?

恭喜你! 您已经完成了本教程,并使 WenderCast 成为一个具有推送通知功能的全功能应用程序!

您可以使用本教程顶部或底部的 Download Materials 按钮下载完成的项目。

想深入了解推送通知的所有功能,如构建自定义用户界面和发送紧急推送?我们的 Push Notifications by Tutorials 一书将教你推送通知的高级功能。

另一个资源是 iOS 推送通知教程:Rich Push Notification

尽管推送通知是现代应用的重要组成部分,但如果你的通知过度,用户拒绝对你的应用进行权限也是很常见的。但是,通过贴心的设计,推送通知可以让你的用户一次又一次地回到你的应用中来!

希望你喜欢这个推送通知教程。如果你有任何问题,欢迎在下面的讨论区留言。

相关推荐
Myli_ing21 分钟前
考研倒计时-配色+1
前端·javascript·考研
余道各努力,千里自同风23 分钟前
前端 vue 如何区分开发环境
前端·javascript·vue.js
软件小伟32 分钟前
Vue3+element-plus 实现中英文切换(Vue-i18n组件的使用)
前端·javascript·vue.js
醉の虾1 小时前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js
张小小大智慧1 小时前
TypeScript 的发展与基本语法
前端·javascript·typescript
hummhumm1 小时前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
asleep7011 小时前
第8章利用CSS制作导航菜单
前端·css
hummhumm1 小时前
第 28 章 - Go语言 Web 开发入门
java·开发语言·前端·python·sql·golang·前端框架
幼儿园的小霸王2 小时前
通过socket设置版本更新提示
前端·vue.js·webpack·typescript·前端框架·anti-design-vue
疯狂的沙粒2 小时前
对 TypeScript 中高级类型的理解?应该在哪些方面可以更好的使用!
前端·javascript·typescript