ios消息推送实现

ios消息推送实现

ios远程推送工作原理

什么是APNS?

APNs:Apple Push Notification server 苹果推送通知服务,苹果的APNs允许设备和苹果的推送通知服务器保持连接,支持开发者推送消息给用户设备对应的应用程序。

消息推送的步骤

  1. 注册:为应用程序申请消息推送服务。此时你的设备会向APNs服务器发送注册请求。
  2. APNs服务器接受请求,并将deviceToken返给你设备上的应用程序
  3. 客户端应用程序将deviceToken发送给后台服务器程序,后台接收并储存。
  4. 后台服务器向APNs服务器发送推送消息。
  5. APNs服务器将消息发给deviceToken对应设备上的应用程序。

####

证书制作

  1. 通过mac的钥匙串访问申请证书:
    钥匙串访问->证书助理->从证书机构请求证书

  2. 输入证书信息(邮箱及名称),选择存储到磁盘。此时我们能得到xx.certSigningRequest文件。

  3. 登陆苹果开发者官网,新建App IDs,注意开启”Push Notifications选项”
  4. 配置Push Notifications,选择Create Certificate,然后点击Choose File上传生成的xx.certSigningRequest文件,上传成功后,可以得到aps_development.cer文件。
  1. 双击aps_development.cer,将密钥导入钥匙串,然后右键导出xx.p12证书,设置相关密码并保存。
  2. 生成push_cert.pem证书
    1)转换公钥
    openssl x509 -in aps_developer.cer -inform der -out public.pem
    2)转换私钥
    openssl pkcs12 -nocerts -in xx.p12 -out private.pem (需要输入密码)
    3)把两个证书合成
    cat public.pem private.pem > push_cert.pem

  3. Production SSL Certificate证书的制作类似。

编码实现

(注:需要在ios工程下的TARGETS->Capabilities->Push Notifications选项设置为ON。同时将Background ModesRemote notifications设置为ON,同时确保Signing的证书信息配置正确)

  • 注册消息推送服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

...

if ([[UIApplication sharedApplication] respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) {
//ios8及以上版本
//创建UIUserNotificationSettings,并设置消息的显示类类型
UIUserNotificationSettings *notiSettings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound) categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:notiSettings];
} else { // ios7
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |UIRemoteNotificationTypeSound |UIRemoteNotificationTypeAlert)];
}
...
}
  • 注册成功获取DeviceToken
1
2
3
4
5
6
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{;
NSLog(@"%@", deviceToken);
NSString *token = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
token = [token stringByReplacingOccurrencesOfString:@" " withString:@""];
NSLog(@"deviceToken:%@", token);
}
  • 注册远程推送失败回调
1
2
3
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
NSLog(@"remote Error! %@",error);
}
  • 获取推送信息
1
2
3
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
NSLog(@"Receive remote notification : %@",userInfo);
}
  • ios8需要在AppDelegate添加此回调方法
1
2
3
4
5
6
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
// 检查当前用户是否允许通知,如果允许就调用 registerForRemoteNotifications
if (notificationSettings.types != UIUserNotificationTypeNone) {
[application registerForRemoteNotifications];
}
}

推送测试客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/*
1.使用时替换deviceToken和passwd的值;
2.证书名为apns-dev.pem,证书与脚本文件在同一目录下
*/

<?php
$deviceToken = 'xxxxxxxxxxx';//5s
$message = '测试推送信息';
$passwd = 'ooooooooooo'
$badge = 'badge';
$mode = 'dev';//这里可以更改是测试还是线上

$body = array("aps" => array("alert" => $message, "badge" => (int)$badge, "sound"=>'default'), "c"=>'3|735|www.baidu.com|1149710');//c为自定义的参数

$ctx = stream_context_create();
$fp;
if($mode == "development") {
stream_context_set_option($ctx, "ssl", "local_cert", "push_cert.pem");
stream_context_set_option($ctx, "ssl", "passphrase", passwd);
$fp = stream_socket_client("ssl://gateway.sandbox.push.apple.com:2195", $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
} else {
stream_context_set_option($ctx, "ssl", "local_cert", "push_cert.pem");
stream_context_set_option($ctx, "ssl", "passphrase", "fslteam");
$fp = stream_socket_client("ssl://gateway.push.apple.com:2195", $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
}

if (!$fp) {
echo "Failed to connect $err $errstrn";
return;
}

if($mode == "dev") {
echo "Connection OK ==> apns_dev.pem ==> ssl://gateway.sandbox.push.apple.com:2195<br>";
} else {
echo "Connection OK ==> apns_pro.pem ==> ssl://gateway.push.apple.com:2195<br>";
}

$payload = json_encode($body);
$msg = chr(0) . pack("n",32) . pack("H*", str_replace(' ', '', $deviceToken)) . pack("n",strlen($payload)) . $payload;
echo "---------------------------------<br>";
echo "Sending token:".$deviceToken.'<br>';
echo "Sending message :" . $payload . "<br>";
echo "---------------------------------<br>";
fwrite($fp, $msg);
fclose($fp);

运行效果

参考文档

iOS手把手教你生成推送证书

ios远程推送和python版push server相关笔记

php pushDemo

ios8推送注册方式的改变

Thank you for your support!