我们的IOS移动应用要实现消息推送,告诉用户有多少条消息未读,类似下图的效果(笑果),特把APNS和Erlang相关解决方案笔记于此备忘.
 
   
   上面图片中是Apple Notification在UI展现的形式之一,Notification共有三种形式:图标显示更新数字(badge),提示信息(alert),提示音(sound);
 
   iOS Apple Push Notification Services (APNs)官方的开发文档位置在:[Apple Push Notification Services],iOS团队的Matthijs Hollemans写的入门文档:Apple Push Notification Services in iOS 6 Tutorial 从这两份文档中,可以了解APNs的设计和开发的各种细节.首先是APNS的设计初衷:当用户没有启动应用,或者没有开机那么应用Server想要推送的消息就无法到达,需要其他的机制来完成消息的投递.
 
  Apple Push Notification service (APNs)把消息推送到设备上,设备上有应用已经注册过要接受此类消息.这里会有三种角色:Provider, APNs,Device . 见下图:
 
   
  
 
     上图说明:消息提供者(Provider),Provider接入到APNs,把最新的消息推送到 APNs,然后由APNs推送到目标设备(Device)的指定应用(Client APP).
 
      从上面的图,可以提出很多问题,特别是考虑到一些极端情况的时候,很有意思,可以通过这些问题驱动阅读Apple开发文档:
  1. Provider,APNs,Device 这三者之间的信任关系是怎么建立?
  2. 如何标识消息是给哪台机器的哪个应用的?消息传递的协议是怎么设计的(如何承载要发送的消息)?
  3. 在Device离线的情况下,Provider提交N条要发送给该Device的消息到APNs,APNs如何处理?
  4. 对于一些极端情况:比如Device做了系统恢复,应用卸载,Device硬件损坏,APNs有哪些应对机制?
  
    首先解决三者的信任关系,Provider(APP Server)的开发方要从Apple Dev Center获得SSL证书, 每个证书一个应用,甚至开发和生产环境的证书都要分别申请. Provider要在APNs中进行认证注册,目前注册使用的是应用程序的唯一标识(bundle identifier).Provider Connection的是对应到指定应用的,certificate中包含了应用程序的标识信息(bundle ID),APNs维护了一个废弃列表,如果一个Provider上了名单,APNs就会移除对该应用的信任. Provider和APNs通信协议是二进制协议,使用TCP流协议建立SSL(TLS)安全连接,官方文档称这种信任为Connection Trust. 
 
    对于用户设备APNs使用的是Token Trust.用户安装一个APP的时候,如果APP需要消息推送功能通常在安装成功之后会经由用户设备发起注册请求,用户设备将此请求转发到APNs, APNs生成唯一的device certificate,其中包含了device token.Device Token 中包含了设备的唯一标识,使用Token key加密Device Token返回到Device.用户设备把device token返回给发起注册请求的应用程序,应用程序把Device Token的信息传递给Provider.用户设备上安装的APP从APNs 获得device token之后每一次连接到ANPs都要提供这个token. APNs解密device token并验证这个token是从连接过来的设备生成的:APNs保证实际连接过来的设备标识和certificate文件中里面包含的标识一致.
 
   Provider提交到APNS的notification两个必要的信息:把什么消息投递给谁,即包含设备标识(Device Token)和实际消息体(Payload).APNS使用token Key解密token,从中提取设备ID来决定最终消息投递到哪个设备.Device Token有一个非常贴切的类比:手机号,它包含的信息可以让APNs来定位安装了指定应用的设备.APNs还使用Device Token来路由消息,Payload的消息组织形式是类JSON的,它包含的信息包括推送给设备什么内容以及如何提示;Payload内容大小限制是 256 bytes.
  注意:Device Token和设备的UDID不是一回事,用户恢复系统,重装都会导致device token变化.
 
    APNs有一个 Feedback Service的设计,它维护应用消息推送失败的设备列表,如果应用已经卸载了就无法投递成功,这样Feedback Service里面就会有记录.Provider的开发方应定期从该服务拉取这个失败列表来调整自己的发送行为:不要再给一个总是失败的设备推送消息了.如果设备离线,notification会在APNs上保存有限的一段时间,设备上线之后完成推送.如果设备离线期间同一个应用推送了多条notification,那么只会保存最新的notification,如果设备长期离线,任何离线消息都会被抛弃掉.这样如果iPhone掉海里面,需要推送给它的消息在过期之后就会被清理掉,不会长久占用APNs的资源.
 
 
  
 
经过上面的分析基本可以列出Erlang实现消息推送的技术要点了:
[1] JSON数据解析构造 mochijson mochijson2之类的模块就可以搞定  mochijson:encode --> list_to_binary
[3] 二进制协议实现 (Apple Binary Iterface)
Packet = [<<1:8, MsgId/binary, Expiry:4/big-unsigned-integer-unit:8,
                32:16/big,
                BinToken/binary,
                PayloadLength:16/big,
                BinPayload/binary>>]
 
