iOS8 的 APNS(推送)-本地推送-服务器推送-地理位置推送

iOS Jan 5, 2015

iOS8 的推送改变了很多,一个一个来说吧。

从哪说起呢,感觉怎么这么乱。先列个列表吧。

  • 远程推送
  • 初级
  • 进阶(本地测试)(服务器测试)
  • 地理位置推送

服务器推送

先说服务器推送,使用之前必须先注册这个推送,用户要允许这个程序进行推送

最简单的方法:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 方法里

if (IOS8) {
        [[UIApplication sharedApplication] registerForRemoteNotifications];
        
        UIUserNotificationSettings *set = [UIUserNotificationSettings settingsForTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:set];
    }else{
        
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:
         (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
    }

然后屏幕上就会询问是否允许推送

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken 方法中,可以得到 deviceToken 一般来说重装、更新都不会改变,手机还原、刷机才会改变。不过也不排除苹果突然用了什么新的算法,导致更改。所以妥当的做法是每次开启,都验证一次。

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error 方法里可以打印错误。

高级一点的做法

iOS8开放了通知的一些功能,比如左划处理

如果是未锁屏状态:

锁屏状态:

创建消息上面要添加的动作(按钮的形式显示出来)

UIMutableUserNotificationAction *action = [[UIMutableUserNotificationAction alloc] init];
action.identifier = @"action";  //按钮的标示
action.title=@"查看";  //按钮的标题
action.activationMode = UIUserNotificationActivationModeForeground;  //当点击的时候启动程序
//    action.authenticationRequired = YES;
//    action.destructive = YES;
UIMutableUserNotificationAction *action2 = [[UIMutableUserNotificationAction alloc] init];  //第二按钮
action2.identifier = @"action2";
action2.title=@"取消";
action2.activationMode = UIUserNotificationActivationModeBackground;  //当点击的时候不启动程序,在后台处理
action.authenticationRequired = YES;//需要解锁才能处理,如果action.activationMode = UIUserNotificationActivationModeForeground;则这个属性被忽略
action.destructive = YES;

创建动作(按钮)的类别集合

UIMutableUserNotificationCategory *categorys = [[UIMutableUserNotificationCategory alloc] init];
categorys.identifier = @"alert";//这组动作的唯一标示
[categorys setActions:@[action,action2] forContext:(UIUserNotificationActionContextMinimal)];

创建UIUserNotificationSettings,并设置消息的显示类类型

UIUserNotificationSettings *uns = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound) categories:[NSSet setWithObjects:categorys, nil]];

注册推送

[[UIApplication sharedApplication] registerUserNotificationSettings:uns];
[[UIApplication sharedApplication] registerForRemoteNotifications];

若要使用远程推送,满足两个条件:

  1. 用户需要调用注册用户推送 registerUserNotificationSettings;
  2. 在 info.plist 文件中UIBackgroundModes必须包含远程通知。

1 上面已经介绍了,具体说 2,打开项目设置,按图设置即可

离线push数据包带上特定Category字段(字段内容需要前后台一起定义,必须要保持一致),手机端收到时,就能展示上述代码对应Category设置的按钮,和响应按钮事件。

//payload example:  {"aps":{"alert":"杰哥是个天才!!", "sound":"default", "badge": 1, "category":"alert"}}

重大修改:离线push数据包之前能带的数据最多为256字节,现在APPLE将该数值放大到2KB。 这个应该是只针对IOS8的。

本地测试

- (void)applicationDidEnterBackground:(UIApplication *)application 方法中

    UILocalNotification *notification = [[UILocalNotification alloc] init];
    notification.fireDate=[NSDate dateWithTimeIntervalSinceNow:5];
    notification.timeZone=[NSTimeZone defaultTimeZone];
    notification.alertBody=@"测试推送的快捷回复";
    notification.category = @"alert";
    [[UIApplication sharedApplication]  scheduleLocalNotification:notification];

就有如下效果:

远程测试

我假设你已经有下面三个文件:

CSR文件

P12私有密钥文件,Push.p12

SSL证书文件,aps_development.cer

我们用的是php环境,所以制作pem证书即可,java 环境需要p12证书,详细教程下方提供几个。

  • 把.cer的SSL证书转换为.pem文件,执行命令
openssl x509 -in aps.cer -inform der -out apns-cer.pem
  • 把私钥Push.p12文件转化为.pem文件。首先输入Push.p12的密码,再给新文件设置密码(至少4位),确认一遍,完成
openssl pkcs12 -nocerts -out apns-key.pem -in EduPush.p12
  • 去除密码
openssl rsa -in apns-key.pem -out apns-key-nop.pem
  • 对生成的这两个pem文件再生成一个pem文件,来把证书和私钥整合到一个文件里
cat apns-key-nop.pem apns-cer.pem > cert.pem

php代码可以到这里下载,设置方法详见README文件

地理位置推送

这个推送是新的API才有的特性,必须配合CLLocation定位一起使用。

//Location Notification
CLLocationManager *locMan = [[CLLocationManager alloc] init];
locMan.delegate = self;
[locMan requestWhenInUseAuthorization];

#pragma mark - CLLocationManager

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status

{
     BOOL canUseLocationNotifications = (status == kCLAuthorizationStatusAuthorizedWhenInUse);
    if (canUseLocationNotifications) {
        [self startShowLocationNotification];
    }
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification

{
    CLRegion *region = notification.region;
    if (region) {
    }
}

- (void)startShowLocationNotification

{
    CLLocationCoordinate2D local2D ;
    local2D.latitude = 123.0;
    local2D.longitude = 223.0;
    UILocalNotification *locNotification = [[UILocalNotification alloc] init];
    locNotification.alertBody = @"你接收到了";
    locNotification.regionTriggersOnce = YES;
    locNotification.region = [[CLCircularRegion alloc] initWithCenter:local2D radius:45 identifier:@"local-identity"];
    [[UIApplication sharedApplication] scheduleLocalNotification:locNotification];
}

如果没有开启Core Location 那么上面的didReceiveLocalNotification不会被调用

Tags

Jie Li

🚘 On-road / 📉 US Stock / 💻 Full Stack Developer / 🎓 Grad Student / ®️ ENTJ

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.