iOS推送通知

文章目录

  • 一、推送通知的介绍
    • 1. 简介
    • 2. 通知的分类
  • 二、本地通知
    • 1. 本地通知的介绍
    • 2. 实现本地通知
    • 3. 监听本地通知的点击
  • 三、远程通知
    • 1. 什么是远程通知
    • 2. 为什么需要远程通知
    • 3. 远程通知的原理
    • 4. 如何做远程通知
    • 5. 远程通知证书配置
    • 6. 获取远程推送要用的 `DeviceToken`
    • 7. 测试方式: 远程通知
    • 8. 监听远程通知的点击事件
  • 四、极光推送
    • 1. [极光推送 iOS 文档](https://docs.jiguang.cn/jpush/client/iOS/ios_sdk/)
    • 2. 在极光推送平台创建一个应用
    • 3. [iOS SDK 集成](https://docs.jiguang.cn/jpush/client/iOS/ios_guide_new/),官网讲解的很详细,简单导入 极光推送的iOS SDK
    • 4. 测试项目的 `Bundle Identifier`要与我们上面创建证书的 `Bundle ID` 保持一致,并且打开如下图所示
    • 5. 在 `AppDelegate.m` 导入极光推送的相应代码
    • 6. 在极光推送后台进行推送,[发送通知](https://www.jiguang.cn/console/push/#/push/app/61a37ea3be0141df677f2da6/setting/platform/ios)

一、推送通知的介绍

1. 简介

推送通知,也被叫做远程通知,是在iOS 3.0以后被引入的功能。是当程序没有启动或不在前台运行时,告诉用户有新消息的一种途径,是从外部服务器发送到应用程序上的。
一般说来,当要显示消息或下载数据的时候,通知是由远程服务器(程序的提供者)发送,然后通过苹果的推送通知服务(Apple Push Notification Service,简称APNS)推送到设备的程序上。

2. 通知的分类

1、本地通知
概念:由APP本身给应用程序推送消息,不需要服务器的支持
常见场景:app本地定时提醒
注意:不是非常常用.

2、远程通知
概念:由服务器推送消息给用户,需要服务器的支持
常见场景:APP关闭后提醒的通知消息
注意:非常常用.但是如果仅仅是给用户提醒,客户端(你)做的事情就非常简单.

3、推送通知的呈现样式

  • 在屏幕顶部显示一块横幅
  • 锁屏界面也可以显示

提示:收到通知还可以做如下操作

  • 收到通知时,同时播放音效.(比如支付宝或者微信收账语音提示)
  • 收到通知时,改变APP图标上的数字(app图标上的消息数量)

二、本地通知

1. 本地通知的介绍

  1. 直接由应用程序(程序中写入对应代码)给用户发出通知

  2. 本地通知需要用到一个重要的类: UNUserNotificationCenter

  3. 本地通知的实现步骤:
    (1)创建本地通知
    (2)设置本地通知要发出的内容等信息

    • 发出时间
    • 发出内容
    • 播放的音效

    (3)调度本地通知

2. 实现本地通知

(1)、注册通知

  • 通常是在 AppDelegatedidFinishLaunchingWithOptions 中进行注册,代码如下
let center = UNUserNotificationCenter.current()
        center.delegate = self
        center.requestAuthorization(options: [.alert, .badge, .sound]) { granted, _ in
            if granted == true {
                print("允许通知")
            } else {
                print("不允许通知")
            }
        }

(2)、创建并且发出通知

public func send(_ body: String) {
        let content = UNMutableNotificationContent()
        // 通知的内容
        content.title = "门禁Demo本地消息"
        content.subtitle = "iBeacon"
        content.body = body
        content.sound = UNNotificationSound.default
        // 间隔多久推送一次
        // UNTimeIntervalNotificationTrigger   延时推送
        // UNCalendarNotificationTrigger       定时推送
        // UNLocationNotificationTrigger       位置变化推送
        
        // 当前时间之后的0.1s后推送一次(如果重复的话时间要大于等于60s)
        let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 0.1, repeats: false)
        // 消息标识
        let id = "req_identifier" + UUID().uuidString
        // 建立通知请求
        let request = UNNotificationRequest.init(identifier: id, content: content, trigger: trigger)
        // 将建立的通知请求添加到通知中心
        UNUserNotificationCenter.current().add(request)
    }

总体属性展示

@NSCopying open var badge: NSNumber? // 应用程序右上角的数字
open var body: String // 提示信息
@NSCopying open var sound: UNNotificationSound? // 设置通知发出时音效
open var subtitle: String // 通知副标题
open var title: String // 通知中心的标题
open var userInfo: [AnyHashable : Any] // 额外信息

(3)、移除通知

       // 移除所有的通知
      UNUserNotificationCenter.current().removeAllPendingNotificationRequests()

       // 移除某个通知
       UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [id])

3. 监听本地通知的点击

(1)、为什么要监听本地通知的点击?
不管应用程序出于后台还是被杀死,点击通知都可以打开应用程序。
当用点击通知时,进入到某一个固定界面,需要监听用户点击了通知

(2)、监听本地通知的点击,应用程序分很多种状态

  • 在前台:如果在前台不需要进行页面跳转
  • 在后台:点击应用时进行页面的跳转
  • 被杀死:点击应用打开应用时,进行页面的跳转

应用程序在前台或者后台时的代码如下

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        print("本地通知的点击")
        /**
         UIApplicationStateActive, 前台
         UIApplicationStateInactive, 进入前台
         UIApplicationStateBackground 在后台
         */
        if application.applicationState == .active {
            return // 前台情况下 不做操作
        }
        // 进行页面的跳转
    }