[4] deviceToken -> binary 需要hexstr_to_bin的方法,这个代码片段之前说过多次了
bin_to_hexstr(Bin) ->
lists:flatten([io_lib:format("~2.16.0B", [X]) ||
X <- binary_to_list(Bin)]). hexstr_to_bin(S) ->
hexstr_to_bin(S, []).
hexstr_to_bin([], Acc) ->
list_to_binary(lists:reverse(Acc));
hexstr_to_bin([X,Y|T], Acc) ->
{ok, [V], []} = io_lib:fread("~16u", [X,Y]),
hexstr_to_bin(T, [V | Acc]).
[5] 维护TCP连接,重连机制
 
按照上面的要点完成了基本的验证之后,在Github上找到了开源项目apns4erl (地址:https://github.com/inaka/apns4erl),这个项目对APNS服务做了良好的实现和封装.下面介绍下apns4erl的使用:
 
 

开源项目APNS4erl

 
证书制作:
  APP Server和Apple Server中间建立信任关系需要通过各种证书,apns4erl作者在项目中提供了生成证书的脚本,不过在项目首页提到.cer和.p12文件生成pem证书的脚本地址是错的,实际位置是:
 
执行下面的脚本就一步一步即可:

#!/bin/sh

# Usage:
# test_certs {cert_file} {private_key_file}
# Example:
# test_certs aps_developer_indetity.cer aps_developer_identity.p12 mkdir -p priv/temp
openssl pkcs12 -in "$2" -out priv/temp/key-enc.pem
openssl rsa -in priv/temp/key-enc.pem -out priv/temp/key.pem
openssl x509 -inform der -in "$1" -out priv/temp/cert.pem
cat priv/temp/cert.pem priv/temp/key.pem > priv/cert.pem
rm -rf priv/temp
make test
下面是测试代码,注意send_badge/1方法就是我们需要的效果:
-module(t).
-compile(export_all).
-define(APNS_NAME,app_apns). -include("apns.hrl").
-include("localized.hrl"). conn_apns() ->
ssl:start(),
apns:start(),
apns:connect(
?APNS_NAME,
fun handle_apns_error/,
fun handle_apns_delete_subscription/
). send_message()->
apns:send_message(?APNS_NAME, "devicetoken31d1df3a324bb72c1ff2bcb3b87d33fd1a2b7578b359fb5494eff", "hello,这是一号话务员"). send_message(Msg) ->
apns:send_message(my_connection_name, #apns_msg{
alert = Msg ,
badge = ,
sound = "beep.wav" ,
expiry = ,
device_token = "devicetoken31d1df3a324bb72c1ff2bcb3b87d33fd1a2b7578b359fb5494eff"
}). send_badge(Number)->
apns:send_badge(qiaoqiao_apns,"devicetoken31d1df3a324bb72c1ff2bcb3b87d33fd1a2b7578b359fb5494eff", Number). handle_apns_error(MsgId, Status) ->
error_logger:error_msg("error: ~p - ~p~n", [MsgId, Status]). handle_apns_delete_subscription(Data) ->
error_logger:info_msg("delete subscription: ~p~n", [Data]).
APNS相关资料:
 
 
[0] iOSDeveloper Library: Apple Push Notification Service (APNS)
 
[1] Apple Push Notification Services in iOS 6 Tutorial
 
[2]  Apple Push Notification Services in iOS 6 Tutorial 中文
 http://www.raywenderlich.com/zh-hans/24732
 
[3] iOS 和 Android 的后台推送原理各是什么?有什么区别?
 
[4] 苹果产品是如何实现推送功能的呢?
 
[5] 为什么 Android 的后台推送不如 iOS 的推送使用广泛?
 
[6]  Is the device token as unique as the device ID?
 
[7]  If the user restores backup data to a new device or computer, or reinstalls the operating system, the device token changes. https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/IPhoneOSClientImp.html
 
[8] Apple Push Notifications with Erlang
 
[9] Sending Apple Push Notifications with Erlang
 
最后小图一张:
 

