实现需求:收到iOS推送后,本地sqlite保存退送记录。点击退送记录列表能够响应推送的事件。如果退送没有点击退送的话,没有办法获得退送的信息,所以也没有办法保存到本地,所以这个问题要解决。另一个问题是服务器要能够给特定的人发推送,所以注册推送的时候注册用户相关信息。
在程序启动的方法 didFinishLaunchingWithOptions
注册推送服务。要�区分不同的版本。
- (void)registerAPNS {
float sysVer = [[[UIDevice currentDevice] systemVersion] floatValue];
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
if (sysVer >= 10) {
// iOS 10
[self registerPush10];
#endif
if (sysVer < 8) {
// before iOS 8
[self registerPushBefore8];
} else {
// iOS 8-9
[self registerPush8to9];
}
}
- (void)registerPush10{
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
}
}];
[[UIApplication sharedApplication] registerForRemoteNotifications];
#endif
}
- (void)registerPush8to9{
UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
UIUserNotificationSettings *mySettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:mySettings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
- (void)registerPushBefore8{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
}
同时还应该在didFinishLaunchingWithOptions
添加推送处理逻辑,用于用户app没有启动时收到推送点击退送进入app的情况,其实也可以不调用XGPush handleLaunching:launchOptions successCallback
,直接调用里面的块里面的代码也是可以的,这样做也许是为了XGPush统计处理,也可能有其他原因,或者是信鸽的规范。
[XGPush handleLaunching:launchOptions successCallback:^{
[SqlitePush insertPushCacheWithKey:nil andWithValue:launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]];
}
// 自己根据推送字典的内容处理
[self processRomote:launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]];
NSLog(@"[XGDemo] Handle launching success-1");
} errorCallback:^{
NSLog(@"[XGDemo] Handle launching error-3");
}];
注册后,苹果会返回devicetoken,包含了设备信息和应用信息,然后调用信鸽的注册设备函数向信鸽服务器注册,
注册成功后通过setAccount函数设置账号,用来确定当前用户的身份,用户服务器对批量或者特定的用户退送。
一般account账号就是用户的user_id,比较稳定。
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSString *deviceTokenStr = [XGPush registerDevice:deviceToken account:@"myAccount" successCallback:^{
// NSLog(@"[XGDemo] register push success");
[XGPush setAccount:HVUSER_KEY successCallback:^{
NSLog(@"[XGDemo] Set account success");
} errorCallback:^{
NSLog(@"[XGDemo] Set account error");
}];
} errorCallback:^{
NSLog(@"[XGDemo] register push error");
}];
NSLog(@"[XGDemo] device token is %@", deviceTokenStr);
}
用户在前台运行的时候,默认收到推送不会弹出来,但是可以收到,所以应该手动处理,使用了 第三方类库
EBForeNotification
来显示推送。但是在iOS 10以后,推送发生了改变,即使在前台也可以正常显示推送了。
注册失败的也可以查看原因
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"[XGDemo] register APNS fail.\n[XGDemo] reason : %@", error);
}
在iOS10 以前 收到退送分为下面两种形式
- iOS 10以前走这里
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
[XGPush handleReceiveNotification:userInfo
successCallback:^{
[self processRomote:userInfo];
[SqlitePush insertPushCacheWithKey:nil andWithValue:userInfo];
} errorCallback:^{
NSLog(@"[XGDemo] Handle receive error");
}];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
if (userInfo!=nil) {
[SqlitePush insertPushCacheWithKey:nil andWithValue:userInfo];
//ios 10 以前在前台运行要自己让通知弹出
if (application.applicationState == UIApplicationStateActive) {
//1312
[EBForeNotification handleRemoteNotification:userInfo soundID:0 isIos10:NO];
}
else
{
[self processRomote:userInfo];
}
[application setApplicationIconBadgeNumber:0];
}
completionHandler(UIBackgroundFetchResultNewData);
}
- iOS 10 调用下面方法
// iOS 10 会走新 API, iOS 10 以前会走到老 API
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
// App 用户点击通知的回调
// 无论本地推送还是远程推送都会走这个回调
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler {
[self processRomote:response.notification.request.content.userInfo];
[XGPush handleReceiveNotification:response.notification.request.content.userInfo
successCallback:^{
NSLog(@"[XGDemo] Handle receive success");
} errorCallback:^{
NSLog(@"[XGDemo] Handle receive error");
}];
completionHandler();
}
// App 在前台弹通知需要调用这个接口
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
NSDictionary * userInfo = notification.request.content.userInfo;
if ([userInfo[@"action"] isEqualToString:@"logout"]) {
[self processRomote:userInfo];
return;
}
[SqlitePush insertPushCacheWithKey:nil andWithValue: notification.request.content.userInfo];
completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert);
}
以前的信鸽版本虽然也有对特定的用户进行推送的实现,但是极其不方便。比如原来用户没有登录,后来登录,或者换个账号登录的时候。app的用户id就发生变化了,根本不知道该怎么重新注册,自己几乎尝试了所有的unregister
类似的方法,并且尝试了很多,但是不起作用,应该是之前的版本提到要求信鸽的setAccount函数要求在didRegisterForRemoteNotificationsWithDeviceToken
这里面用,而didRegisterForRemoteNotificationsWithDeviceToken
方法根据文档必须满足3个条件才会调用,其中一个条件和上次获取的时间有关,另外一个记不清了,反正就是和用户登录和退出无关,所以在用户退出和登录的时候推送信息绑定的还是上一个用户或者任意用户(没有登录的情况)。但是在新的信鸽版本中,下面这两个函数起到了作用,可以随时更改推送的用户信息。
用户登录的时候
// 设置账号
[XGPush setAccount:HVUSER_KEY successCallback:^{
NSLog(@"[XGDemo] Set account success login");
} errorCallback:^{
NSLog(@"[XGDemo] Set account error login");
}];
用户退出登录的时候
[XGPush delAccount:^{
NSLog(@"反注册成功");
} errorCallback:^{
NSLog(@"反注册失败");
}];