一、关于推送

1. APNs是什么?

Apple Push Notification service (以下用APNs代称),APNs 是苹果远程推送功能中最引人注目的核心,它是一个健壮的、安全的、高效的服务,可以让 app 开发者在 iOS (如果有的话,watchOS)、 tvOS 和 macOS设备上宣传各种信息。

2. APNs是如何工作的?

当 app 在用户的设备上初次运行的时候,系统会在 app 和 APNs 之间自动地建立一个受认可的、加密的和持续的长链接。这个链接允许你的 app 设置是否要收到推送。

这具体有4个步骤

  1. 运行收到通知
  2. 注册 APNs 然后收到一个 app 指定的设备 token
  3. 把上面收到的 token 发送到后台服务器
  4. 在 app 里面实现对于将要来的远程推送的相关支持

剩下的就是提供者服务器和 APNs 之间的通信了,需要在苹果的开发者账户中配置还要使用苹果提供的加密过的证书。提供者也就是服务器,你需要在上面部署、管理来跟 APNs 进行通信(如下图:)

based on HTTP/2 Network Protocol, a POST request, a JSON payload, a device token

传送方式最大 size
legacy binary interface2KB(2048bytes)
HTTP/2 (recommanded)4KB
VoIP5KB

远程推送的产生过程

当在后台和 app 上推送配置都完成以后,后台服务器就可以发送推送请求到 APNs,APNs 会传达相关的推送装载(payload)给目标设备。收到这条推送以后,系统就会把 payload 传到设备指定的 app 中,以此 app 可以管理和用户的交互。

如果 app 的推送到达了一个开机的设备,但是 app 没有在运行,系统依然会展示这一条推送。但是如果设备关机了的话,APNs 会暂停然后稍后再进行分发推送。

二、 iOS 12 推送的新特性

1. Grouped Notification

a. iOS 12 之前的通知

屏幕快照 2018-08-07 下午6.32.55

b. iOS 12 的 Grouped Notification

屏幕快照 2018-08-07 下午6.35.32

c. 改进原因

  • 分组后的通知更有条理,更高效,不会让用户淹没在通知流中

d. Automatic Grouping

屏幕快照 2018-08-07 下午6.44.45

有三种方式去设置分组的方式:

  • 自动分组,如果在 payload 里面设置了thread-id那么会按照thread-id进行分组
  • 忽略thread-id,一个 app 的通知只分在一个组里面
  • 关闭分组,跟 iOS 12 之前的通知样式一样,平铺通知

e. Thread identifier

在 payload 里面配置的字段是thread-id,但是在本地推送中字段是threadIdentifier

需要注意的是,根据苹果文档

Provide this key with a string value that represents the app-specific identifier for grouping notifications. If you provide a Notification Content app extension, you can use this value to group your notifications together.

必须要在 app 里面实现了ContentExtension,才能实现分组功能。

f. Summary Text

  • 默认样式

    • 屏幕快照 2018-08-07 下午7.22.17
  • 自定义样式

    • 屏幕快照 2018-08-07 下午7.22.30

2. Notification content extensions

a. 创建步骤

  1. 选择模板

屏幕快照 2018-08-07 下午7.25.55

  1. 自动完成默认类的创建
import UserNotifications 
import UserNotificationsUI 

class NotificationViewController: UIViewController, UNNotificationContentExtension {
    func didReceive(_ notification: UNNotification) { 
        // Set up content extension view 
    } 
} 
  1. 在 plist 文件中更改 category 的名称

屏幕快照 2018-08-07 下午7.31.41

b. 设置 Action

 屏幕快照 2018-08-07 下午7.33.14

   // Set up actions.
    let testAction = UNNotificationAction(identifier: "testAction", title: "test", options: [.authenticationRequired])

    // Set up categories.
    let textCategory = UNNotificationCategory(identifier: "textCategory", actions: [testAction], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: "textCategory", options: [])

    notificationCenter.setNotificationCategories([imageCategory,textCategory])

c. Action 回调

两个方法(都要遵守UNNotificationContentExtension协议 ):

  1. Appdelegate 里面实现 didReceive(_ response: UNNotificationResponse, completionHandler completion: @escaping (UNNotificationContentExtensionResponseOption) -> Void)
  2. ContentExtension 里面实现 didReceive(_ response: UNNotificationResponse, completionHandler completion: @escaping (UNNotificationContentExtensionResponseOption) -> Void)