应用程序被杀死时的情况下不会走上面的代码,但是不管是在任何情况下都会走下面的代码,通过launchOptionskey来做出各种判断,代码如下

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        // 判断是否是通过点击通知打开了应用程序
        if let key = launchOptions?[UIApplication.LaunchOptionsKey.localNotification] {
            // 在app杀死的情况下,本地通知的所走的地方
        }
}

提示:对应 launchOptions 的其他常用 key 如下

  • 对应的是启动应用程序的的远程通知信息userInfo(NSDictionary)
    UIApplicationLaunchOptionsRemoteNotificationKey
  • 对应的是为启动应用程序的的本地通知对象(UILocalNotification)
    UIApplicationLaunchOptionsLocalNotificationKey
  • 对应的对象为启动URL(NSURL)
    UIApplicationLaunchOptionsURLKey
  • 从点击3D Touch iCon启动,对应的是点击的iCon的信息。
    UIApplicationLaunchOptionsShortcutItemKey
    * 有关蓝牙的操作
    UIApplicationLaunchOptionsBluetoothPeripheralsKey
    UIApplicationLaunchOptionsBluetoothCentralsKey
    * 对应启动的源应用程序的bundle ID (NSString)
    UIApplicationLaunchOptionsSourceApplicationKey

三、远程通知

1. 什么是远程通知

概念:由服务器发送消息给用户弹出消息的通知(需要联网)
远程推送服务,又称为 APNSApple Push Notification Services
APNS通知:是指通过向 Apple APNs 服务器发送通知,到达 iOS 设备,由 iOS 系统提供展现的推送。用户可以通过 IOS 系统的 “设置” >> “通知” 进行设置,开启或者关闭某一个 App 的推送能力。

2. 为什么需要远程通知

例子:APP搞活动,促销活动或者商品降价,想告知用户.但是该用户不经常打开APP。 如何通知该用户有最新的活动呢?
传统方式:只有用户打开了APP客户端,客户端向服务器请求是否有最新的活动,才能在APP中告知用户活动.
局限性:只要用户关闭了APP,就无法跟APP的服务器沟通,无法从服务器上获得最新的数据内容
远程通知的好处:不管用户打开还是关闭APP,只要联网了,都能接收到服务器推送的远程通知

