iOS - APNS 远程推送
参考文档
开始集成 iOS 的远程推送,先在苹果开发者账号配置好推送证书后,开始进行代码开发
第一步,获取通知权限,系统通知框只会出现一次,如果用户拒绝授权。根据需要通过获取当前通知权限,去弹一个提示用户前往 System Setting 打开授权的自定义弹窗
前往 System Setting 页面的示例代码如下
UIApplication.shared.open(URL.init(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)
iOS 10.0 开始支持 UNUserNotificationCenter
,直接通过 UNUserNotificationCenter
请求通知权限
// 该方法会触发
UIApplication.shared.registerForRemoteNotifications()
let center = UNUserNotificationCenter.current()
// center.delegate = self
center .requestAuthorization(options: [.sound, .alert]) { (grand, error) in
if (error != nil) {
}else {
}
}
获取到推送权限之后,我们需要在移动端获取注册后的 device-token,然后将 device-token 传到我们的后台
// 获取用于注册的 DEVICE_TOKEN
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
var deviceTokenString = ""
let bytes = [UInt8](deviceToken)
for item in bytes {
deviceTokenString += String(format:"%02x", item&0x000000FF)
}
// 获取到 DEVICE_TOKEN 后和用户账号进行绑定
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
}
提交完成后,当我们接收到推送消息时在 didReceiveRemoteNotification
代理方法中进行消息处理
// 已经收到通知
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// UIApplication.State 有三种状态: inactive/active/background
// inactive 是处理应用从后台跳转前台,还是从前台到后台的事件触发状态
if application.applicationState == .inactive {
guard let navi = window?.rootViewController as? UINavigationController else { return }
navi.pushViewController(DeviceManagementViewController.init(), animated: true)
}
}
推送消息分为两种格式:透传消息、通知栏消息
- 通知栏消息,当设备在后台收到远程推送后,立刻弹出通知栏,开发者没办法控制通知栏的弹出
- 通过透传消息可以自定义消息格式,然后在前台做 UI 的多样式展示
通知栏消息的格式参考 Generating a Remote Notification,其中 alert 字典中的 title、subtitle、body 中可以控制消息通知的标题、副标题、内容
{
"aps" : {
"alert" : {
"title" : "Game Request",
"subtitle" : "Five Card Draw",
"body" : "Bob wants to play poker"
},
"category" : "GAME_INVITATION"
},
"gameID" : "12345678"
}
展示效果如下图所示
如何实现在前台,当收到消息的时候也弹出通知栏
/// 添加 UNUserNotificationCenter 的 代理
/// 实现 UNUserNotificationCenterDelegate 的 userNotificationCenter 方法
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification, withCompletionHandler
completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.badge, .sound, .alert])
}
App icon 角标处理,苹果的推送消息会根据 JSON 中 apns 的 badge 字段进行角标数量的设置,然后在 App 端进行启动后的 -1 或者清空
// 角标数量清空
UIApplication.shared.applicationIconBadgeNumber = 0
推送测试
在 iOS 中我们可以使用命令行进行推送测试,参考文档见 Sending Push Notifications Using Command-Line Tools
文档中有两种方式进行推送: 证书、device-token;这里只讲一下利用 device-token 发送推送的方式:
在终端新建 shell 文件,这里命名为 push-remote-notification
touch push-remote-notification.sh
vim push-remote-notification.sh
编辑 shell 脚本,这里需要 der 和 pem 证书,如果已经有了 p12 证书,可以通过 openssl 进行转换
# 下面的变量需要根据实际情况修改
CERTIFICATE_FILE_NAME={DER 证书路径}
CERTIFICATE_KEY_FILE_NAME={PEM 证书路径}
# bundle id
TOPIC={appid}
DEVICE_TOKEN={device-token}
# 生产环境
# APNS_HOST_NAME=api.push.apple.com
# 开发环境
APNS_HOST_NAME=api.sandbox.push.apple.com
curl -v --header "apns-topic: ${TOPIC}" --header "apns-push-type: alert" --cert "${CERTIFICATE_FILE_NAME}" --cert-type DER --key "${CERTIFICATE_KEY_FILE_NAME}" --key-type PEM --data '{"aps":{"alert":"test"}}' --http2 https://${APNS_HOST_NAME}/3/device/${DEVICE_TOKEN}
运行 shell 脚本
sh push-remote-notification.sh