在开始之前,首先了解下自定义消息和通知的几点区别。
自定义消息和通知的区别
- 收到推送自定义消息时推送通知栏不显示
- 自定义消息推送不经过APNS,所以说跟推送证书没有关系
- 只有app在前台时才能收到自定义消息,未启动或者启动但处于后台时接收不到(解决了不想在app未启动时收到推送消息的问题)
SDK初始化
Appdelegate文件
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// 极光推送
if (UIDevice.current.systemVersion as NSString).floatValue >= 10.0 {
if #available(iOS 10.0, *) {
let entity = JPUSHRegisterEntity()
entity.types = NSInteger(UNAuthorizationOptions.alert.rawValue | UNAuthorizationOptions.badge.rawValue | UNAuthorizationOptions.sound.rawValue)
_ = JPUSHService.register(forRemoteNotificationConfig: entity, delegate: self)
} else {
// Fallback on earlier versions
}
} else if (UIDevice.current.systemVersion as NSString).floatValue >= 8.0 {
//可以添加自定义categories
JPUSHService.register(forRemoteNotificationTypes: UIUserNotificationType.badge.rawValue | UIUserNotificationType.sound.rawValue | UIUserNotificationType.alert.rawValue, categories: nil)
} else {
//categories 必须为nil
JPUSHService.register(forRemoteNotificationTypes: UIUserNotificationType.badge.rawValue | UIUserNotificationType.sound.rawValue | UIUserNotificationType.alert.rawValue, categories: nil)
}
var isJpushProduction: Bool
#if DEBUG
isJpushProduction = false
#else
isJpushProduction = true
#endif
JPUSHService.setup(withOption: launchOptions, appKey: JPUSHService_appKey, channel: "Publish channel", apsForProduction: isJpushProduction, advertisingIdentifier: nil)
return true
}
通知(极光远程推送)
调用此 API 来取得应用程序对应的 RegistrationID。 只有当应用程序成功注册到 JPush 的服务器时才返回对应的值,否则返回空字符串。
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
JPUSHService.registerDeviceToken(deviceToken)
/**
completionHandler用于处理设置返回结果
resCode返回的结果状态码
registrationID返回registrationID
*/
JPUSHService.registrationIDCompletionHandler { (resCode, registrationID) in
print("resCode--", resCode, " registrationID---", registrationID ?? "没有")
}
}
注册失败回调方法
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("didFailToRegisterForRemoteNotificationsWithError----", error)
}
iOS10以下的系统版本,收到本地通知(LocalNotification)时调用
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
let userInfo = notification.userInfo;
print("userInfo-------", userInfo ?? ["":""])
}
基于iOS10以下iOS 7 及以上的系统版本,收到远程通知(RemoteNotification)时调用
private func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
JPUSHService.handleRemoteNotification(userInfo)
// 收到远程通知后的处理
handleTheRemoteNotification(userInfo: userInfo as NSDictionary)
completionHandler(UIBackgroundFetchResult.newData)
}
在iOS 10出来后,极光推出了下面的两个新方法来替代了以上的两个方法。
iOS10及以上系统版本,app在后台(1、app在后台运行 2、锁屏状态 3、app关闭时)收到通知并且当用户点击通知栏上的消息时调用
@available(iOS 10.0, *)
func jpushNotificationCenter(_ center: UNUserNotificationCenter!, didReceive response: UNNotificationResponse!, withCompletionHandler completionHandler: (() -> Void)!) {
let userInfo = response.notification.request.content.userInfo
if response.notification.request.trigger?.isKind(of: UNPushNotificationTrigger.classForCoder()) == true {
JPUSHService.handleRemoteNotification(userInfo)
print("iOS10后台收到通知(当用户点击通知栏的时候)...")
// 收到远程通知后的处理
handleTheRemoteNotification(userInfo: userInfo as NSDictionary)
} else {
print("----本地通知")
}
completionHandler() // 系统要求执行这个方法
}
iOS10及以上系统版本,app处于前台时接收到通知时调用
@available(iOS 10.0, *)
func jpushNotificationCenter(_ center: UNUserNotificationCenter!, willPresent notification: UNNotification!, withCompletionHandler completionHandler: ((Int) -> Void)!) {
let userInfo = notification.request.content.userInfo
if notification.request.trigger?.isKind(of: UNPushNotificationTrigger.classForCoder()) == true {
JPUSHService.handleRemoteNotification(userInfo)
print("iOS10 前台收到远程通知...")
// 收到远程通知后的处理
handleTheRemoteNotification(userInfo: userInfo as NSDictionary)
} else {
print("本地通知...")
}
let tempPresentationOptions = UNNotificationPresentationOptions.alert.rawValue | UNNotificationPresentationOptions.sound.rawValue | UNNotificationPresentationOptions.badge.rawValue
completionHandler(Int(tempPresentationOptions)) // 需要执行这个方法,选择是否提醒用户,有Badge、Sound、Alert三种类型可以选择设置
}
自定义方法,用于收到远程通知后的一些处理操作,比如取值以及页面的跳转等等
func handleTheRemoteNotification(userInfo: NSDictionary) {
let aps = userInfo["aps"] as? NSDictionary // 取得 APNs 标准信息内容
let content = aps?["alert"] as? String ?? "" // 推送显示的内容
let customizeField = aps?["customizeExtras"] as? String ?? "" // 服务端中Extras字段,key是自己定义的
let ctrlAlert = UIAlertController(title: "提醒", message: content, preferredStyle: UIAlertControllerStyle.alert)
let confirmAction = UIAlertAction(title: "确定", style: .default){ (action) in
UIApplication.shared.applicationIconBadgeNumber -= 1
// 所需业务逻辑处理。。。
}
let cancelAction = UIAlertAction(title: "取消", style: .default) { (action) in
UIApplication.shared.applicationIconBadgeNumber -= 1
// 不作处理
}
ctrlAlert.addAction(cancelAction)
ctrlAlert.addAction(confirmAction)
let rootVC = UIApplication.shared.keyWindow?.rootViewController
}
通知(本地推送)
对于一些业务需求,比如闹铃或者日历的一些提醒事件等,自己推送消息,实现推送通知的效果。
func pushLocalNotification() {
let notification = UILocalNotification()
if #available(iOS 8.2, *) {
notification.alertTitle = "小蜗牛"
} else {
// Fallback on earlier versions
}
notification.alertBody = "快来玩啊~"
notification.userInfo = ["name": "Tony", "gender": "man"]
UIApplication.shared.presentLocalNotificationNow(notification)
}
自定义消息
功能说明:只有在前端运行的时候才能收到自定义消息的推送。
从jpush服务器获取用户推送的自定义消息内容和标题以及附加字段等。
这些内容是和后台的同学们协商好的,并且由他们来写好向极光推送的相应服务。
获取iOS的推送内容需要在appDelegate类中注册通知并实现回调方法。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// 极光推送,接收自定义消息
let defaultCenter = NotificationCenter.default
defaultCenter.addObserver(self, selector: #selector(networkDidReceiveMessage(notification:)), name: NSNotification.Name.jpfNetworkDidReceiveMessage, object: nil)
return true
}
回调方法
// 接收自定义消息
func networkDidReceiveMessage(notification:NSNotification) {
let userInfo: NSDictionary = notification.userInfo! as NSDictionary
print("自定义消息---",userInfo)
// 业务逻辑处理。。。
}
标签与别名
别名 alias
为安装了应用程序的用户,取个别名来标识。以后给该用户 Push 消息时,就可以用此别名来指定。
每个用户只能指定一个别名。
同一个应用程序内,对不同的用户,建议取不同的别名。这样,尽可能根据别名来唯一确定用户。
系统不限定一个别名只能指定一个用户。如果一个别名被指定到了多个用户,当给指定这个别名发消息时,服务器端API会同时给这多个用户发送消息。
举例:在一个用户要登录的游戏中,可能设置别名为 userid。游戏运营时,发现该用户 3 天没有玩游戏了,则根据 userid 调用服务器端API发通知到客户端提醒用户。
标签 tag
为安装了应用程序的用户,打上标签。其目的主要是方便开发者根据标签,来批量下发 Push 消息。
可为每个用户打多个标签。
举例: game, old_page, women
别名与标签的设置
因为别名和标签可以重复设置,所以我把它放在了登录方法中。
func login() {
//极光推送 注册别名
let alias = String(format: "%d", userId)
JPUSHService.setTags(["lowbeer","doubeer"], aliasInbackground: alias)
}
然后在退出登录时注销别名和标签,避免在多个设备上登录后,通过别名发送通知时,多个设备都会收到的情况。
// 退出登录
func logout() {
// 注销推送别名和标签
JPUSHService.setTags([], aliasInbackground: "")
}
参数说明
alias
- nil 此次调用不设置此值。
- 空字符串 ("")表示取消之前的设置。
- 每次调用设置有效的别名,覆盖之前的设置。
- 有效的别名组成:字母(区分大小写)、数字、下划线、汉字,特殊- 字符(v2.1.9支持)@!#$&*+=.|。
- 限制:alias 命名长度限制为 40 字节。(判断长度需采用UTF-8编码)
tags
- nil 此次调用不设置此值。
- 空集合([NSSet set])表示取消之前的设置。
- 集合成员类型要求为String类型
- 每次调用至少设置一个 tag,覆盖之前的设置,不是新增。
- 有效的标签组成:字母(区分大小写)、数字、下划线、汉字,特殊字符(v2.1.9支持)@!#$&*+=.|。
- 限制:每个 tag 命名长度限制为 40 字节,最多支持设置 1000 个 tag,但总长度不得超过7K字节。(判断长度需采用UTF-8编码)
单个设备最多支持设置 1000 个 tag。App 全局 tag 数量无限制。
小结
在推送测试时如果接收不到通知,不要着急,不要悲伤,深呼吸,淡定~~~
- 要检查好项目的开发和生产证书是否配置正确,并上传到了极光应用后台,并保证证书没有过期。参考SDK集成指南 和 证书设置指南
- 项目Target的Push Notifications开关是否打开。
- 卸载应用重新安装。我有次第一次收到了,但是后边却无论如何都接收不到了,然后拿着RegId和MsgId问了下极光的技术,他们告诉我:
1、apple认为token失效了
2、苹果建议程序每次启动的时候从 apns 获取 devicetoken
重新获取一次新的token,测试时,简单的操作就是卸载重装
---该问题可以看下这个苹果APNs’ device token特性和过期更新。 - 在极光官网最下方有技术交流群,可以加群找技术咨询解决。