3. 远程通知的原理

1、原理图

2、为什么服务器不直接推消息给用户

  • 在通常情况下服务器端是不能主动向客户端推消息的
  • 如果想服务器端给客户端推消息,必须建立长连接
  • 客户端在处于后台时(app杀死的情况下)不能和服务器端建立长连接
    请添加图片描述

3、为什么苹果服务器可以推消息给用户?
所有的苹果设备,在联网状态下,都会与苹果的服务器建立长连接
苹果建立长连接的作用: 时间校准、系统升级提示、查找我的iPhone、远程通知 等等
常见疑惑:
苹果在推送消息时,如何准确的推送给某一个用户,并且知道是哪一个APP ?
在服务器把消息给苹果的APNs服务器时,必须告知苹果DeviceToken
DeviceToken是由用户手机的UDID和应用程序的BundleID共同生成的
通过DeviceToken可以找到唯一手机中的唯一应用程序

4、完整的流程图
iOS推送通知_第1张图片

4. 如何做远程通知

  • 首先,BundleID对应的App ID必须是明确的(特殊功能)
  • 该APPID必须配置两个证书
    • **开发证书:**用于调试远程推送
    • **发布证书:**用于发布后给用户推送消息
  • 根据上面的App ID重新配置描述文件
  • 安装对应的证书,即可开始测试远程推送

5. 远程通知证书配置

1、我们先创建一个 CSR 文件(又叫做:证书签名请求文件)(下面会用到,它是用来绑定电脑的)

  • 找到 Launchpad 里面的 钥匙串访问
    iOS推送通知_第2张图片

  • 打开钥匙串访问->证书助理->从证书机构颁请求证书
    iOS推送通知_第3张图片

  • 出现如下界面,选择存储到磁盘,点击继续
    iOS推送通知_第4张图片

*选择存储到待会好找的地方(比如:桌面,自己建的文件夹等等),存储
iOS推送通知_第5张图片

2、在 Identifiers里面创建一个明确的App ID

在这里插入图片描述

iOS推送通知_第6张图片

iOS推送通知_第7张图片

iOS推送通知_第8张图片

  • 提示:Bundle ID 一定要填写明确的iOS推送通知_第9张图片
    点击注册
    iOS推送通知_第10张图片

3、为(2)中创建的App ID 配置推送 开发证书(测试证书)与推送发布证书

点击进入编辑页面
在这里插入图片描述

在这里插入图片描述

iOS推送通知_第11张图片

iOS推送通知_第12张图片

iOS推送通知_第13张图片

在这里插入图片描述

在这里插入图片描述

4、配置描述文件
* iOS证书分2种,1种是开发证书,用来给你(开发人员)做真机测试的;1种是发布证书,发布证书又分发布到app store的(这里不提及)和发布测试的ad hoc证书。

iOS推送通知_第14张图片

iOS推送通知_第15张图片

提示:描述文件下载完后记得双击运行一下

6. 获取远程推送要用的 DeviceToken

1、工程的 Bundle identifier 要与我们上面设置的 App ID 保持一致,并且添加Push Notification选项
iOS推送通知_第16张图片

2、在苹果的APNs服务器注册,以获取DeviceToken

  • 通常在 AppDelegate 里面的 didFinishLaunchingWithOptions 中添加如下代码进行注册
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        // 1.向用户请求可以给用户推送消息
        let center = UNUserNotificationCenter.current()
        center.delegate = self
        center.requestAuthorization(options: [.alert, .badge, .sound]) { granted, _ in
            if granted == true {
                print("允许通知")
            } else {
                print("不允许通知")
            }
        }
        // 2.注册远程通知(拿到用户的DeviceToken)
        application.registerForRemoteNotifications()
		return true
}
  • 注册之后在另外一个代理方法中,拿到DeviceToken
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        // 将用户的用户名和deviceToken发送给服务器,让服务器进行保存备份即可
        print(deviceToken as NSData)
        // 例如:
        // 其中我们服务器要保存的 deviceToken 是不包括两边的尖括号的
    }

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print(error.localizedDescription)
    }

