ejabberd: Apple Push Notification Service
主要是通过 hook ejabberd 的离线消息处理,从而实现针对离线消息进行推送
1. Hook offline message
记录 device token
这一步没啥好说的,iOS 连接到 APNs 后获取到 device token,发给服务器,服务器负责维护好对应关系即可。
注意客户端退出时清理掉相应记录。在 ejabberd 中新增一个模块,注册
offline_message_hook
,大致如下:start(Host, Opts) -> ?INFO_MSG("Starting mod_push_service", []), register(?MODULE, spawn(?MODULE, init, [Host, Opts])), ok. init(Host, _Opts) -> ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, send_notification, 10), ok. stop(Host) -> ?INFO_MSG("Stopping mod_push_service", []), ejabberd_hooks:delete(offline_message_hook, Host, ?MODULE, send_notification, 10), ok. send_notification(From, To, Packet) -> dosomething.
2. Implement APNs
从 Apple 获取推送证书
在服务端使用该证书建立 ssl 连接
按照 Apple 文档生成指定格式的 Payload 并发送
Apple 同时提供了 feedback channel 来获取失效 token 便于服务端获取记录,实现方式和发送消息类似,区别在于一个是发送消息,一个是接收消息
连接的粗略代码如下
-module(apntest). -export([connect/0]). connect() -> application:start(asn1), application:start(crypto), application:start(public_key), application:start(ssl), Address = "gateway.sandbox.push.apple.com", Port = 2195, Cert = "cert.pem", Options = [{certfile, Cert}, {mode, binary}], Timeout = 10000, case ssl:connect(Address, Port, Options, Timeout) of {ok, Socket} -> PayloadString = "{\"aps\":{\"alert\":\"Hello world.\",\"sound\":\"chime\", \"badge\":1}}", Payload = list_to_binary(PayloadString), PayloadLength = size(Payload), Packet = <<0:8, 32:16/big, 16#ff496f96352abb7c875bedfc755287XXXXXXe14bfadade9ff6ba75360de65441:256/big, PayloadLength:16/big, Payload/binary>>, ssl:send(Socket, Packet), ssl:close(Socket), PayloadString; {error, Reason} -> Reason end.
有一些开源的 Erlang APNs 推送服务实现,比如 apns4erl,不过这个项目实在引用了太多不必要的东西了 XD,还是推荐自己看懂后根据需求重新实现,代码也不复杂