Swift JPush极光推送通知和自定义消息

在开始之前,首先了解下自定义消息和通知的几点区别。

自定义消息和通知的区别

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

推荐阅读更多精彩内容

  • 版本记录 前言 前一篇已经对ios新特性进行了介绍,这一篇则对ios的SDK进行说明。1. 极光推送集成(一)2....
    刀客传奇阅读 1,269评论 0 1
  • 版本记录 前言   现在很多APP都有推送功能,其中极光推送就是很多APP的首选。我们最近的几个APP也是用的极光...
    刀客传奇阅读 8,333评论 0 8
  • 点击查看原文 Web SDK 开发手册 SDK 概述 网易云信 SDK 为 Web 应用提供一个完善的 IM 系统...
    layjoy阅读 13,590评论 0 15
  • 推送技术产生场景: --服务器端主动性: 客户端与服务器交互都是客户端主动的, 服务器一般不能主动与客户端进行数据...
    原军锋阅读 34,368评论 4 60
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,494评论 18 139