个推推送总结:
个推第三方平台官网地址:http://www.getui.com/cn/index.html
首先去官网注册账号,创建应用,应用的配置信息,创建APNs推送证书上传 P12证书(开发对应开发证书,上线对应生产证书)包括导入 SDK 添加依赖库...这些繁琐的事请移步个推官网查看 xcode 集成教程.
一.推送的流程
个推 iOS 推送服务框架如下图所示:
- 绿色部分是 APNs 推送,个推平台替开发者的应用通过苹果 APNs 服务器向指定的目标设备进行推送。由 APNs Server 将通知推送到相应的 iOS 设备上。
- 红色部分是个推应用内推送部分,即 App 启动时,应用内集成的个推SDK会开启长连接到个推服务器,从而开发者可通过个推服务器推送消息到 App 里,这条链路性能和稳定性更强,是APNs的一个很重要的补充。
app 在收到推送消息时分为三种情况
1.app 在前台接收到通知
APP接收到推送后推送后首先弹出一个Alert提示是否跳转页面
2.app 在后台接收到通知
点击通知栏使APP进入前台后,直接跳转页面
点击icon图标使APP进入前台后,不作操作
3.app 处于关闭状态接收到通知
点击通知栏启动APP,直接跳转页面
点击icon图标启动APP,不作操作
二.iOS 集成个推只支持透传消息(透传消息并且支持安卓)
三.集成个推官网 SDK 配置AppID,AppKey,AppSecret
首先为AppDelegate添加一个属性 分辨通知的三种情况
// 用来判断是否是通过点击通知栏开启(唤醒)APP @property (nonatomic) BOOL isLaunchedByNotification;
[1]:使用APPID/APPKEY/APPSECRENT创建个推实例
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self startSdkWith:kGtAppId appKey:kGtAppKey appSecret:kGtAppSecret];
}
- (void)startSdkWith:(NSString *)appID appKey:(NSString *)appKey appSecret:(NSString *)appSecret { //[1-1]:通过 AppId、 appKey 、appSecret 启动SDK //该方法需要在主线程中调用 [GeTuiSdk startSdkWithAppId:appID appKey:appKey appSecret:appSecret delegate:self]; //[1-2]:设置是否后台运行开关 [GeTuiSdk runBackgroundEnable:YES]; //[1-3]:设置电子围栏功能,开启LBS定位服务 和 是否允许SDK 弹出用户定位请求 [GeTuiSdk lbsLocationEnable:YES andUserVerify:YES]; }
[2]:注册APNS
#pragma mark - 用户通知(推送) _自定义方法 /** 注册远程通知 */ - (void)registerRemoteNotification { if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 // Xcode 8编译会调用 UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionCarPlay) completionHandler:^(BOOL granted, NSError *_Nullable error) { if (!error) { NSLog(@"request authorization succeeded!"); } }]; [[UIApplication sharedApplication] registerForRemoteNotifications]; #else // Xcode 7编译会调用 UIUserNotificationType types = (UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge); UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; [[UIApplication sharedApplication] registerForRemoteNotifications]; #endif } else if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) { UIUserNotificationType types = (UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge); UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; [[UIApplication sharedApplication] registerForRemoteNotifications]; } else { UIRemoteNotificationType apn_type = (UIRemoteNotificationType)(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge); [[UIApplication sharedApplication] registerForRemoteNotificationTypes:apn_type]; } }
[3]远程通知注册成功委托
/** 远程通知注册成功委托 */ - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { NSString *token = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]]; token = [token stringByReplacingOccurrencesOfString:@" " withString:@""]; NSLog(@" >>>[DeviceToken Success]:%@ ", token); NSLog(@"--个推注册成功_-"); // [ GTSdk ]:向个推服务器注册deviceToken [GeTuiSdk registerDeviceToken:token]; }
/** 远程通知注册失败委托 */
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { NSLog(@"---个推注册失败---");
//注册失败通知个推服务器 [GeTuiSdk registerDeviceToken:@""];
}
[4]APP已经接收到“远程”通知(推送) - (App运行在后台/App运行在前台)
/** APP已经接收到“远程”通知(推送) - (App运行在后台/App运行在前台) */ - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { //此时 App 在后台点击通知栏进去前台 这里可做进入前台操作 //app 进去前台 icon角标显示数为0 并且发送个推服务器 [[UIApplication sharedApplication] cancelAllLocalNotifications]; [UIApplication sharedApplication].applicationIconBadgeNumber = 0; [GeTuiSdk setBadge:0]; // [ GTSdk ]:将收到的APNs信息传给个推统计 [GeTuiSdk handleRemoteNotification:userInfo]; // [4-EXT]:处理APN NSString *record = [NSString stringWithFormat:@"App运行在后台/App运行在前台[APN]%@, %@", [NSDate date], userInfo]; NSLog(@"%@", record); completionHandler(UIBackgroundFetchResultNewData); self.isLaunchedByNotification = YES;
//iOS 10中收到推送消息
#pragma mark - iOS 10中收到推送消息 #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 // iOS 10: App在前台获取到通知 - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler { NSLog(@"willPresentNotification:%@", notification.request.content.userInfo); // 根据APP需要,判断是否要提示用户Badge、Sound、Alert completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert); } // iOS 10: 点击通知进入App时触发 - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler { //角标复位 [GeTuiSdk resetBadge]; [[UIApplication sharedApplication]setApplicationIconBadgeNumber:0]; [[UIApplication sharedApplication] cancelAllLocalNotifications]; NSLog(@"didReceiveNotification:%@", response.notification.request.content.userInfo); // [ GTSdk ]:将收到的APNs信息传给个推统计 [GeTuiSdk handleRemoteNotification:response.notification.request.content.userInfo]; completionHandler(); } #endif
//设置GeTuiSdkDelegate
注意 APP 启动成功会返回 clientId ,我们项目中使用clientId进行消息透传,在登录的时候将clientId传给我们自己的服务器,我们服务器根据clientId给用户进行推送
/** SDK启动成功返回cid */ - (void)GeTuiSdkDidRegisterClient:(NSString *)clientId { // [4-EXT-1]: 个推SDK已注册,返回clientId NSLog(@">>>[GeTuiSdk RegisterClient]:----%@", clientId); // 将clientId写入本地 [USER_DEFAULT setObject:clientId forKey:kPushClientId]; } /** SDK遇到错误回调 */ - (void)GeTuiSdkDidOccurError:(NSError *)error { // [EXT]:个推错误报告,集成步骤发生的任何错误都在这里通知,如果集成后,无法正常收到消息,查看这里的通知。 NSLog(@" >>[GTSdk error]:%@ ", [error localizedDescription]); }
/** SDK收到透传消息回调 */
/** SDK收到透传消息回调 */ - (void)GeTuiSdkDidReceivePayloadData:(NSData *)payloadData andTaskId:(NSString *)taskId andMsgId:(NSString *)msgId andOffLine:(BOOL)offLine fromGtAppId:(NSString *)appId { // 汇报个推自定义事件 [GeTuiSdk sendFeedbackMessage:90001 andTaskId:taskId andMsgId:msgId]; // [4]: 收到个推消息 //这里收到透传消息,根据自己服务器返回的格式处理 NSDictionary * jsonDict = [NSJSONSerialization JSONObjectWithData:payloadData options:NSJSONReadingMutableLeaves error:nil]; // 当app不在前台时,接收到的推送消息offLine值均为YES // 判断app是否是点击通知栏消息进行唤醒或开启 // 如果是点击icon图标使得app进入前台,则不做操作,并且同一条推送通知,此方法只执行一次 if (offLine) { // 离线消息,说明app接收推送时不在前台 if (self.isLaunchedByNotification) { // app是通过点击通知栏进入前台 } else { // app是通过点击icon进入前台,在这里不做操作 } } else { // app已经处于前台,提示框提示 //调用系统震动系统声音 AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); AudioServicesPlaySystemSound(1007); } // 控制台打印日志 NSString *msg = [NSString stringWithFormat:@"SDK收到透传消息回调taskId=%@,messageId:%@,payloadMsg:%@%@", taskId, msgId, jsonDict, offLine ? @"<离线消息>" : @""]; NSLog(@" >>[GTSdk ReceivePayload]:%@ ", msg); #pragma mark--- 接收到推送后,进行提示或怎样 }
/** SDK收到sendMessage消息回调 */ - (void)GeTuiSdkDidSendMessage:(NSString *)messageId result:(int)result { // 发送上行消息结果反馈 NSString *msg = [NSString stringWithFormat:@"sendmessage=%@,result=%d", messageId, result]; NSLog(@" >>[GTSdk DidSendMessage]:%@ ", msg); } /** SDK运行状态通知 */ - (void)GeTuiSDkDidNotifySdkState:(SdkStatus)aStatus { // 通知SDK运行状态 NSLog(@" >>[GTSdk SdkState]:%u ", aStatus); }
#pragma mark ---application - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { NSLog(@"推送的内容:%@",notificationSettings); [application registerForRemoteNotifications]; }
注意: app 运行在后台时并不会走 APNS 推送,由个推服务器推送,我们要让 app在后台第一时间让个推 SDK 断线,先用 APNS 推送, app 进入前台重新激活 SDK, 如果由个推服务器推送 app 可以收到透传的消息,但不会在通知栏提示.
- (void)applicationDidEnterBackground:(UIApplication *)application { ///切后台关闭SDK,让SDK第一时间断线,让个推先用APN推送 [GeTuiSdk destroy]; } - (void)applicationWillEnterForeground:(UIApplication *)application { //设置角标为0 相当于复位 [GeTuiSdk setBadge:0]; [[UIApplication sharedApplication]setApplicationIconBadgeNumber:0];//进入前台取消应用消息图标搜索 [[UIApplication sharedApplication] cancelAllLocalNotifications]; } - (void)applicationDidBecomeActive:(UIApplication *)application { [DeviceDelegateHelper sharedInstance].preDate = [NSDate date]; /// 重新上线 [self startSdkWith:kGtAppId appKey:kGtAppKey appSecret:kGtAppSecret]; }
四.推送开关
关于推送开关的设置,我这里使用单例类属性接收,
//SDK设置推送模式回调 - (void)GeTuiSdkDidSetPushMode:(BOOL)isModeOff error:(NSError *)error { if (error) { NSLog(@" >>[GTSdk SetModeOff Error]:%@ ", [error localizedDescription]); return; } NSLog(@"---ss-%d____",isModeOff); NSLog(@" >>[GTSdk SetModeOff]:%@ ----", isModeOff ? @"开启" : @"关闭"); [GlobalData shareIntance].isMessagePush = isModeOff; }
在需要设置 UISwitch 开关的地方来设置
[pushBtn setOn:[DemoGlobalClass sharedInstance].isMessageShake];
- (void)getValue:(UISwitch*)sender { [GlobalData shareIntance].isMessagePush = sender.isOn; NSLog(@"-----%d__--",!sender.isOn); //发送开关结果告诉个推服务器 [GeTuiSdk setPushModeForOff:!sender.isOn]; }
五.关于iOS icon 角标显示
角标的处理,其实个推 SDK 已经封装好了,iOS 前端只需要把收到推送的消息个数,已读全部通知,设置角标为0并且发送个推服务器,如有未读推送通知,把剩余的通知发送给个推服务器,我们服务器从个推服务器上获取角标,来设置推送的消息个数,并有我们服务器发送透传消息过来.
//设置角标为0 相当于复位 [GeTuiSdk setBadge:0]; [[UIApplication sharedApplication]setApplicationIconBadgeNumber:0];//进入前台取消应用消息图标搜索 [[UIApplication sharedApplication] cancelAllLocalNotifications];