注意

  • 获取到的 deviceToken 发送给服务器,让服务器进行保存备份即可
  • 我们服务器要保存的 deviceToken 是不包括两边的尖括号的

7. 测试方式: 远程通知

(1)、使用一个第三方的Mac程序来测试:PushMeBaby,并删除里面的资源,把我们自己推送的开发证书与发布证书模仿其命名改名并拖进去

iOS推送通知_第17张图片

(2)、修改 PushMeBaby里面的ApplicationDelegate.m,把 self.deviceToken 修改为我们上面 3.6 中运行后拿到的 DeviceToken,切记 DeviceToken 不包含左右尖括号

iOS推送通知_第18张图片

(3)、做完操作,运行PushMeBaby,选择相应的内容

iOS推送通知_第19张图片

备注
还有其他APP 同样可以实现,例如:PushMan、SmartPush
可以实现在电脑上模拟APNS推送

8. 监听远程通知的点击事件

其实和本地通知的监听是一样的,一种是在前台和后台的监听,一种是在app杀死情况下的监听,代码如下

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        LocalNotification.shared.setNotifiAuth()
         // 2.注册远程通知(拿到用户的DeviceToken)
         application.registerForRemoteNotifications()
         // 判断是否是通过点击通知打开了应用程序
        if let key = launchOptions?[UIApplication.LaunchOptionsKey.localNotification] {
            // 在app杀死的情况下,本地通知的所走的地方
        }
        return true
}

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        // 将用户的用户名和deviceToken发送给服务器,让服务器进行保存备份即可
        print(deviceToken)
        // 例如:
        // 其中我们服务器要保存的 deviceToken 是不包括两边的尖括号的
    }
    
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print(error.localizedDescription)
    }
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        print("本地通知的点击")
        /**
         UIApplicationStateActive, 前台
         UIApplicationStateInactive, 进入前台
         UIApplicationStateBackground 在后台
         */
        if application.applicationState == .active {
            return // 前台情况下 不做操作
        }
        // 进行页面的跳转
    }
    
class LocalNotification: NSObject {
    
    /// 单例
    public static let shared = LocalNotification()
    
    public func setNotifiAuth() {
        let center = UNUserNotificationCenter.current()
        center.delegate = self
        center.requestAuthorization(options: [.alert, .badge, .sound]) { granted, _ in
            if granted == true {
                print("允许通知")
            } else {
                print("不允许通知")
            }
        }
    }
    
    public func send(_ body: String) {
        let content = UNMutableNotificationContent()
        // 通知的内容
        content.title = "Demo本地消息"
        content.subtitle = "iBeacon"
        content.body = body
        content.sound = UNNotificationSound.default
        // 间隔多久推送一次
        // UNTimeIntervalNotificationTrigger   延时推送
        // UNCalendarNotificationTrigger       定时推送
        // UNLocationNotificationTrigger       位置变化推送
        
        // 当前时间之后的0.1s后推送一次(如果重复的话时间要大于等于60s)
        let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 0.1, repeats: false)
        // 消息标识
        let id = "req_identifier" + UUID().uuidString
        // 建立通知请求
        let request = UNNotificationRequest.init(identifier: id, content: content, trigger: trigger)
        // 将建立的通知请求添加到通知中心
        UNUserNotificationCenter.current().add(request)
    }
}

@available(iOS 13.0.0, *)
extension LocalNotification: UNUserNotificationCenterDelegate {
    // 前台显示弹窗
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions {
        return .alert
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        
    }
}

