想要推送消息就需要添加
import UserNotifications包
申请权限
UNUserNotificationCenter.current()//获取UNUserNotificationCenter类的单例
requestAuthorization
requestAuthorization申请权限:
badge:角标
sound:声音
alert:横幅
carPlay:车载环境
criticalAlert:紧急通知
announcement:让耳机读取通知内容
无论用户是勿扰或静音状态都能通知 使用紧急通知需要给苹果写申请
providesAppNotificaitonSettings:在系统setting界面提供一个蓝色的app自定义选项
provisional:临时
发送一个不打断的notificaiton 的临时通知中心
//发起权限申请
UNUserNotificationCenter.current().requestAuthorization(options: [.alert,.sound,.badge], completionHandler: {
(granted, error) in
if let error = error{
print(error.localizedDescription)
}
if granted{
print("用户已经授权")
} else {
print("通知服务器不要再发送了")
}
});
这个授权通知只发送一次,除非删除app
如果用户第一次拒绝了通知,用户自己也可以通过
自己打开权限
getNotificationSettings
会返回settings参数给闭包
options: [.alert,.sound,.badge]
中的.alert是指lock screen,notification center,banners三个东西一一对应于settings.lockScreenSetting,settings.notificationCenterSetting,settings.alertSetting
每次发送通知之前都要获取一下状态再发送
UNNotificationSettings分三块
Getting authorization status:获取授权状态
getting device specific settings:获取设备通知配置
getting interface setting:获取通知界面配置
app只有在后台时才会接收到这个通知
当一个活动开始时activity kit 会从apple push notification service(apn)获得一个push token
push token对于请求的每一个活动是唯一的,这也是为什么你的app需要发送这个token给你的service在他发送push之前,无论如何你的service都必须发送token给apn,最后apn会将payload发送给设备,这将唤醒你的小控件来显示UI
modul
当权限被用户拒绝时,用户点击了发送通知,我们需要引导用户进入设置界面打开权限
DispatchQueue.main.async {
let alert = UIAlertController(title: "alertViewTitle", message: "o", preferredStyle: .alert)
let cancleAction = UIAlertAction(title: "cancle", style: .cancel, handler: nil)
//引导user进入setting界面
let startingAction = UIAlertAction(title: "setting", style: .default) { action in
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
}
alert.addAction(cancleAction)
alert.addAction(startingAction)
self.present(alert,animated: true, completion: nil)
}
在通知下面添加按钮
app启动的时候就需要注册按钮,按钮是由整个App控制
专业术语
APNs
apple push norification service
device token
唯一标识客户设备(由APNs生成),可以看作寄快递的地址
需要先向apns注册app,苹果才会将用户的
我们需要先获取到用户的device token、,但是我们并不是直接找用户请求devic token而是找苹果,一开始要跟apns推送服务器连接起来,先向apns注册app,注册好后apns会将包含用户设备和包含特指app的信息组合成deviceToken发给app,因为deviceToken
然后将这个device token发送给苹果(APNs)告诉苹果我这个app需要给这个device token的用户发送远程通知
用户会将自己的device token发送给苹果(APNs)
device token会在app重装后更新
证书和令牌
主要用于服务器和APNs通信
服务器个给apns发送信息的时候苹果想要链接是安全的链接,希望推送消息不要中途被拦截,篡改,希望app做一些安全处理,就可以做两种处理:
TLS Certificate
服务器(APNs)和客户端(公司服务器 provide serveer)通过交换证书来建立链接,这些证书包含了用于加密和解密通信的公钥和私钥。
这个有一些限制 比如说每年要更新一次
Authentication Token( token base)
用户或应用程序提供一组凭据一般是用户名和密码,认证服务器就会验证这些凭据然后办法一个认证令牌,这个令牌可以在后续验证中使用无需再输入凭据
优点:只需输入一次就可以在多个网站使用,例如苹果网站只需要输入一次用户名和密码就可以在其所有旗下网站浏览
缺点:在provide server上也就是客户端需要每20-60分钟更新一次
隐式推送
当包含.provisional的时候就为隐式推送 此时并不会弹出弹框询问用户权限,而是直接拥有权限,但是隐式推送只会显示在通知中心或者锁屏界面,并不会显示在主界面。
.requestAuthorization(options: [.provisional]
命令行转换音频
/System/Library/Sounds/Submarine.aiff …/Desktop/sub.caf -d ima4 -f caff -v
相关API
UNMutableNotificationContent
notification的内容
content.categoryIdentifier = “NOTIFICATION”//添加该notification的categoryIndentifier//主要决定了添加那个类型的button
content.badge = 1//忘了这里为什么为1了
content.userInfo = [“REQUEST_USER_ID”:88]
content.threadIdentifier = “NOTIFICATION”//主要给通知分组,当有多个不同的notification发来时会被折叠在两个notification里面如下图:
2more这个东西叫做通知概要(summary)//但是感觉这两个被弃用了啊,目前看起来不启用
content.summaryArgument = “消息”
content.summaryArgumentCount = 1//默认是1,主要表示消息次数*n 这里是1
//content.attachmzents//附件或视频
openURL
用于打开某个链接或者应用程序
在使用 canOpenURL: 和 openURL: 方法时,需要在应用的 Info.plist 文件中添加相关的白名单配置,以声明可以打开的 URL Scheme。
远程通知和本地通知的区别
本地通知是本地code写死了
远程通知可以不需要本地更新软件,就可以实时的从服务器推送通知
远程通知:
并不是app远程服务器直接发送给用户设备,而是远程服务器先把相关的推送内容(notification content,证书,目标用户的device token)发送给苹果(APNs),等APNs确认这些信息无误之后给指定的用户发送推送,内容格式使用的json格式
远程通知
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
//添加notification的代理
UNUserNotificationCenter.current().delegate = self
//找苹果注册我们这个app,苹果就会返回当前使用我们app的一个deviceToken,可以定位到这个具体的app在谁的手上
UIApplication.shared.registerForRemoteNotifications()
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("申请成功:\(deviceToken.map{ String(format: "%02.2hhx", $0)}.joined())")//获取到deviceToken,将deviceToken转化为16进制的字符串,可以用于模拟发送remoteNotification
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("申请失败:\(error.localizedDescription)")
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
当收到推送通知时这个方法会被调用。
但是如果payload并不包含”content-available": 1
就只能在app为前台时被调用,因为系统默认会处理通知而不会唤醒应用程序。只有当推送通知包含特定的内容以提示系统唤醒应用程序进行数据获取或执行其他任务时(例如使用了"content-available": 1),才可能在后台调用
添加pushKit
var window: UIWindow?
var pushRegistry: PKPushRegistry!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UNUserNotificationCenter.current().delegate = self;
// 设置 PushKit
pushRegistry = PKPushRegistry(queue: nil)
pushRegistry.delegate = self
pushRegistry.desiredPushTypes = [.voIP]
return true
}
并且在
远程推送
首先需要apps在启动时通过registerForRemoteNotifications
向APNs注册app,
调用 registerForRemoteNotifications() 方法时,实际上是告诉 iOS 操作系统,该应用希望接收远程通知,当IOS系统接受到这个请求时会向APNs发送请求注册,这个请求包含了应用的标识和设备的信息(例如APP ID(BundleID,应用的唯一标识符),UDID(设备唯一标识符),服务器ID)。
注册的目的是为了让APNs知道哪个设备(即哪个应用程序在哪个设备上)希望接收远程通知
APNs接收到请求后会发送Device Token给app唯一标识这个设备上的这个app
如果注册成功可以在这个回调函数中获取到
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("申请成功:\(deviceToken.map{ String(format: "%02.2hhx", $0)}.joined())")//获取到deviceToken,将deviceToken转化为16进制的字符串
}
当app获取到device token后需要将相关信息(Device Token ,Bundle ID,PayLoad(负载,需要发送的通知))发送给provide server,provide server将相关信息携带证书发送给APNs
feed back
Feedback 是 APNs 服务器提供的用于减少服务器压力以及优化网络的服务,基本的工作流程如下图:
Provider 发送一个远程通知给 APNs 服务器,APNs 服务器会检测目的设备是否在线,如果不在线,那么 APNs 服务器会暂存该消息;
当目的设备上线后,APNs 会发送暂存的消息给目的设备(按照苹果官方说法暂存消息只会暂存最后一条消息,之前的消息会被丢弃);
如果目的设备很久都没有上线,那么 APNs 消息会把该设备加入 feedback 名单。Provider 可以定期去 APNs 拉新 feedback 名单;
当 Provider 再次给之前的设备发送远程通知时,需要检查一下 feedback 名单,如果设备在这个名单,则不再发送给 APNs 了;
当设备重新上线后,Provider 可以再将此设备移除 feedback 名单,当 Provider 更新 feedback list 后,就可以重新给该设备发送远程通知了。当然,feedback list 的更新可能会有周期,如果需要及时有效的更新 feedback list,那么需要 App 打开后,及时通知 Provider;
这种机制的好处就是防止发送多余无用的远程通知消息,一方面可以减缓 APNs 服务器的压力,另一方面也可以减少网络流量;
pushKit
PushKit 主要用于处理 VoIP(Voice over Internet Protocol,互联网语音通信)应用程序的推送通知
需要Voip证书
重要特性:它可以在应用程序未运行时唤醒应用程序
PushKit区别与userNotification
不同点:
它不会弹出通知,声音角标等 而是直接唤醒你的APP,进入回调,也就是说,可以在没点击APP启动的情况下,就运行我们自己写的代码
相同点:
都是使用APNs传输推送通知到用户设备上
VoIP
VoIP应用程序必须与服务器保持持续的网络连接,才能接收来电和其他数据
最大的作用是:对方呼入,响起铃声和震动,提醒用户,对方挂断之后,铃声震动停止,普通的APNS通知,已经不能达到我们想要的效果
使用pushkit接收VoIP推送优点:
1.只有当VOIP推送发生时,设备才会被唤醒,避免了VoIP应用的缺点
VoIP推送直接进入应用程序进行处理。
VoIP推送被视为高优先级通知,不会延迟交付。
VoIP推送可以包含比标准推送通知提供的更多的数据。
如果收到VoIP推送时应用程序没有运行,它会自动重新启动。
即使你的应用程序在后台运行,你的应用程序也会在运行时处理推送。
如果你的应用程序没有运行,系统会在收到通知后自动启动;虽然你也可以使用无声的用户通知来更新你的应用程序,但你的应用不能保证在通知到达时启动。
PSTN和VoIP的区别
Public Switched Telephone Network ,本质就是我们现在打电话所使用的电话网络。
payload
VoIP的最大payload是5KB
其他的事4KB