<strong>推送机制:</strong>
1.PHP后台把要发送的消息、目的iPhone的标识打包,发送给APNS(apple推送服务器)
2.APNS在自身的已注册Push服务的iPhone列表中,查找有相应标识的iPhone,并把消息发到iPhone。
3.iPhone把发来的消息传递给相应的应用程序, �程序收到通知。
<strong>流程:</strong>
1,首先创建一个对应的APPID (Registering an App ID),这个和自己项目的Bundle Identifier要相符,不然推送会连接出错。对应了之后,选择服务的时候要勾选PUSH这个,标示这个项目要用到推送。
2,创建开发者的开发证书,证书有开发证书和发布证书,(主要以开发为例,因为开发和发布的证书和配置文件是一样的)。创建的时候注意两点,第一点是选择开发者的推送通知服务,如图:
然后上传自己从电脑里边导出的certSigningRequest文件,最后下载这个证书,双击进行安装。
然后会发现自己电脑钥匙串的证书里边多了一个证书,如图:
导出之后输入一个密码,记住这个密码,后边用,导出之后是一个p12文件,保存起来,最好和刚刚下载的cer这个文件保存在一个文件夹下。
然后打开终端,将cer文件和p12文件分别转换成pem文件: aps_development\ (8).cer是下载的证书文件。DevelopPushP12.p12是从钥匙串导出的p12证书。
openssl x509 -in aps_development\ (8).cer -inform der -out pushDeveCerTopem.pem
openssl pkcs12 -nocerts -out pushDeveP12Topem.pem -in DevelopPushP12.p12
第二次会出现输入密码的界面,就是刚自己导入时候设置的密码,然后会让输入四个字符的新的pem的密码,记住就行了。
然后会看见有两个pem的文件,然后将两个pem文件合并成一个pem文件,也就是将刚刚生成的两个pem合并了:
cat pushDeveCerTopem.pem pushDeveP12Topem.pem > sum.pem
接下来可以测试一下苹果的ssl服务的,也就是APNS的测试服务器:
openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert pushDeveCerTopem.pem -key pushDeveP12Topem.pem
如果出现图中的字样,那么说明配置成功了:
然后进入xcode,记住自己的Bundle Identifier必须和刚刚申请的appid里边的Bundle Identifier匹配,然后选择xcode中这个项目是接收通知的:
然后appdelegate里边:
#import "AppDelegate.h"
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
//判断系统版本,然后进行通知配置,因为ios8以后skd换了
if(SYSTEM_VERSION_LESS_THAN(@"8.0")){
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert];
}else{
//1.创建消息上面要添加的动作(按钮的形式显示出来)
UIMutableUserNotificationAction *action = [[UIMutableUserNotificationAction alloc] init];
action.identifier = @"action";//按钮的标示
action.title=@"Accept";//按钮的标题
action.activationMode = UIUserNotificationActivationModeForeground;//当点击的时候启动程序
// action.authenticationRequired = YES;
// action.destructive = YES;
UIMutableUserNotificationAction *action2 = [[UIMutableUserNotificationAction alloc] init];
action2.identifier = @"action2";
action2.title=@"Reject";
action2.activationMode = UIUserNotificationActivationModeBackground;//当点击的时候不启动程序,在后台处理
action.authenticationRequired = YES;//需要解锁才能处理,如果action.activationMode = UIUserNotificationActivationModeForeground;则这个属性被忽略;
action.destructive = YES;
//2.创建动作(按钮)的类别集合
UIMutableUserNotificationCategory *categorys = [[UIMutableUserNotificationCategory alloc] init];
categorys.identifier = @"alert";//这组动作的唯一标示,推送通知的时候也是根据这个来区分
[categorys setActions:@[action,action2] forContext:(UIUserNotificationActionContextMinimal)];
//3.创建UIUserNotificationSettings,并设置消息的显示类类型
UIUserNotificationSettings *notiSettings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound) categories:[NSSet setWithObjects:categorys, nil]];
[application registerUserNotificationSettings:notiSettings];
}
return YES;
}
#pragma mark - ios8
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
//注册远程通知,ios8以上的注册
[application registerForRemoteNotifications];
}
#pragma mark - ios8 less & < 8.0
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)pToken {
//设备号
NSLog(@"regisger success:%@", pToken);
//注册成功,将deviceToken保存到应用服务器数据库中
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
//接收到通知
NSDictionary *info = [userInfo objectForKey:@"aps"];
// 处理推送消息
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"通知" message:info[@"alert"] delegate:selfcancelButtonTitle:@"取消" otherButtonTitles:nil, nil];
[alert show];
NSLog(@"%@", userInfo);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"Regist fail%@",error);
//通知错误时候代理
}
<strong>服务器:</strong>
将刚刚合成的pem文件和自己要运行的php文件放在同一个文件夹下,服务器代码:
<?php
//手机注册时候返回的设备号,在xcode中输出的,复制过来去掉空格
$deviceToken = ‘70653cf189aeed1fbf207437446b6c9f6dbc406b57de38e52d1667edf1cd8a05‘;
//刚刚合并pem文件时候自己设置的四个字符的密码
$pass = ‘1234‘;
//消息内容
$message = ‘this is my push content!‘.time();
//badge,也就是app中得小红点数
//$badge = 1;
//sound,是提示音, default是代表系统默认的提示音,也就是apple那个来通知的特别俗的提示音
$sound = ‘default‘;
//通知的内容,必须是json
$body = array();
$body[‘aps‘] = array(‘alert‘ => $message);
static $badge=1;
$body[‘aps‘][‘badge‘] = $badge += 1;
if ($sound)
$body[‘aps‘][‘sound‘] = $sound;
//把数组数据转换为json数据
$payload = json_encode($body);
//这个注释的是上线的地址,下边是测试地址,对应的是发布和开发:ssl://gateway.sandbox.push.apple.com:2195这个是沙盒测试地址,ssl://gateway.push.apple.com:2195正式发布地址
//创建推送流,然后配置推送流。
$ctx = stream_context_create();
stream_context_set_option($ctx, ‘ssl‘, ‘local_cert‘, ‘sum.pem‘); //刚刚合成的pem文件
stream_context_set_option($ctx, ‘ssl‘, ‘passphrase‘, $pass);
$fp = stream_socket_client(‘ssl://gateway.sandbox.push.apple.com:2195‘, $err, $errstr, 60,STREAM_CLIENT_CONNECT, $ctx);
if (!$fp) {
print "Failed to connect $err $errstr\n";
return;
}
else {
print "Connection OK\n<br/>";
}
// send message
$msg = chr(0) . pack("n",32) . pack(‘H*‘, str_replace(‘ ‘, ‘‘, $deviceToken)) . pack("n",strlen($payload)) .$payload;
//推送和关闭当前流
fwrite($fp, $msg);
fclose($fp);
?>
然后真机选择在code sign里边选择自己的配置文件,证书不用选择,xcode会自动匹配:
运行自己的app,然后打开终端,进入自己后台服务器的文件夹,运行php文件:
php push.php
如果运行上边服务器的代码,出现Connection OK的字样,说明后台没问题,然后再看看前台时候收到通知。
我这边是接收到了:
<strong>最后看看要注意的几点:</strong>
1,每次的设备号获取之后不能自己在后台手动输入,而是获取之后通过http请求,将设备号发送给服务器,然后让服务器来推,所以项目中获取设备号之后:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)pToken {
NSLog(@"regisger success:%@", pToken);
//注册成功,将deviceToken上传保存到服务器中
AFHTTPRequestOperationManager *Manager = [AFHTTPRequestOperationManager manager];
//这里将pToken进行处理,去掉空格,不写了。
[Manager POST:@"服务器的接受的URL" parameters:@{@"token":pToken}success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"succeed");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"fail");
}];
}
2,小红点问题和跳转问题。当用户进入界面之后,用户离开后台之后小红点的处理。 跳转到指定页面的处理,服务器传来数据,通过客户端判断进行操作,不一一列举。
3,ios 的推送消息有256个字符长度限制;超出范围不能发送 ,且失败。
4,PHP运行的服务器如果没有开通sll模块,不管是apache,还是iis,都要开启这三个模块:
mod_include
mod_cgi
mod_expires
5,php文件在终端中打开,别再浏览器中打开,因为ssl模块不属于服务器的http模块,不开启服务也能推送,这是我试验过的。
6,服务器可以通过不同的身份推送不同的消息给客户端,取决于服务器要什么参数和客户端传什么参数。
7,ios8的注册方法可以这么判断:
#ifdef __IPHONE_8_0
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
[application registerForRemoteNotifications];
}
#endif
8,didFinishLaunchingWithOptions里边的配置应该有点多,不是这么写的应该是,改天改改。ios8步骤就是注册设置,然后注册,这么个流程。
9,推送就是实时通讯。