iOS 设备集成推送,以前需要集成开发证书和生产证书,比较麻烦,现在极光推送集成了Token Authentication,就简单方便许多,简单配置,然后集成就可以了;
一、配置 Token Authentication
1、首先在Developer 开发者中心 证书 添加 “Keys”
这一步很关键: 点击Download下载到本地,下载后是一个 p8 后缀格式 的文件,下载密钥后,由于服务器副本已被删除,因此无法重新下载。如果此时您还没有准备好下载密钥,请单击Done,稍后再下载。请务必将您的密钥备份保存在安全的地方。下载好后,做好备份,储存起来,丢失找不回的
记住下面的 Key ID
2、上传证书
将p8文件上传,输入Key ID,Team ID ,Bundle ID 点击保存就 OK 了
二、集成极光推送SDK
1、导入SDK
根据需求选择是否需要集成 IDFA
pod 'JCore', '2.1.2'
pod 'JPush', '3.2.6'
2、设置Xcode
请先确保 targets 中的 Bundle ID 和 证书中的Bundle ID一致
在TARGETS -> Signing & Capabilities -> + Capability 中添加
-- Access WIFI Information
-- Background Modes -> 勾选 “Remote notifications”
-- Push Notifications
extension AppDelegate: JPUSHRegisterDelegate {
func registureJPUSH(launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
let appKey = ""
let entity = JPUSHRegisterEntity()
if #available(iOS 12.0, *) {
entity.types = Int(JPAuthorizationOptions.alert.rawValue | JPAuthorizationOptions.badge.rawValue | JPAuthorizationOptions.sound.rawValue | JPAuthorizationOptions.providesAppNotificationSettings.rawValue)
} else {
// Fallback on earlier versions
}
JPUSHService.register(forRemoteNotificationConfig: entity, delegate: self)
// 获取 IDFA
// 如需使用 IDFA 功能请添加此代码并在初始化方法的 advertisingIdentifier 参数中填写对应值
// NSString *advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
// Required
// init Push
// notice: 2.1.5 版本的 SDK 新增的注册方法,改成可上报 IDFA,如果没有使用 IDFA 直接传 nil
var apsForProduction = false
#if DEBUG
apsForProduction = false
#else
apsForProduction = true
#endif
JPUSHService.setup(withOption: launchOptions, appKey: appKey, channel: "App Store", apsForProduction: apsForProduction , advertisingIdentifier: nil)
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
JPUSHService.registerDeviceToken(deviceToken)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
debugPrint("did Fail To Register For Remote Notifications With Error: \(error)")
}
// ios 12 Support
@available(iOS 10.0, *)
func jpushNotificationCenter(_ center: UNUserNotificationCenter!, openSettingsFor notification: UNNotification!) {
if notification != nil && ((notification.request.trigger?.isKind(of: UNPushNotificationTrigger.self)) != nil) {
debugPrint("从通知界面直接进入应用")
} else {
debugPrint("从通知设置界面进入应用")
}
}
// iOS 10 Support
@available(iOS 10.0, *)
func jpushNotificationCenter(_ center: UNUserNotificationCenter!, willPresent notification: UNNotification!, withCompletionHandler completionHandler: ((Int) -> Void)!) {
let userInfo = notification.request.content.userInfo
if ((notification.request.trigger?.isKind(of: UNPushNotificationTrigger.self)) != nil) {
JPUSHService.handleRemoteNotification(userInfo)
}
completionHandler(Int(JPAuthorizationOptions.alert.rawValue)) // 需要执行这个方法,选择是否提醒用户,有 Badge、Sound、Alert 三种类型可以选择设置
}
// iOS 10 Support
@available(iOS 10.0, *)
func jpushNotificationCenter(_ center: UNUserNotificationCenter!, didReceive response: UNNotificationResponse!, withCompletionHandler completionHandler: (() -> Void)!) {
let userInfo = response.notification.request.content.userInfo
if ((response.notification.request.trigger?.isKind(of: UNPushNotificationTrigger.self)) != nil) {
JPUSHService.handleRemoteNotification(userInfo)
}
completionHandler() // 系统要求执行这个方法
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// iOS 7 Support
JPUSHService.handleRemoteNotification(userInfo)
completionHandler(.newData)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
// Required, For systems with less than or equal to iOS 6
JPUSHService.handleRemoteNotification(userInfo)
}
}
后续操作
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var isForceLandscape:Bool = false
var isForcePortrait:Bool = false
var isForceAllDerictions:Bool = false //支持所有方向
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow.init(frame: UIScreen.main.bounds)
self.window!.backgroundColor = .white
self.window!.makeKeyAndVisible()
registureJPUSH(launchOptions: launchOptions)
testView(index: 0)
return true
}
/*
//极光推送 角标清0 未读消息不清空
//本地推送UILocalNotification的applicationIconBadgeNumber影响到角标的显示,不出对通知栏的消息造成影响
//3.UIApplication的applicationIconBadgeNumber属性既会影响角标的显示,又会影响通知栏通知的处理。
//1)当applicationIconBadgeNumber>0时,角标会随之变化,通知栏通知不变。
//2)当applicationIconBadgeNumber=0时,角标变为0不显示,通知栏通知清空。
//3)当applicationIconBadgeNumber<0时,角标变为0不显示,通知栏通知清空。
//所以要想不清除通知栏内容,极光就不能设置这个:[UIApplication sharedApplication].applicationIconBadgeNumber = 0;,极光的cleanBadgeNum方法也不能用。
*/
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
// UIApplication.shared.applicationIconBadgeNumber = 0
// App 退至后台会走此方法
testView(index: 1)
/*
if ([UIApplication sharedApplication].applicationIconBadgeNumber) {
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 11.0) {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:-1];
} else {
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
// 设置通知的发送时间,单位秒
localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:0.5];
//收到通知时App icon的角标
localNotification.applicationIconBadgeNumber = -1;
// 3.发送通知(🐽 : 根据项目需要使用)
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}
}
[JPUSHService setBadge:0];
*/
}
}
extension AppDelegate: JPUSHRegisterDelegate {
func registureJPUSH(launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
let appKey = ""
let entity = JPUSHRegisterEntity()
if #available(iOS 12.0, *) {
entity.types = Int(JPAuthorizationOptions.alert.rawValue | JPAuthorizationOptions.badge.rawValue | JPAuthorizationOptions.sound.rawValue | JPAuthorizationOptions.providesAppNotificationSettings.rawValue)
} else {
// Fallback on earlier versions
}
JPUSHService.register(forRemoteNotificationConfig: entity, delegate: self)
// 获取 IDFA
// 如需使用 IDFA 功能请添加此代码并在初始化方法的 advertisingIdentifier 参数中填写对应值
// NSString *advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
// Required
// init Push
// notice: 2.1.5 版本的 SDK 新增的注册方法,改成可上报 IDFA,如果没有使用 IDFA 直接传 nil
var apsForProduction = false
#if DEBUG
apsForProduction = false
#else
apsForProduction = true
#endif
JPUSHService.setup(withOption: launchOptions, appKey: appKey, channel: "App Store", apsForProduction: apsForProduction , advertisingIdentifier: nil)
}
/*
//极光推送 角标清0 未读消息不清空
//本地推送UILocalNotification的applicationIconBadgeNumber影响到角标的显示,不出对通知栏的消息造成影响
//3.UIApplication的applicationIconBadgeNumber属性既会影响角标的显示,又会影响通知栏通知的处理。
//1)当applicationIconBadgeNumber>0时,角标会随之变化,通知栏通知不变。
//2)当applicationIconBadgeNumber=0时,角标变为0不显示,通知栏通知清空。
//3)当applicationIconBadgeNumber<0时,角标变为0不显示,通知栏通知清空。
//所以要想不清除通知栏内容,极光就不能设置这个:[UIApplication sharedApplication].applicationIconBadgeNumber = 0;,极光的cleanBadgeNum方法也不能用。
*/
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
// UIApplication.shared.applicationIconBadgeNumber = 0
// App 退至后台会走此方法
// testView(index: 1)
/*
if ([UIApplication sharedApplication].applicationIconBadgeNumber) {
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 11.0) {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:-1];
} else {
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
// 设置通知的发送时间,单位秒
localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:0.5];
//收到通知时App icon的角标
localNotification.applicationIconBadgeNumber = -1;
// 3.发送通知(🐽 : 根据项目需要使用)
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}
}
[JPUSHService setBadge:0];
*/
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
JPUSHService.registerDeviceToken(deviceToken)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
debugPrint("did Fail To Register For Remote Notifications With Error: \(error)")
}
// ios 12 Support
@available(iOS 10.0, *)
func jpushNotificationCenter(_ center: UNUserNotificationCenter!, openSettingsFor notification: UNNotification!) {
debugPrint("==================== 0")
if notification != nil && ((notification.request.trigger?.isKind(of: UNPushNotificationTrigger.self)) != nil) {
debugPrint("从通知界面直接进入应用")
testView(index: 2)
} else {
debugPrint("从通知设置界面进入应用")
testView(index: 3)
}
}
// iOS 10 Support
@available(iOS 10.0, *)
func jpushNotificationCenter(_ center: UNUserNotificationCenter!, willPresent notification: UNNotification!, withCompletionHandler completionHandler: ((Int) -> Void)!) {
debugPrint("App正在运行时推送进入 = 1")
UIApplication.shared.applicationIconBadgeNumber = 0
let userInfo = notification.request.content.userInfo
debugPrint((userInfo as NSDictionary))
if ((notification.request.trigger?.isKind(of: UNPushNotificationTrigger.self)) != nil) {
JPUSHService.handleRemoteNotification(userInfo)
}
// completionHandler(Int(JPAuthorizationOptions.alert.rawValue)) // 需要执行这个方法,选择是否提醒用户,有 Badge、Sound、Alert 三种类型可以选择设置
completionHandler(Int(JPAuthorizationOptions.sound.rawValue))
showOrderDetailsView(model: AppJPUSHModel.deserialize(from: userInfo as NSDictionary)!, show: true)
}
// iOS 10 Support
@available(iOS 10.0, *)
func jpushNotificationCenter(_ center: UNUserNotificationCenter!, didReceive response: UNNotificationResponse!, withCompletionHandler completionHandler: (() -> Void)!) {
debugPrint("App未运行,点击推送消息进入,App 已退至后台,收到消息推送,点击消息推送 = 2")
let userInfo = response.notification.request.content.userInfo
if ((response.notification.request.trigger?.isKind(of: UNPushNotificationTrigger.self)) != nil) {
JPUSHService.handleRemoteNotification(userInfo)
}
completionHandler() // 系统要求执行这个方法
// testView(index: 5)
showOrderDetailsView(model: AppJPUSHModel.deserialize(from: userInfo as NSDictionary)!, show: false)
}
/*
基于 iOS 7 及以上的系统版本,如果是使用 iOS 7 的 Remote Notification 特性那么处理函数需要使用
*/
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
debugPrint("==================== 3")
// iOS 7 Support
JPUSHService.handleRemoteNotification(userInfo)
completionHandler(.newData)
testView(index: 6)
}
/*
基于 iOS 6 及以下的系统版本,如果 App 状态为正在前台或者点击通知栏的通知消息,那么此函数将被调用,并且可通过 AppDelegate 的 applicationState 是否为 UIApplicationStateActive 判断程序是否在前台运行
*/
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
debugPrint("==================== 4")
// Required, For systems with less than or equal to iOS 6
JPUSHService.handleRemoteNotification(userInfo)
testView(index: 7)
}
func testModel() -> AppJPUSHModel {
var model = AppJPUSHModel()
model.status = 2
model.type = 1
model.title = "asdf dddf"
model.address = "dfadsfadsfasdf "
model.description = "asdfacxggg"
model.attachments = "http://api.unicrom.cn/images/1588231332_494399.jpg,http://api.unicrom.cn/images/1588235202_118597.jpg"
return model
}
func jpushRemoteNotificationInfo(userInfo:NSDictionary) {
// // 取得 APNs 标准信息内容
// NSDictionary *aps = [userInfo valueForKey:@"aps"];
// NSString *content = [aps valueForKey:@"alert"]; //推送显示的内容
// NSInteger badge = [[aps valueForKey:@"badge"] integerValue]; //badge 数量
// NSString *sound = [aps valueForKey:@"sound"]; //播放的声音
// // 取得 Extras 字段内容
// NSString *customizeField1 = [userInfo valueForKey:@"customizeExtras"]; //服务端中 Extras 字段,key 是自己定义的
}
func showOrderDetailsView(model:AppJPUSHModel,show guideView:Bool) {
guard GlobalData.share.api_token != nil else { return }
UIApplication.shared.applicationIconBadgeNumber = 0
/// 工单的状态1:未分配,2:处理中,3:待分配,4:已完成 5: 已取消
let status:[OrderStatus] = [.undistributed,.processing,.unconfirmed,.finished,.canceled]
guard guideView == true else {
if model.type == 0 {
pushViewController(orderStatue: status[model.status!-1], companyId: model.company_id, sheetId: model.sheet_id)
} else {
pushViewController(orderStatue: status[model.status!-1], companyId: model.company_id, sheetId: model.sheet_id)
}
return
}
if model.type == 0 {
self.window!.addSubview(progressView)
progressView.frame = self.window!.bounds
progressView.setValues(text: model.process_note) {
self.pushViewController(orderStatue: status[model.status!-1], companyId: model.company_id, sheetId: model.sheet_id)
}
}
else {
self.window!.addSubview(orderDetailView)
orderDetailView.frame = self.window!.bounds
orderDetailView.setValues(model: model) {
self.pushViewController(orderStatue: status[model.status!-1], companyId: model.company_id, sheetId: model.sheet_id)
}
}
}
func pushViewController(orderStatue:OrderStatus,companyId:Int! = nil,sheetId:Int! = nil) {
let vc = WorkUndistributedVC()
vc.orderStatue = orderStatue
vc.companyId = companyId
vc.sheetId = sheetId
topVC!.navigationController!.pushViewController(vc, animated: true)
}
func testView(index:Int) {
let progressView = JPUSHViewOrderProgress.loadFromNib("JPUSHView", index: 0)
self.window!.addSubview(progressView)
progressView.frame = self.window!.bounds
progressView.setValues(text: nil) {
}
progressView.detailTextView.text = "\(index)"
}
}
推送消息
/*
App 未运行,无推送消息: 0
App 未运行,有推送消息: 1 - 0
App 未运行,点击推送消息: 5 - 0
App 正在前台运行: 4
App 已退至后台,收到消息推送,未点击消息推送: 无
App 已退至后台,收到消息推送,点击消息推送: 5
*/
具体文档请参考 : 极光推送-官方文档