这里就不赘述推送证书和签名文件了,做过远程推送的都知道。
准备工作
注册JPUSH账号并创建应用,创建应用过程中需要Apple推送证书文件,这个可以在Apple开发中心创建并下载,最终我们可以得到appKey。
下载官方SDK并导入到项目中,并完成下面所罗列出的配置工作。
在项目Targets -> 项目名 -> Capabilities -> Background Modes,勾选Remote notifications选项,保证我们的app在后台也能接收到推送信息。
在项目Targets -> 项目名 -> General -> Linked Frameworks and Libraries下添加下列framework:
- CFNetwork.framework
- CoreFoundation.framework
- CoreTelephony.framework
- SystemConfiguration.framework
- CoreGraphics.framework
- Foundation.framework
- UIKit.framework
- Security.framework
- ImageIO.framework
- Xcode7需要的是libz.tbd;Xcode7以下版本是libz.dylib
- Adsupport.framework (获取IDFA需要;如果不使用IDFA,请不要添加)
注册通知
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,防止多次跳转。如果没有值,则啥都不发生就行了。
由于项目比较大,可以直接查看这个文件就好了,如果有兴趣,可以下载整个项目。