Zhihao's Studio.

Match开发笔记 肆 极光推送接入指南(Swift版)

Word count: 1,620 / Reading time: 6 min
2018/09/20 Share

前言

在接入极光推送过程中,发现官网文档比较老旧了,而且使用的是OC版本,在上架Match 2.0的过程中,需要增加推送功能。于是就花了一些精力去研究,并最终改写得到了Swift版本的代码,这里写一个总结,希望能对想使用Swift接入极光推送的朋友们提供一些启发。

iOS推送机制和JPush的意义

APNs

iOS推送,最终只有一条官方渠道,那就是APNs。APNs通知是指通过向Apple APNs服务器发送通知,到达iOS设备,由iOS系统提供展现的推送。

极光推送的意义

一般开发者都是自己部署服务器,向APNs Server推送。极光推送,是在这中间增加了一步,即开发者自己部署的服务器向极光服务器推送,然后由极光服务器向APNs推送。

iOS和JPush的关系图(来源极光推送官网)

这样做有什么意义呢?极光认为带来了下列好处:

  1. 减少开发及维护成本:应用开发者不需要去开发维护自己的推送服务器与 APNs 对接。集成了 JPush iOS SDK 后不必自己维护更新 device token。通过 JPush 的 Web Portal 直接推送,也可以调用 JPush 的 HTTP 协议 API 来完成,开发工作量大大减少。
  2. 减少运营成本:极光推送支持一次推送,同时向 Android, iOS, WinPhone 三个平台。支持统一的 API 与推送界面。极光推送提供标签、别名绑定机制,以及提供了非常细分的用户分群方式,运营起来非常简单、直观。
  3. 提供应用内推送:除了使得 APNs 推送更简单,也另外提供应用内消息推送。这在类似于聊天的场景里很有必要。

接入前期准备

设置iOS消息推送证书

接入通知前,需要严格按照此文档配置相关证书。否则将会影响消息推送组件的正常使用。苹果开发最烦人的部分恐怕证书绝对算的上是一个了,关于推送证书的生成,这里推荐一个博客,可以参考。

iOS相比于安卓比较特殊,分为生产环境(上架版)和测试环境(开发版),最后导出极光所需要的.p12文件。导出.p12文件的坑也不少,推荐这篇博文,供参考。

最终在极光控制台上,分别将生产环境和开发环境的两个.p12文件上传,通过验证后,会出现下面截图的样子。

极光平台注册

在极光平台注册你的app,主要需要Bundle ID和开发者认证(企业营业执照)。注册完成后,获得重要信息:AppKey,这个码是后面一直需要使用的。

极光SDK的导入

导入极光SDK,既可以选择手动,也可以选择使用cocoapods。我使用的是cocoapods,原因很简单,因为如果不想要推送功能了,只需要在podfile里删掉pod ‘JPush’那行就行了。

导入后,一定记得要在XCode里勾上Application Target 的 Capabilities->Push Notifications 选项,否则将无法接受推送。

代码

添加bridge文件

因为极光推送是由OC写成,因此swift的项目里不能直接使用,需要借助桥接文件。只要在项目里新建一个OC文件,XCode就会创建一个xxx-Bridging-Header.h文件,在该文件中加入代码,就可以使用极光推送SDK了,啊真香!

1
2
3
4
5
#import "JPUSHService.h"
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#import <UserNotifications/UserNotifications.h>
#endif
#import <AdSupport/AdSupport.h>

添加Delegate

在AppDelegate.swift文件中,让AppDelegate遵从JPUSHRegisterDelegate,后面就可以使用相关代理方法了。

初始化相关代码

初始化APNs和JPush

初始化代码如下

1
2
3
4
5
6
7
8
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let entity = JPUSHRegisterEntity()
entity.types = 1 << 0 | 1 << 1 | 1 << 2
JPUSHService.register(forRemoteNotificationConfig: entity, delegate: self)
let advertisingId = ASIdentifierManager.shared().advertisingIdentifier.uuidString
JPUSHService.setup(withOption: launchOptions, appKey: "极光平台给分配的", channel: "App Store", apsForProduction: true, advertisingIdentifier: advertisingId)
}

