我们的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. Perl碎碎念

    1. 如何去重 #!/usr/bin/perl use strict; my %hash; while(<>){ chomp; print "$_\n" unless ...

  2. EntityFramework 7 Join Count LongCount 奇怪问题(已修复)

    问题说明: 博客问题纪录 Use EF7, Linq Join Count is error EF7 Code Commit EF7 版本(注意 rc): 旧版本:"EntityFramew ...

  3. 关于在用curl函数post网页数据时,遇上表单提交 type为submit 类型而且没有name和id时可能遇到的问题及其解决方法

    curl函数库实现爬网页内容的链接在 http://www.cnblogs.com/linguanh/p/4292316.html 下面这个是没有name和id 标识的 <input type= ...

  4. 魔方渗透系统安装VMtools教程

    虚拟机魔方渗透系统安装VMtools教程 1.开机登陆后,如图点击安装VMtools. 2.进入media文件夹: cd /media   查看mdia文件夹内容: ls   3.打开VMware T ...

  5. JS中的this

    JS中的this 最近在学习JavaScript面向对象,其中有个难点就是关于this的问题. 关于this,我们要知道的两个问题,一个是this指向什么?另一个是this可以写在哪? 关于this的 ...

  6. Hibernate —— HQL、QBC检索方式

    一.HQL 检索方式 以双向的一对多来测试 HQL 检索方式.以 Department 和 Employee 为例. 建表语句: CREATE TABLE department ( dept_id ) ...

  7. iOS阶段学习第33天笔记(自定义标签栏(UITabBar)介绍)

    iOS学习(UI)知识点整理 一.自定义标签栏 1.方法一 单个创建标签栏 #import "AppDelegate.h" #import "SecondViewCont ...

  8. 定制自己的mybatis生成

    MyBatis Generator原生提供的生成方式targetRuntime有几种,但都不符合项目需求或想自定义自己的方法. 网上的文章也很多: 如:http://generator.sturgeo ...

  9. [翻译] Autoac 最佳实践和建议

    使用嵌套的 ILifetimeScope 解析服务 Autofac 被设计为跟踪(track)和清理(dispose)资源.为确保资源被正确处理,务必将长时间运行的应用程序分成小的工作单元 (请求或事 ...

  10. Javascript:Javascript数据类型详解

    要成为一个优秀的前端工程师,系统的学习Javascript,有夯实的Javascript基础,以及对语言本身的深刻的理解,是基本功.从Javascript数据类型开始,我将对Javascript知识体 ...