[Erlang 0106] Erlang实现Apple Push Notifications消息推送的更多相关文章

  1. 使用Google Cloud Messaging (GCM),PHP 开发Android Push Notifications (安卓推送通知)

    什么是GCM? Google Cloud  Messaging (GCM) 是Google提供的一个服务,用来从服务端向安卓设备发送推送通知. GCM分为客户端和服务端开发. 这里我们只介绍服务端开发 ...

  2. (转)在SAE使用Apple Push Notification Service服务开发iOS应用, 实现消息推送

    在SAE使用Apple Push Notification Service服务开发iOS应用, 实现消息推送 From: http://saeapns.sinaapp.com/doc.html 1,在 ...

  3. Push:iOS基于APNS的消息推送

    1. Push的三个步骤,如下图所示: (1)Push服务应用程序把要发送的消息.目的iPhone的标识打包,发给APNS: (2)APNS在自身的已注册Push服务的iPhone列表中,查找有相应标 ...

  4. [置顶] 手把手教你iOS消息推送证书生成以及Push消息

    iOS推送消息是许多iOS应用都具备的功能,今天在给应用加推送功能,在生成证书的过程中,发生了各种令人蛋痛的事.下面就把步骤拿出来分享下: iOS消息推送的工作机制可以简单的用下图来概括: Provi ...

  5. 了解iOS消息推送一文就够:史上最全iOS Push技术详解

    本文作者:陈裕发, 腾讯系统测试工程师,由腾讯WeTest整理发表. 1.引言 开发iOS系统中的Push推送,通常有以下3种情况: 1)在线Push:比如QQ.微信等IM界面处于前台时,聊天消息和指 ...

  6. 为友盟消息推送开发的PHP SDK(composer版):可以按省发Android push

    一直以来APP希望按省市县推送Android push,只能自己分析用户经纬度,打tag发送. 现在终于有服务商提供了. 友盟消息推送 可以“按省推送”,很方便. 我为友盟做了PHP SDK(comp ...

  7. 带你了解什么是Push消息推送

    前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 如果有看我最近文章的同学可能就知道我在公司负责的是一 ...

  8. APP消息推送机制的实现(PUSH)

    出于好奇,想了解一下消息推送机制,在网上搜索到了几篇文章,感觉还不错,粘贴下来,等真正用到的时候再仔细研究 以下两篇是关于ios的 1.http://blog.csdn.net/xyxjn/artic ...

  9. 采用MQTT协议实现android消息推送(2)MQTT服务端与客户端软件对比、android客户端示列表

    1.服务端软件对比 https://github.com/mqtt/mqtt.github.io/wiki/servers 名称(点名进官网) 特性 简介 收费 支持的客户端语言 IBM MQ 完整的 ...

随机推荐

  1. C算法编程题(四)上三角

    前言 上一篇<C算法编程题(三)画表格> 上几篇说的都是根据要求输出一些字符.图案等,今天就再说一个“上三角”,有点类似于第二篇说的正螺旋,输出的字符少了,但是逻辑稍微复杂了点. 程序描述 ...

  2. JavaScript框架设计(三) push兼容性和选择器上下文

    JavaScript框架设计(三) push兼容性和选择器上下文 博主很久没有更博了. 在上一篇 JavaScript框架设计(二) 中实现了最基本的选择器,getId,getTag和getClass ...

  3. 安装nginx

    [yum安装nginx] yum clean all(这步不执行会出现no more mirrors to try错误) cd /etc/yum.repos.d/ vi nginx.repo 填写 [ ...

  4. php isset( $test ) 的神奇之处。

    很久一段时间没更新博客了,由于近段时间一直在忙 挑战杯 的项目,所以没怎样把一些总结放上来.这次,总结下 php 的一个 函数 : boolean isset($test), 返回值:boolean类 ...

  5. norflash驱动编写笔记

    [部分转自]http://blog.csdn.net/ziyiyunmen/article/details/9744901 1. 读数据 md.b 0 2. 读ID NOR手册上: 往地址555H写A ...

  6. jquery技巧之让任何组件都支持类似DOM的事件管理

    本文介绍一个jquery的小技巧,能让任意组件对象都能支持类似DOM的事件管理,也就是说除了派发事件,添加或删除事件监听器,还能支持事件冒泡,阻止事件默认行为等等.在jquery的帮助下,使用这个方法 ...

  7. 在 Git 中 Checkout 历史版本

    昨天写代码的时候,误删了一个文件.今天发现的时候,commit 已经 push 到版本库了.本想用 git reset 回退版本,找回文件后重新提交.但是想起 Git 是一个版本控制系统哎,直接从版本 ...

  8. 纯CSS3实现动态火车行驶特效

    上次开完飞机,这次开火车 查看效果:http://hovertree.com/texiao/css3/7/ 效果图: 代码如下: <!DOCTYPE html> <html> ...

  9. 关于项目中值对象Identifier的设计-领域驱动

    到现在为止做了不项目,发现每个实体都会有个相应的值对象. 先简单说一下值对象和实体之间的区别: (以下内容来着<领域驱动设计>一书) 当一个小孩画画的时候,他注意的是画笔的颜色和笔尖的粗细 ...

  10. 【Java每日一题】20161214

    package Dec2016; import java.util.ArrayList; import java.util.List; public class Ques1214 { public s ...