可通知 1.2.6

可通知 1.2.6

测试已测试
Lang语言 Obj-CObjective C
许可 Apache-2.0
发布最新发布2020年3月

Matt Brooke-SmithIgor FerreiraFabio Gallonetto维护。



可通知 1.2.6

  • Future Workshops

可通知

可通知 是一个实用类集合,可以轻松集成可通知-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之后,系统会在两个地方通知应用程序这一操作

  1. 在 application(_:didFinishLaunchingWithOptions:) 方法中的 launchOptions 处接收到 UIApplicationLaunchOptionsKey.remoteNotification
  2. 如果应用处于前台,并且已配置 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的可变内容键。

许可证

Apache许可证版本2.0