English 中文(简体)
How to send a push notification using Erlang?
原标题:

I m trying to send a push notification to APNs using Erlang. This is the code I came up with so far:

-module(apnstest2).
-export([connect/0]).

connect() ->
    application:start(ssl),
    ssl:seed("someseedstring"),
    Address = "gateway.sandbox.push.apple.com",
    Port = 2195,
    Cert = "/path/to/Certificate.pem",
    Key = "/path/to/Key.unenc.pem",
    Options = [{certfile, Cert}, {keyfile, Key}, {mode, binary}],
    Timeout = 1000,
    {ok, Socket} = ssl:connect(Address, Port, Options, Timeout),

    Token = "195ec05a962b24954693c0b638b6216579a0d1d74b3e1c6f534c6f8fd0d50d03",
    Payload = "{"aps":{"alert":"Just testing.","sound":"chime", "badge":10}}",
    TokenLength = length(Token),
    PayloadLength = length(Payload),

    Packet = [<<0:8, TokenLength, Token, PayloadLength, Payload>>],

    ssl:send(Socket, list_to_binary(Packet)),
    ssl:close(Socket).

The code doesn t take advantage of Erlang s concurrency but is just a prototype. I only want to test if I can send the push in the most simple way.

I think the problem is in the packet being sent to the APNs. This is the binary format of a push notification:

alt text http://developer.apple.com/IPhone/library/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Art/aps_provider_binary.jpg

How should I create such a packet in Erlang? Could someone please take a look at my code and tell me where the problem is?
Also I used Erlang s SSL application to create the connection and send the data and I don t know if this is the problem or the packet.
Thanks!

最佳回答

To start with, there is no need for creating a list of a single binary and then calling list_to_binary/1 on it. You can just send the binary itself.

Also, make sure the field lengths and values are appropriate according to the protocol:

TokenLength = 32 = length(Token),
Packet = <<0:8, TokenLength:16/big, Token, PayloadLength:16/big, Payload>>,
ssl:send(Socket, Packet),

Now that we have gotten this far, we will see that length(Token) is in fact 64, not 32: You forgot to convert the hex string for Token to a binary, so you are sending a 64 byte hex character string instead of 32 binary bytes.

So... making Payload a binary from the start, and making Token a numeric constant, you can do something like the following:

Payload = <<"{"aps":{"alert":"Just testing.","sound":"chime", "badge":10}}">>,
PayloadLength = size(Payload),
Packet = <<0:8, 32:16/big,
          16#195ec05a962b24954693c0b638b6216579a0d1d74b3e1c6f534c6f8fd0d50d03:256/big,
          PayloadLength:16/big, Payload/binary>>,
ssl:send(Socket, Packet),

Thanks to Christian for pointing out a number of mistakes in the former revisions of this answer.

问题回答

I see two mistakes:

  • Token should be passed in binary and not in hex ascii.
  • You can t use the binary syntax to turn lists into binaries.

For parsing hex to an integer and then down to binary use something like this:

Token = "dead",
TokenNum = erlang:list_to_integer(Token, 16),
TokenBin = <<TokenNum:32/integer-unit:8>>,

Build the protocol packet with something like this:

TokenBin = ...,
Payload = <<"Payload">>,
PayloadSize = byte_size(Payload),
Packet = <<0:8, 32:16, TokenBin/binary, PayloadSize:16, Payload/binary>>,

Try use a simple library epns(Erlang Push Notifications)

This library can send push notification as APNS and FCM by Erlang side. How use epns(Erlang Push Notifications) library - you can read in README.md. This liblary can used as 3-rd party in project, or you can run it locally for see how this library works:

$ git clone https://github.com/vkatsuba/epns.git
$ cd epns
$ make

Retested on Erlang 20~21





相关问题
Printing several binary data fields from Google DataStore?

I m using Google App Engine and python for a web service. Some of the models (tables) I have in my web service have several binary data fields in them, and I d like to present this data to a computer ...

Handling large ActiveRecord object set as binary data

I have an issue with manipulating large number of record objects of type ActiveRecord model(Records are extracted from a complex operation but from the same table) and I want to pass that object set ...

How to send a push notification using Erlang?

I m trying to send a push notification to APNs using Erlang. This is the code I came up with so far: -module(apnstest2). -export([connect/0]). connect() -> application:start(ssl), ssl:...

What is a suitable buffer for Python s struct module

In Python I m accessing a binary file by reading it into a string and then using struct.unpack(...). Now I want to write to that string using struct.pack_into(...), but I get the error "Cannot use ...

Storing hexadecimal values as binary in MySQL

I was thinking about how I m storing passwords in my database : appropriately salted SHA1 strings in a CHAR(40) field. However, since the character data in there is actually just a hex representation ...

View ram in DOS

Is there a way in dos (im using a dos boot disk on a linux machine) to view portions of ram? ie. some form of command to read the binary at a given address? edit: my bootable floppy doesnt have ...

热门标签