swift集成JPUSH(极光推送)代码部分解析

/ 0

这里就不赘述推送证书和签名文件了,做过远程推送的都知道。

准备工作

注册JPUSH账号并创建应用,创建应用过程中需要Apple推送证书文件,这个可以在Apple开发中心创建并下载,最终我们可以得到appKey。

下载官方SDK并导入到项目中,并完成下面所罗列出的配置工作。

在项目Targets -> 项目名 -> Capabilities -> Background Modes,勾选Remote notifications选项,保证我们的app在后台也能接收到推送信息。

在项目Targets -> 项目名 -> General -> Linked Frameworks and Libraries下添加下列framework:

注册通知

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    setupJPush(launchOptions) // 配置JPUSH    
    return true
}
// 配置极光推送
private func setupJPush(launchOptions: [NSObject: AnyObject]?) {
    JPUSHService.registerForRemoteNotificationTypes(UIUserNotificationType.Badge.rawValue | UIUserNotificationType.Alert.rawValue | UIUserNotificationType.Sound.rawValue, categories: nil)
    JPUSHService.setupWithOption(launchOptions, appKey: JPUSH_APP_KEY, channel: JPUSH_CHANNEL, apsForProduction: JPUSH_IS_PRODUCTION)
    JPUSHService.crashLogON()
    
    // 延迟发送通知(app被杀死进程后收到通知,然后通过点击通知打开app在这个方法中发送通知)
    performSelector(#selector(sendNotification(_:)), withObject: launchOptions, afterDelay: 1.5)
}

处理通知

// 发送通知
@objc private func sendNotification(launchOptions: [NSObject: AnyObject]?) {
    if let options = launchOptions {
        let userInfo = options[UIApplicationLaunchOptionsRemoteNotificationKey] as? [NSObject : AnyObject]
        if let info = userInfo {
            NSNotificationCenter.defaultCenter().postNotificationName("didReceiveRemoteNotificationOfJPush", object: info)
        }
    }
}

// 传递deviceToken注册远程通知
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
    JPUSHService.registerDeviceToken(deviceToken)
}

// 注册远程通知失败
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
    print("did Fail To Register For Remote Notifications With Error: \(error)")
}

// iOS7后接收到远程通知
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
    
    JPUSHService.handleRemoteNotification(userInfo)
    completionHandler(UIBackgroundFetchResult.NewData)
    
    if application.applicationState == .Background || application.applicationState == .Inactive {
        application.applicationIconBadgeNumber = 0
        NSNotificationCenter.defaultCenter().postNotificationName("didReceiveRemoteNotificationOfJPush", object: userInfo)
    } else if application.applicationState == .Active {
        application.applicationIconBadgeNumber = 0
        
        let message = userInfo["aps"]!["alert"] as! String
        let alertC = UIAlertController(title: "收到新的消息", message: message, preferredStyle: UIAlertControllerStyle.Alert)
        let confrimAction = UIAlertAction(title: "查看", style: UIAlertActionStyle.Destructive, handler: { (action) in
            NSNotificationCenter.defaultCenter().postNotificationName("didReceiveRemoteNotificationOfJPush", object: userInfo)
        })
        let cancelAction = UIAlertAction(title: "忽略", style: UIAlertActionStyle.Default, handler: { (action) in
            
        })
        alertC.addAction(confrimAction)
        alertC.addAction(cancelAction)
        UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alertC, animated: true, completion: nil)
    }
}

// 接收到本地通知
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
    JPUSHService.showLocalNotificationAtFront(notification, identifierKey: nil)
}

值得注意的是,我们APP在收到远程通知后的处理工作,在这里要分成3种情况来处理。

第一种:app处于活跃状态下,也就是用户正在使用app的情况下收到远程通知。这个时候会直接调用下面的方法。

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void)

这个方法中我们可以获取到通知信息,一般做法是给用户一个友好的提示,并让用户选择是否跳转到指定的控制器。

第二种:app处于非活跃状态下,或者app在后台运行中收到远程通知。如果用户点击了推送信息,这个时候会打开我们的app,并调用下面方法。

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void)

我们可以在这个方法中发送通知,跳转到指定的控制器。

第三种:app在已经被杀死进程的情况下收到远程通知。我们都知道appdelegate里的如下方法,只会在启动应用程序的时候调用一次。

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool

大家也许都注意到了,这个方法里有一个参数 launchOptions 。这个参数是做甚的呢?当我们的应用程序不是通过用户直接点击应用图标启动的情况下,这个参数才会有值。比如通过其他应用打开的应用,比如通过通知打开的应用。这里我只解释通过远程通知打开应用时这个参数的用法。

其实就是通过通知启动应用时, launchOptions 字典通过

UIApplicationLaunchOptionsRemoteNotificationKey 键可以直接获取到 userInfo 字典。这个字典就和上面接收到远程通知方法中的那个userInfo参数一样。既然我们可以通过这个参数获取到userInfo,所以我们就可以在这里进行发送通知给需要跳转的控制器了。

不过值得注意的是:这个方法是应用程序启动时才调用的方法,所以这个时候我们需要跳转的控制器还没有创建呢?既然没有注册通知中心,我们在这个时候发送通知有何意义?

解决办法1:延迟发送通知,也就是在确保接收通知的控制器已经注册了通知中心,我们才在这里post通知。

解决办法2:保存userInfo,也就是在appDelegate里新增一个全局属性来引用这个字典。然后在我们需要跳转的控制器里直接判断userInfo是否有值,如果有值则可以直接跳转,并把userInfo赋值为nil,防止多次跳转。如果没有值,则啥都不发生就行了。

由于项目比较大,可以直接查看这个文件就好了,如果有兴趣,可以下载整个项目。

demo:https://github.com/6ag/BaoKanIOS/blob/master/BaoKanIOS/BaoKanIOS/Classes/Application/AppDelegate.swift