iOS消息推送的工作机制如下:

wKioL1Sriw2ye4IKAAB6HmGJY1g952.jpg

Provider是指某个iPhone软件的Push服务器,APNS是Apple Push Notification Service的缩写,是苹果的服务器。

 上图可以分为三个阶段:

第一阶段:应用程序把要发送的消息、目的iPhone的标识打包,发给APNS。 

第二阶段:APNS在自身的已注册Push服务的iPhone列表中,查找有相应标识的iPhone,并把消息发送到iPhone。 

第三阶段:iPhone把发来的消息传递给相应的应用程序,并且按照设定弹出Push通知。

实现的很简单,很环保.原理如下

  • 财大气粗的苹果提供了一堆服务器,每个ios设备和这些服务器保持了一个长连接,ios版本更新提示,手机时钟校准什么的都是通过这个连接.

  • 苹果把这个长连接开放出来给大家推送消息用,很积德,因为这是个全球服务,几十亿台ios设备,服务器少说也需要上万台,还没有钱可以赚. andorid的爸爸就不做这个,于是各个app为了发消息,只能直接拼命赖在后台维持一个长连接,电就是这样被耗光的

  • 苹果提供消息服务简称为APNS,只是是长连接机器的一部分,你要向你的用户发消息,必须通过apns中转,你写程序发给它,它转发给你的手机,你的推送程序和用户手机没有直接联系

  • 消息推送不支持群发,只能一个一个发.如果你的App有100万个用户,要发消息怎么办? 一个一个的发呗,发100万次.消息包大概包括两部分:标示用户手机的id(32个字节)+消息体(<=256Bytes),消息体是json字符串,传输过程用ssl加密的

  • 标示用户手机的ID 叫做 device tokens,每个手机都不一样,deviceToken非常重要

app支持推送的技术实现

要实现推送功能,你需要干如下几件事情

  1. 你需要写3段程序

  2. 到苹果开发者中心注册一次,并下载一份cer文件

  3. 从苹果的Provisioning Portal,填写并下载一个Provisioning Profile

先说2,3两点

  • 下载cer文件,是推送程序要用,因为要通过ssl信道发送数据

  • 填写并下载Provisioning Profile,并从xcode加入到你的app项目文件中,你可以理解为办手续,总不能无证乱发吧,

需要写的3段程序分别是

  1. 前文提到的保存device token的代码,很简单的,随便搭个http服务,用mysql建个表,你在app里面用http post提交就行

  2. 第二段程序是:你的app必须做个标记,告诉ios,你会给用户产生推送消息,这个代码很简单,一句话搞定

     [[UIApplication sharedApplication] registerForRemoteNotificationTypes:
         (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];

    加在app初始化函数里面即可


  3. 最后是:推送程序,这个代码量可能最多.逻辑很简单:遍历你的存放devictTokent的数据表,逐一发消息给苹果的APNS服务器.推送程序,有很多开源代码,用APNS为关键词,

    ****************服务器端push.php**************** 


     
    //手机注册应用返回唯一的deviceToken 
    $deviceToken = 'eb87b209 6395a040 a1cf85e5 15b6e972 20ec883f 6b3ac80f 02b92a1a 58cf273e'; 
    //ck.pem通关密码 
    $pass = '13!@#23';    
    //消息内容 
    $message = '这是一条推送测试通知1'.time(); 
    //badge我也不知是什么 
    //$badge = 1; 
    //sound我也不知是什么(或许是推送消息到手机时的提示音) 
    $sound = 'Duck.wav'; 
    //建设的通知有效载荷(即通知包含的一些信息) 
    $body = array(); 
    $body['aps'] = array('alert' => $message); 
    //if ($badge) 
    //  $body['aps']['badge'] = $badge; 
    if ($sound) 
      $body['aps']['sound'] = $sound; 
    //把数组数据转换为json数据 
    $payload = json_encode($body); 
    echo strlen($payload),"\r\n"; 


    //下边的写法就是死写法了,一般不需要修改, 
    //唯一要修改的就是: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', dirname(__FILE__) . '\\' . 'dev_ck.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
    "; 

    } 
    // send message 
    $msg = chr(0) . pack("n",32) . pack('H*', str_replace(' ', '', $deviceToken)) . pack("n",strlen($payload)) . $payload; 
    print "Sending message :" . $payload . "\n";   
    fwrite($fp, $msg); 
    fclose($fp); 
    ?> 


    php服务端如果出问题,请检查是否开通ssl模块 
    Apache需要开启ssl模块,通过查看Apache的官方文档得知,使用ssl需要Apache开启三个支持模块分别是: 
    mod_include 
    mod_cgi 
    mod_expires 
    *注意:ios 的推送消息有256个字符长度限制;超出范围不能发送