d. 局限

  1. 不够动态,不能及时更新 Action
  2. category 绑定在了一起,在创建 category 的时候就绑定了 Action

e. 引入了新的 api

  • var notificationActions: [UNNotificationAction]

    • readWrite Action 数组
  • UNNotificationExtensionUserInteractionEnabled

    • ContentExtension 中 的 plist 文件中的 NSExtension 项中添加
    • YES 可以允许在 ContentExtension 中交互
  • func performNotificationDefaultAction()

    • 可以在交互里面写然后进入 app
  • func dismissNotificationContentExtension()

    • 退出 ContentExtension
    • 不会 remove 掉这个通知

f. 效果

  • 没有使用新的 api:

    • 屏幕快照 2018-08-07 下午7.53.04
  • 使用了新的 api 后

    • 屏幕快照 2018-08-07 下午7.53.16

3. Notification management

a. 3个方式来管理通知

  1. 通知左滑使用 Manage

    1. 710_hd_whats_new_in_user_notifications_2018年8月7日 下午8.16.18
  2. 3D Touch 通知点击右上角的 ...

    1. 710_hd_whats_new_in_user_notifications_2018年8月7日 下午8.18.29
  3. 偶尔出现在通知底下的建议提示框

    1. 710_hd_whats_new_in_user_notifications_2018年8月7日 下午8.18.54

b. 页面内配置通知

  • func userNotificationCenter(_ center: UNUserNotificationCenter, openSettingsFor notification: UNNotification?)

4. Provisional authorization

a. iOS 12 之前,在用户收到通知之前,有这个提示

屏幕快照 2018-08-07 下午8.52.22

b. 临时授权

屏幕快照 2018-08-07 下午8.56.18

特性:

  • 自动使用
  • 没有授权提示
  • 静音推送(只在通知中心中遇到)

c. 实现步骤

let notificationCenter = UNUserNotificationCenter.current() 
notificationCenter.requestAuthorization(options:[.badge, .sound, .alert, .provisional]) { 

} 

d. 总结

  1. 要让通知内容更有意义,无论是时间还是内容
  2. 使用.provisional作为修饰词

5. Critical alerts

a. 引入的原因

WX20180808-101813@2x

  • 在 iOS 12 以前如果设置了勿扰模式,通话和通知会被静音
  • 在某些情况下,重要的通知会被遗漏,比如:

    • 医药、健康监测(WWDC 710的例子是低血糖警告)
    • 家庭和安全
    • 公共安全
  • 这些通知都是需要用户马上做出反应的

b. Critical Alert 的特点/

  1. 无视勿扰模式铃声开关
  2. 播放声音,甚至是自定义的音频文件
  3. 因此,Critical Alert 会干扰到用户
  4. WWDC上不建议所有的 app 都使用这一特性,除非真的需要
  5. 需要申请Entitlement

c. Critical Alert的样式

  • 通知带有警告logo

    • 屏幕快照 2018-08-08 上午10.33.20
  • 在通知设置里面可以选择开关或者关闭Critical Alert,甚至可以只开启Critical Alert,而关闭其他所有通知

    • 屏幕快照 2018-08-08 上午10.33.34
  • 因此,Critical Alert会有特别的弹窗样式

    • 屏幕快照 2018-08-08 上午10.37.17

d. 代码实现

let notificationCenter = UNUserNotificationCenter.current()

// options 后面带 criticalAlert
notificationCenter.requestAuthorization(
    options:[.sound, .badge, .alert, .criticalAlert]) {
}


let content = UNMutableNotificationContent()
content.title = "WARNING: LOW BLOOD SUGAR"
content.body = "Glucose level at 57."
content.categoryIdentifier = "low-glucose—alert"
// 可以自定义声音
content.sound = UNNotificationSound.criticalSoundNamed(@"warning-sound" withAudioVolume: 1.00)

payload

{
    "aps" : {
        "sound" : {
            "critical": 1,
            "name": "warning-sound.aiff",
            "volume": 1.0
           }
    }
}

e. 总结

  1. Critical Alert 是需要用户马上开始采取行动的特别的通知
  2. 具有干扰性

参考:

苹果APNs文档

WWDC710视频