iOS 中的推送通知

重要

本节中的信息与 iOS 9 及更早版本有关,此处已保留以支持较旧的 iOS 版本。 对于 iOS 10 及更高版本,请参阅 用户通知框架指南,了解如何在 iOS 设备上支持本地通知和远程通知。

推送通知应保持简短状态,并且仅包含足够的数据,以通知移动应用程序应与服务器应用程序联系以获取更新。 例如,当新电子邮件到达时,服务器应用程序只会通知移动应用程序新电子邮件已到达。 通知不包含新电子邮件本身。 然后,当服务器适合时,移动应用程序将从服务器中检索新电子邮件

iOS 中推送通知的中心是 Apple 推送通知网关服务(APNS)。 这是 Apple 提供的服务,负责将通知从应用程序服务器路由到 iOS 设备。 下图演示了适用于 iOS 的推送通知拓扑:此映像演示了适用于 iOS 的推送通知拓扑

远程通知本身是符合 iOS 开发人员文档中 本地和推送通知编程指南通知有效负载 部分中指定的格式和协议的 JSON 格式字符串。

Apple 维护 APNS 的两个环境:沙盒环境生产环境。 沙盒环境用于在开发阶段进行测试,可在 TCP 端口 2195 上的 gateway.sandbox.push.apple.com 找到。 生产环境用于已部署的应用程序,可在 TCP 端口 2195 上的 gateway.push.apple.com 找到。

要求

推送通知必须遵循 APNS 体系结构规定的以下规则:

  • 256 字节消息限制 - 通知的整个消息大小不得超过 256 字节。
  • 未收到确认 - APNS 不会向发件人提供向预期收件人发送消息的任何通知。 如果设备无法访问并且发送了多个顺序通知,则除最近的通知之外的所有通知都将丢失。 仅将最新的通知传送到设备。
  • 每个应用程序都需要安全证书 - 必须通过 SSL 与 APNS 通信。

创建和使用证书

上一部分中提到的每个环境都需要自己的证书。 本部分介绍如何创建证书、将其与预配配置文件相关联,然后获取用于 PushSharp 的个人信息交换证书。

  1. 若要创建证书,请转到 Apple 网站上的 iOS 预配门户,如以下屏幕截图中所示(请注意左侧的应用 ID 菜单项):

    苹果网站上的 iOS 预配门户

  2. 接下来,导航到“应用 ID”部分并创建新的应用 ID,如以下屏幕截图所示:

    导航到“应用 ID”部分并创建新的应用 ID

  3. 单击“+”按钮时,你将能够输入应用 ID 的说明和捆绑标识符,如下一屏幕截图所示:

    输入应用 ID 的说明和捆绑标识符

  4. 请确保选择 显式应用 ID,并且捆绑标识符不会以 * 结尾。 这将创建一个适用于多个应用程序的标识符,推送通知证书必须适用于单个应用程序。

  5. 在“应用服务”下,选择 推送通知

    选择推送通知

  6. 然后按 提交 以确认注册新的应用程序 ID。

    确认新应用 ID 的注册

  7. 接下来,必须为应用 ID 创建证书。 在左侧导航中,浏览到 证书 > 所有 并选择 + 按钮,如以下屏幕截图所示:

    为应用 ID 创建证书

  8. 选择是要使用开发证书还是生产证书:

    选择开发证书或生产证书

  9. 然后选择刚刚创建的新应用 ID:

    选择刚刚创建的新应用 ID

  10. 这将显示说明,这些说明将引导你完成在 Mac 上使用 Keychain Access 应用程序创建 证书签名请求 的过程。

  11. 创建证书后,它必须用作生成过程的一部分来对应用程序进行签名,以便它可以向 APN 注册。 这需要创建和安装使用证书的预配配置文件。

  12. 若要创建开发预配配置文件,请导航到 预配配置文件 部分,并使用刚刚创建的应用 ID 按照步骤创建配置文件。

  13. 创建预配配置文件后,在 Xcode 组织器 中打开并刷新它。 如果创建的预配配置文件未显示,可能需要从 iOS 预配门户下载配置文件并手动导入配置文件。 以下屏幕截图显示了添加配置文件的组织器示例:
    此屏幕截图显示了管理器示例,其中添加了预配配置文件

  14. 此时,我们需要将 Xamarin.iOS 项目配置为使用此新创建的预配配置文件。 这在 项目选项 对话框的“iOS 包签名”选项卡下完成,如以下屏幕截图所示:
    配置 Xamarin.iOS 项目以使用此新创建的预配配置文件

此时,应用程序配置为使用推送通知。 但是,证书还需要完成几个步骤。 此证书采用与 PushSharp 不兼容的 DER 格式,需要个人信息交换(PKCS12)证书。 若要转换证书,使其可由 PushSharp 使用,请执行以下步骤:

  1. 下载证书文件 - 登录到 iOS 预配门户,选择“证书”选项卡,选择与正确的预配配置文件关联的证书,然后选择 下载
  2. Open Keychain Access - 这是 OS X 中密码管理系统的 GUI 接口应用程序。
  3. 导入证书 - 如果尚未安装证书,文件...从密钥链访问菜单中导入项。 导航到上面导出的证书,然后选择它。
  4. 导出证书 - 展开证书,使关联的私钥可见,右键单击密钥并选择“导出”。 系统会提示输入已导出文件的文件名和密码。

