可通知
可通知 是一个实用类集合,可以轻松集成可通知-Rails
它处理设备令牌注册,并负责重试失败的请求和避免重复注册
为不同用户注册现有令牌将导致令牌被重新分配
设置
项目集成
iOS上的可通知
可在CocoaPods中使用。要使用它安装,只需将以下行添加到您的Podfile
pod 'Notifiable'
如果您未使用CocoaPods,您可以通过克隆此项目并将文件导入到自己的项目中来实现。此库使用AFNetworking作为依赖项,并被配置为子模块
您可以在Sample文件夹中查看实现示例。
配置SDK
在使用NotifiableManager
实例和方法之前,需要设置SDK将要与之通信的服务器和访问配置的组ID。
NotifiableManager.configure(url: <<SERVER_URL>>, accessId: <<USER_API_ACCESS_ID>>, secretKey: <<USER_API_SECRET_KEY>>, groupId: <<GROUP_ID>>)
组ID
如果你有一个通知扩展,可能希望在应用程序和相应的扩展之间共享Notifiable SDK配置。为此,SDK使用App Group的概念。
使用
要使用NotifiableManager
,创建一个新的实例,传递你的服务器URL、应用程序访问ID和应用密码密钥。您也可以提供块,用于在设备注册远程通知和接收新通知时通知您的代码。
self.manager = NotifiableManager(groupId: <<GROUP_ID>>, didRegisterBlock: { [unowned self] (manager, token) -> Void in
...
}, andNotificationBlock: { [unowned self] (manager, device, notification) -> Void in
...
})
转播应用程序事件
将设备token转播给NotifiableManager
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData)
{
NotifiableManager.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
}
将新通知转播给NotifiableManager
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
guard NotifiableManager.isValidNotification(userInfo) else {
completionHandler(.noData)
return
}
NotifiableManager.markAsReceived(notification: userInfo, groupId: kAppGroupId) { (error) in
if let _ = error {
completionHandler(.failed)
} else {
completionHandler(.newData)
}
}
}
监听应用程序事件
当设备注册远程通知或接收到远程通知时,您可以使用NotifiableManager
初始化时的块或注册一个作为NotifiableManagerListener
的对象来通知您。
func viewDidLoad() {
super.viewDidLoad()
NotifiableManager.register(listener: self)
}
//MARK: NotifiableManagerListener methods
func applicationDidRegisterForRemoteNotification(token: NSData) {
...
}
func applicationDidReceive(notification: [NSObject : AnyObject]) {
...
}
func manager(_ manager: NotifiableManager, didRegisterDevice device: NotifiableDevice) {
...
}
func manager(_ manager: NotifiableManager, didFailToRegisterDevice error: NSError) {
...
}
设备注册
在调用 application:didRegisterForRemoteNotificationsWithDeviceToken:
后,您可以使用设备令牌在 Notifiable-Rails
服务器上注册此设备。
您可以注册一个匿名设备
override func viewDidLoad() {
super.viewDidLoad()
//1 - Config manager
self.manager = NotifiableManager(groupId: <<GROUP_ID>>, didRegisterBlock: { [unowned self] (manager, token) -> Void in
//3 - Register device
self.registerDevice(manager, token: token)
}, andNotificationBlock: nil)
//2 - Request for permission
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (authorized, error) in
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
func registerDevice(manager:NotifiableManager, token:NSData) {
manager.register(name:"iPhone", locale: NSLocale.autoupdatingCurrentLocale(), properties: ["onsite":true]) { (device, error) -> Void in
...
}
}
或注册与用户关联的设备
func registerDevice(manager:NotifiableManager, token:NSData) {
manager.register(name:"device", userAlias: "user", locale: NSLocale.autoupdatingCurrentLocale(), properties: ["onsite":true]) { (device, error) -> Void in
...
}
}
properties
字典中保存了一些扩展参数,这些参数代表设备元数据,例如您可以发送设备的当前纬度和经度。
您可以通过管理器的 currentDevice
属性访问已注册的设备信息
let device = self.manager.currentDevice
更新设备信息
设备注册后,您可以更新设备信息
self.manager.update(token: nil, name: "device", userAlias: "user", location: NSLocale.currentLocale(), properties: ["onsite":true]) { (device, error) -> Void in
...
}
您还可以将设备关联到其他用户
self.manager.associated(to: user, completionHandler: { (device, error) -> Void in
...
}
或匿名化令牌
self.manager.anonymise { (device, error) -> Void in
...
}
注销设备
您可能希望在用户注销或选择退出应用时注销设备令牌。
self.manager.unregister { (device, error) -> Void in
...
}
通知验证
如果您有多个服务/框架可以在您的应用中发送通知,您可以在尝试向服务器发送请求之前检查通知是否由 Notifiable 发送的。
NotifiableManager.isValidNotification(userInfo)
更新通知状态
iOS 在接收到或打开通知时有一些特定的规则来调用您的应用,为了确保 Notifiable 服务器正确显示通知状态,应用必须使用 SDK 通知此类状态的更改,因为系统调用的方法超出了 SDK 的范围。
将通知标记为已打开
当用户点击通知时,在iOS 10之后,系统会在两个地方通知应用程序这一操作
- 在 application(_:didFinishLaunchingWithOptions:) 方法中的
launchOptions
处接收到UIApplicationLaunchOptionsKey.remoteNotification
- 如果应用处于前台,并且已配置
UNUserNotificationCenter
,则调用userNotificationCenter(_:didReceive:withCompletionHandler:)
在这两种情况下,您可以使用 markAsOpen(notification:groupId:completion:)
方法(其中 groupId 为可选参数)来通知服务器用户已打开通知。
通知验证
如果您有多个服务/框架可以在您的应用中发送通知,您可以在尝试向服务器发送请求之前检查通知是否由 Notifiable 发送的。
NotifiableManager.isValidNotification(userInfo)
应用程序完成启动
if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? [NSObject:AnyObject], NotifiableManager.isValidNotification(remoteNotification) {
NotifiableManager.markAsOpen(notification: remoteNotification, groupId: kAppGroupId, completion: nil)
}
UNUserNotificationCenter
在操作 UNUserNotificationCenterDelegate
时,最好在 NotifiableManager
完成其操作后再调用 completionHandler
。这将确保向 Notifiable 服务器的网络请求完成。
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
guard NotifiableManager.isValidNotification(userInfo) else {
completionHandler()
return
}
NotifiableManager.markAsOpen(notification: userInfo, groupId: kAppGroupId) { (_) in
completionHandler()
}
}
将通知标记为已接收
iOS系统有多个入口点来指示设备收到了远程通知。为了保持通知状态的一致性,您需要在一收到通知后立即将通知标记为已接收。这可以通过使用方法NotifiableManager.markAsReceived(notification:, groupId:, completion:)
(groupId是可选的)来实现,该方法用于在服务器上更新通知状态。
应用收到远程通知
如果您的服务器发送包含content-available: 1
的消息,并且您的应用已启用“远程通知”功能,则系统可能会唤醒您的应用以通知已到达的通知。在此点,您可以调用服务器来更新该通知状态。
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
guard NotifiableManager.isValidNotification(userInfo) else {
completionHandler(.noData)
return
}
NotifiableManager.markAsReceived(notification: userInfo, groupId: kAppGroupId) { (error) in
if let _ = error {
completionHandler(.failed)
} else {
completionHandler(.newData)
}
}
}
如Apple文档所述[2]
如果您已启用远程通知的背景模式,当远程通知到达时,系统会启动您的应用(或将它从挂起状态唤醒),并进入后台状态。但是,如果用户强制退出应用,系统不会自动启动应用。在这种情况下,用户必须重新启动应用或重新启动设备,系统才会再次尝试自动启动应用。
UNUserNotificationCenter
如果应用处于前台,并且您已配置了UNUserNotificationCenter
,则将调用userNotificationCenter(_:willPresent:withCompletionHandler:)
,这是更新通知状态的最好时机。
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
guard NotifiableManager.isValidNotification(userInfo) else {
return
}
NotifiableManager.markAsReceived(notification: userInfo, groupId: kAppGroupId) { (error) in
completionHandler(.alert)
}
}
通知服务扩展
如果服务器发送包含mutable-content: 1
属性的通知,您可以实现通知服务扩展,并在那里更新服务器上的通知状态。
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
self.bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
NotifiableManager.markAsReceived(notification: request.content.userInfo, groupId: kAppGroupId) { [weak self] (_) in
guard let contentHandler = self?.contentHandler, let bestAttempt = self?.bestAttemptContent else { return }
contentHandler(bestAttempt)
}
}
只有当以下两个条件都满足时,此扩展才会被调用
- 远程通知配置为显示警报。
- 远程通知的aps字典中包含带有值为1的可变内容键。