提示:我们可以使用新的监听用户点击远程通知的方法,如下:(包含上面的两种监听方式)

 /*
 此方法是新的用于响应远程推送通知的方法
  1.如果应用程序在后台,则通知到,点击查看,该方法自动执行
  2.如果应用程序在前台,则通知到,该方法自动执行
  3.如果应用程序被关闭,则通知到,点击查看,先执行didFinish方法,再执行该方法
  4.可以开启后台刷新数据的功能
  	step1:点击target-->Capabilities-->Background Modes-->Remote Notification勾上
  	step2:在给APNs服务器发送的要推送的信息中,添加一组字符串如:
  	{"aps":{"content-available":"999","alert":"bbbbb.","badge":1}}
  	其中content-availabel就是为了配合后台刷新而添加的内容,999可以随意定义
*/
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        print("本地通知的点击")
        /**
         UIApplicationStateActive, 前台
         UIApplicationStateInactive, 进入前台
         UIApplicationStateBackground 在后台
         */
        if application.applicationState == .active {
            return // 前台情况下 不做操作
        }
        // 进行页面的跳转
        completionHandler(.newData);
    }

四、极光推送

1. 极光推送 iOS 文档

APNs 通知:是指通过向 Apple APNs 服务器发送通知,到达 iOS 设备,由 iOS 系统提供展现的推送。用户可以通过 IOS 系统的 “设置” >> “通知” 进行设置,开启或者关闭某一个 App 的推送能力。
JPush iOS SDK 不负责 APNs 通知的展现,只是向 JPush 服务器端上传 Device Token 信息,JPush 服务器端代理开发者向 Apple APNs 推送通知。

APNs 通知与应用内消息对比

APNS 应用内消息
推送原则 由 JPush 服务器发送至 APNS 服务器,再下发到手机。 由 JPush 直接下发,每次推送都会尝试发送,如果用户在线则立即收到。否则保存为离线。
离线消息 离线消息由 APNS 服务器缓存按照 Apple 的逻辑处理。 用户不在线 JPush server 会保存离线消息,时长默认保留一天。离线消息保留 5 条。
推送与证书环境 应用证书和推送指定的 iOS 环境匹配才可以收到。 自定义消息与 APNS 证书环境无关。
接收方式 应用退出,后台以及打开状态都能收到 APNS。 需要应用打开,与 JPush 建立连接才能收到。
展示效果 如果应用后台或退出,会有系统的 APNS 提醒。如果应用处于打开状态,则不展示,iOS 10 开始可实现前台展示。 非 APNS,默认不展示。可通过获取接口自行编码处理。
处理函数 Apple 提供的接口:didReceiveRemoteNotification JPush 提供的接口:networkDidReceiveMessage

2. 在极光推送平台创建一个应用

iOS推送通知_第20张图片

iOS推送通知_第21张图片

iOS推送通知_第22张图片

3. iOS SDK 集成,官网讲解的很详细,简单导入 极光推送的iOS SDK

4. 测试项目的 Bundle Identifier要与我们上面创建证书的 Bundle ID 保持一致,并且打开如下图所示

iOS推送通知_第23张图片

静默推送(silent_push):如果只携带content-available: 1,不携带任何badge,sound 和消息内容等参数,则可以不打扰用户的情况下进行内容更新等操作即为“Silent Remote Notifications”。

5. 在 AppDelegate.m 导入极光推送的相应代码

这里说明几个参数

  • appKey:选择极光控制台的应用 ,点击“设置”获取其 appkey 值。请确保应用内配置的 appkey 与极光控制台上创建应用后生成的 appkey 一致。
  • channel:指明应用程序包的下载渠道,为方便分渠道统计,具体值由你自行定义,如:App Store。
  • apsForProduction:
    • 1.3.1 版本新增,用于标识当前应用所使用的 APNs 证书环境。
    • 0(默认值)表示采用的是开发证书,1 表示采用生产证书发布应用。
    • 注:此字段的值要与 Build Settings 的 Code Signing 配置的证书环境一致。
  • advertisingIdentifier:详见 关于 IDFA。

6. 在极光推送后台进行推送,发送通知

iOS推送通知_第24张图片

iOS推送通知_第25张图片

在手机上我们就能收到推送通知了

你可能感兴趣的:(iOS开发,ios,macos)