iOS推送的实现

iOS中的推送分为本地推送和远程推送,本文主要介绍远程推送的原理。

原理

还是先从下面这张经典的图说起:

要将指定消息推送到指定的设备上,首先明确谁来发送这个消息,在iOS的推送中,最后实际发送消息的就是APNS-苹果的推送服务器,APNS只是帮忙发送消息,具体发的消息内容以及发到哪些设备上这些都需要额外的服务器告诉APNS,也就是需要部署自己的推送服务器和APNS对接,实际开发中经常使用第三方平台的推送服务诸如友盟,极光和个推等;其次需要确定的是APNS如何定位到指定的设备(即只给指定的设备推送消息),而且推送的消息点击后打开指定的App(我们自己开发的)?这里就需要Device Token这个身份证,有了这个身份证APNS就能准确的将消息推送到指定的设备上。

  • 首先在项目中书写代码请求注册推送,这一步会弹窗告知用户让用户授权。
  • 用户授权成功后,系统会向APNS服务器请求Device Token
  • App在拿到这个Device Token后,要将这个标识自己身份的Device Token上送到第三方服务器集中管理。
  • 当有消息需要推送时,利用第三方服务器的推送窗口,将消息以及需要发送的Device Token信息一并发送给APNS,最后APNS会将消息推送到指定的设备上。

项目配置推送环境

Signing & Capabilities点击Capability button添加Push Notifications,需要开发证书里包含了推送功能。

请求用户授权

一般在application(_:didFinishLaunchingWithOptions:) 中注册推送通知,需要在主线程中执行。

func registerForPushNotifications() {
  UNUserNotificationCenter.current() 
    .requestAuthorization(options: [.alert, .sound, .badge]) { granted, _ 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()
      }
  }
}

.options参数:

.badge:在图标右上角显示数字
.sound: 播放声音
.alert: 弹窗显示文本通知
.carPlay: 在CarPlay上显示通知
.provisional: 没有提醒的通知。不会有弹窗授权,但你的通知只会默默地显示在通知中心
.providesAppNotificationSettings: 表示该应用有自己的通知设置的用户界面
.criticalAlert: 忽略静音开关和请勿打扰。你需要从苹果那里获得一个特殊的权利来使用这个选项,因为它只用于非常特殊的使用情况。

处理APNS回调

在向APNS注册推送成功后,会返回当前设备上此APP对应的Device Token

  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)")
  }
  func application(
    _ application: UIApplication,
    didFailToRegisterForRemoteNotificationsWithError error: Error
  ) {
    print("Failed to register: \(error)")
  }
}

APNS推送消息时,用户点击消息后在以下代理方法中进行处理:

extension AppDelegate: UNUserNotificationCenterDelegate {
  func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    didReceive response: UNNotificationResponse,
    withCompletionHandler completionHandler: @escaping () -> Void
  ) {
    let userInfo = response.notification.request.content.userInfo
   // 处理推送消息
    completionHandler()
  }
}

使用xcode在模拟器上模拟通知

由于消息需要通过第三方服务器转发给APNS服务器,这里采用Xcode模拟发送通知,首先查看模拟器的device_identifier,点击Windows ▸ Devices and Simulators切换到Simulators选择当前的模拟器拷贝Identifier


创建一个名为first.apn的文件,内容如下:

{
  "aps": {
    "alert": "Breaking News!",
    "sound": "default",
    "link_url": "https://www.baidu.com"
  }
}

cdfirst.apn文件的目录下,输入指令xcrun simctl push device_identifier bundle_identifier first.apn,其中device_identifierbundle_identifier替换为刚刚获取的模拟器的device_identifier和项目的Bundle_identifier,例如如下所示:

这里Xcode利用模拟器的device_identifie结合Bundle_identifier来确定给哪个模拟器的哪个App发送消息,相当于上面提到的Device Token

模拟真机上推送

在真机上推送消息时,第三方服务器是需要苹果的推送证书和APNS服务器交互的,推送证书分为开发者推送证书和生产推送证书,同时有p12p8二种格式的,具体证书的申请流程不在此赘述。

App store中下载APNS Tool软件,软件打开如下:


选择Credentials,点击Request authotization申请授权,此时下面的CREDENTIALS会显示相关信息包括Device token等,拷贝下面的P8 key字符串,这其实就是p8证书的内容,利用拷贝的内容建立一个名为push.p8的推送证书文件(新建纯文本文件粘贴后修改文件后缀即可)。最后将Credentials页面的内容全部复制粘贴到Push页面上,顺便将APNs Server切换至Production,点击右上角的Send push即可收到推送。

要想在另外一台手机上收到推送,只需要输入另外一台手机的Device Token即可;同时测试推送的软件也可以使用MacPushNotifications软件。

第三方平台个推的实现

本文选取第三方个推作为介绍,其他平台诸如友盟,极光推送等使用方式大同小异,官方Demo地址官方视频讲解地址

SDK的集成

在集成SDK前需要去个推官网创建应用并上传证书拿到AppIdAppKeyAppSecret,直接下载官方SDK集成即可。

通过SDK注册推送

集成了SDK后一切操作都变得十分简单,首先是启动SDK,填入上面所说的AppIdAppSecretAppKey

    // [ GTSDK ]:使用APPID/APPKEY/APPSECRENT启动个推
    GeTuiSdk.start(withAppId: kGtAppId, appKey: kGtAppKey, appSecret: kGtAppSecret, delegate: self)

通过SDK注册远程推送通知,使用SDK后无需关注DeviceToken相关逻辑(SDK都帮忙做了),只需要关系消息回调即可。

GeTuiSdk.registerRemoteNotification([.alert, .badge, .sound])

个推消息回调

通过回调拿到个推消息。

  func geTuiSdkDidReceiveNotification(_ userInfo: [AnyHashable : Any], notificationCenter center: UNUserNotificationCenter?, response: UNNotificationResponse?, fetchCompletionHandler completionHandler: ((UIBackgroundFetchResult) -> Void)? = nil) {
    let msg = "[ TestDemo ] \(#function) \(userInfo)"
    homePage.logMsg(msg)
    // [ 参考代码,开发者注意根据实际需求自行修改 ]
    completionHandler?(.noData)
  }
   // 透传消息回调
  func geTuiSdkDidReceiveSlience(_ userInfo: [AnyHashable : Any], fromGetui: Bool, offLine: Bool, appId: String?, taskId: String?, msgId: String?, fetchCompletionHandler completionHandler: ((UIBackgroundFetchResult) -> Void)? = nil) {
    let msg = "[ TestDemo ] \(#function) fromGetui:\(fromGetui ? "个推消息" : "APNs消息") appId:\(appId ?? "") offLine:\(offLine ? "离线" : "在线") taskId:\(taskId ?? "") msgId:\(msgId ?? "") userInfo:\(userInfo)"
    homePage.logMsg(msg)
  }

在个推开发者平台上推送消息

在个推官网创建一个透传消息,填写通知内容,确认后发送:


image.png

总结

本文阐述了iOS推送的实现原理,其中如何获取DeviceToken最为重要,并通过相关推送App等辅助工具进行了推送的模拟,并介绍了第三方推送的使用(其他平台的使用大同小异),弄清了推送的原理后能更好的理解iOS的推送机制,通过APNS服务器推送保证了消息传递的准时性和统一性。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容

  • iOS中通知机制又叫消息机制,其包括两类:一类是本地通知;另一类是推送通知,也叫远程通知。两种通知在iOS中...
    七里汀阅读 2,097评论 3 2
  • 版权声明 本文翻译自:raywenderlich.com 原文作者: Jack Wu 译者: JMStack 转载...
    jmstack阅读 7,045评论 6 30
  • 总体内容1.推送通知的介绍2.本地通知3.远程通知4.极光推送的使用 一、推送通知的介绍 1.1、推送通知的作用:...
    IIronMan阅读 5,107评论 4 34
  • 级别: ★★☆☆☆标签:「iOS 本地推送」「iOS 远程推送」「iOS通知扩展」作者: dac_1033审校: ...
    QiShare阅读 7,661评论 7 32
  • 概述 iOS中的通知包括本地推送通知和远程推送通知,两者在iOS系统中都可以通过弹出横幅的形式来提醒用户,点击横幅...
    大成小栈阅读 1,764评论 0 2