至此,我们已完成与证书相关的工作。 我们创建了一个证书,该证书将用于对 iOS 应用程序进行签名,并将该证书转换为可用于服务器应用程序中 PushSharp 的格式。 接下来,让我们看看 iOS 应用程序如何与 APNS 交互。

向 APNS 注册

在 iOS 应用程序可以接收远程通知之前,它必须向 APNS 注册。 APNS 将生成唯一的设备令牌,并将其返回到 iOS 应用程序。 然后,iOS 应用程序将获取设备令牌,然后将自身注册到应用程序服务器。 一旦发生这种情况,注册就会完成,应用程序服务器可能会将通知推送到移动设备。

从理论上讲,每次 iOS 应用程序向 APNS 注册自身时,设备令牌都可能会更改,但实际上这种情况并不经常发生。 作为优化,应用程序可以缓存最新的设备令牌,并且仅在应用程序服务器发生更改时更新。 下图演示了注册和获取设备令牌的过程:

此图演示了注册和获取设备令牌的过程

通过对当前 UIApplication 对象调用 RegisterForRemoteNotificationTypes,在应用程序委托类的 FinishedLaunching 方法中处理 APNS 注册。 当 iOS 应用程序向 APNS 注册时,它还必须指定要接收的远程通知类型。 这些远程通知类型在枚举 UIRemoteNotificationType中声明。 以下代码片段是 iOS 应用程序如何注册以接收远程警报和锁屏提醒通知的示例:

if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
    var pushSettings = UIUserNotificationSettings.GetSettingsForTypes (
                       UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound,
                       new NSSet ());

    UIApplication.SharedApplication.RegisterUserNotificationSettings (pushSettings);
    UIApplication.SharedApplication.RegisterForRemoteNotifications ();
} else {
    UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
    UIApplication.SharedApplication.RegisterForRemoteNotificationTypes (notificationTypes);
}

APNS 注册请求在后台发生 - 收到响应时,iOS 将在 AppDelegate 类中调用方法 RegisteredForRemoteNotifications 并传递已注册的设备令牌。 令牌将包含在 NSData 对象中。 以下代码片段演示如何检索 APNS 提供的设备令牌:

public override void RegisteredForRemoteNotifications (
UIApplication application, NSData deviceToken)
{
    // Get current device token
    var DeviceToken = deviceToken.Description;
    if (!string.IsNullOrWhiteSpace(DeviceToken)) {
        DeviceToken = DeviceToken.Trim('<').Trim('>');
    }

    // Get previous device token
    var oldDeviceToken = NSUserDefaults.StandardUserDefaults.StringForKey("PushDeviceToken");

    // Has the token changed?
    if (string.IsNullOrEmpty(oldDeviceToken) || !oldDeviceToken.Equals(DeviceToken))
    {
        //TODO: Put your own logic here to notify your server that the device token has changed/been created!
    }

    // Save new device token
    NSUserDefaults.StandardUserDefaults.SetString(DeviceToken, "PushDeviceToken");
}

如果注册因某种原因(例如设备未连接到 Internet)而失败,iOS 将在应用程序委托类上调用 FailedToRegisterForRemoteNotifications。 以下代码片段演示如何向用户显示警报,告知用户注册失败:

public override void FailedToRegisterForRemoteNotifications (UIApplication application , NSError error)
{
    new UIAlertView("Error registering push notifications", error.LocalizedDescription, null, "OK", null).Show();
}

设备令牌维护

设备令牌将在一段时间内过期或更改。 因此,服务器应用程序需要执行一些内部清理和清除这些过期或更改的令牌。 当应用程序作为推送通知发送到具有过期令牌的设备时,APNS 将记录并保存该过期的令牌。 然后,服务器可以查询 APNS,找出哪些令牌已过期。

APNS 用于提供 反馈服务 - 一个 HTTPS 终结点,通过创建的证书进行身份验证以发送推送通知,并发送回有关哪些令牌已过期的数据。 此功能已被 Apple 弃用并移除。

现在,用于反馈服务先前报告情况的新 HTTP 状态代码已经出现。

410 - 该主题的设备令牌不再处于活动状态。

此外,响应正文中还会有新的 timestamp JSON 数据密钥:

如果状态标头中的值为410,则此密钥的值表示APNs最后一次确认设备令牌对该主题无效的时间。

在设备向您的提供商注册具有更晚时间戳的令牌之前,停止推送通知。

总结

本部分介绍有关 iOS 中推送通知的关键概念。 它解释了 Apple 推送通知网关服务(APNS)的角色。 然后,它介绍了创建和使用对 APNS 功能至关重要的安全证书。 这份文档最终总结了应用服务器如何使用 反馈服务 来阻止追踪过期设备令牌的讨论。