上报device_token

实现JPUSHRegisterDelegate的代理方法,上报device_token。device_token主要是用来帮助推送定位到特定的设备使用的。

1
2
3
4
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
//注册 DeviceToken
JPUSHService.registerDeviceToken(deviceToken)
}

接收到消息的处理

这个部分为可选,主要是用来实现用户点开通知后的特定动作,比如跳转到特定页面。这就要跟后端开发人员商量好,将特定的消息通过通知的extra选项传递过来,然后手机端在做相应的跳转。

1
2
3
4
5
6
7
8
9
10
11
12
13
func jpushNotificationCenter(_ center: UNUserNotificationCenter!, didReceive response: UNNotificationResponse!, withCompletionHandler completionHandler: (() -> Void)!) {
let userInfo = response.notification.request.content.userInfo
let page : String = userInfo[AnyHashable("page")] as! String
if(page == "home") {
//跳转到home页面
}else if(page == "display"){
//跳转到特定页面
}
}

根据通知类型跳转到不同页面的效果:

清楚应用ICON角标

当用户点进应用之后,应用角标的通知数目应该清0,否则强迫症患者会被逼疯。

1
2
3
4
5
func applicationWillEnterForeground(_ application: UIApplication) {
application.applicationIconBadgeNumber = 0
application.cancelAllLocalNotifications()
}

设置Tags和alias

Tags是区分通知类型的,可以给不同的推送类型打Tag,比如我想接受新题目通知,不想接收点赞通知。而alias一般是有唯一性的,需要根据用户名或手机号这种好区分的东西来分辨。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
var outAlias:NSString?
var outTags:NSSet?
(outAlias, outTags) = self.analyseInput(alias as NSString!, tags: tags)
JPUSHService.setTags(outTags as! Set<String>, completion: { (a, b, c) in
}, seq: 1)
func analyseInput(_ alias:NSString!, tags:NSSet!)->(NSString?,NSSet?) {
var outAlias:NSString?
var outTags:NSSet?
if alias.length == 0 {
outAlias = nil
} else {
outAlias = alias
}
if tags.count == 0 {
outTags = nil
} else {
outTags = tags
var emptyStringCount = 0
tags.enumerateObjects({ (tag:Any, stop:UnsafeMutablePointer<ObjCBool>) -> Void in
if (tag as AnyObject).isEqual(to: "") {
emptyStringCount += 1
} else {
emptyStringCount = 0
stop.pointee = true
}
} as! (Any, UnsafeMutablePointer<ObjCBool>) -> Void)
if emptyStringCount == tags.count {
outAlias = nil
}
}
return (outAlias,outTags)
}

上架前的提醒

提交新版本或者初次上架之前,最后会遇到一个关于IDFA的选项。

您的 App 正在使用广告标识符 (IDFA)。您必须先提供关于 IDFA 的使用信息或将其从 App 中移除,然后再上传您的二进制文件。

记得要勾上是。否则会遇到麻烦。

参考

  1. APNs 推送原理及问题
  2. iOS SDK 集成指南
  3. ios 消息推送证书设置和整理(备忘)
  4. p12证书导出按钮为灰色的处理办法
  5. iOS提交审核:您的 App 正在使用广告标识符 (IDFA)
CATALOG
  1. 1. 前言
  2. 2. iOS推送机制和JPush的意义
    1. 2.1. APNs
    2. 2.2. 极光推送的意义
  3. 3. 接入前期准备
    1. 3.1. 设置iOS消息推送证书
    2. 3.2. 极光平台注册
    3. 3.3. 极光SDK的导入
  4. 4. 代码
    1. 4.1. 添加bridge文件
    2. 4.2. 添加Delegate
    3. 4.3. 初始化相关代码
      1. 4.3.1. 初始化APNs和JPush
      2. 4.3.2. 上报device_token
      3. 4.3.3. 接收到消息的处理
      4. 4.3.4. 清楚应用ICON角标
      5. 4.3.5. 设置Tags和alias
  5. 5. 上架前的提醒
  6. 6. 参考