Pigeon
HTTP2-compliant wrapper for sending iOS and Android push notifications.
Installation
Add pigeon as a mix.exs dependency:
Note: Pigeon's API will likely change until v1.0
def deps do
[{:pigeon, "~> 0.5.0"}]
end
After running mix deps.get, configure mix.exs to start the application automatically.
def application do
[applications: [:pigeon]]
endGCM (Android)
Usage
Set your environment variables.
config :pigeon, gcm_key: "your_gcm_key_here"Create a notification packet.
data = %{ message: "your message" } n = Pigeon.GCM.Notification.new(data, "your device registration ID")Send the packet.
Pigeon.GCM.push(n)
Sending to Multiple Registration IDs
Pass in a list of registration IDs, as many as you want. IDs will automatically be chunked into sets of 1000 before sending the push (as per GCM guidelines).
data = %{ message: "your message" }
n = Pigeon.GCM.Notification.new(data, ["first ID", "second ID"])Notification Struct
When using Pigeon.GCM.Notification.new/2, message_id and updated_registration will always be nil. These keys are set in the response callback. registration_id can either be a single string or a list of strings.
%Pigeon.GCM.Notification{
data: nil,
message_id: nil,
registration_id: nil,
updated_registration_id: nil
}APNS (Apple iOS)
Usage
Set your environment variables. See below for setting up your certificate and key.
config :pigeon, apns_mode: :dev, apns_cert: "cert.pem", apns_key: "key_unencrypted.pem"Create a notification packet. Note: Your push topic is generally the app's bundle identifier.
n = Pigeon.APNS.Notification.new("your message", "your device token", "your push topic")Send the packet.
Pigeon.APNS.push(n)
Generating Your Certificate and Key .pem
In Keychain Access, right-click your push certificate and select "Export..."
Export the certificate as
cert.p12Click the dropdown arrow next to the certificate, right-click the private key and select "Export..."
Export the private key as
key.p12From a shell, convert the certificate.
openssl pkcs12 -clcerts -nokeys -out cert.pem -in cert.p12Convert the key.
openssl pkcs12 -nocerts -out key.pem -in key.p12Remove the password from the key.
openssl rsa -in key.pem -out key_unencrypted.pemcert.pemandkey_unencrypted.pemcan now be used as the cert and key inPigeon.push, respectively. Set them in yourconfig.exs
Notifications with Custom Data
Notifications can contain additional information for the aps key with a map passed as an optional 4th parameter (e.g. setting badge counters or defining custom sounds)
n = Pigeon.APNS.Notification.new("your message", "your device token", "your push topic", %{
badge: 5,
sound: "default"
})Or define custom payload data with an optional 5th parameter:
n = Pigeon.APNS.Notification.new("your message", "your device token", "your push topic", %{}, %{
your-custom-key: %{
custom-value: 500
}
})Handling Push Responses
GCM
Pass an optional anonymous function as your second parameter. This function will get called on each registration ID assuming some of them were successful.
data = %{ message: "your message" } n = Pigeon.GCM.Notification.new(data, "device registration ID") Pigeon.GCM.push(n, fn(x) -> IO.inspect(x) end)Reponses return a tuple of either
{:ok, notification}or{:error, reason, notification}. You could handle responses like so:on_response = fn(x) -> case x do {:ok, notification} -> # Push successful, check to see if the registration ID changed if !is_nil(notification.updated_registration_id) do # Update the registration ID in the database end {:error, :InvalidRegistration, notification} -> # Remove the bad ID from the database {:error, reason, notification} -> # Handle other errors end end data = %{ message: "your message" } n = Pigeon.GCM.Notification.new(data, "your device token") Pigeon.GCM.push(n, on_response)
Notification structs returned as {:ok, notification} will always contain exactly one registration ID for the registration_id key.
For {:error, reason, notification} tuples, this key can be one or many IDs depending on the error. :InvalidRegistration will return exactly one, whereas :AuthenticationError and :InternalServerError will return up to 1000 IDs (and the callback called for each failed 1000-chunked request).
Error Responses
Slightly modified from GCM Server Reference
| Reason | Description |
|---|---|
| :MissingRegistration | Missing Registration Token |
| :InvalidRegistration | Invalid Registration Token |
| :NotRegistered | Unregistered Device |
| :InvalidPackageName | Invalid Package Name |
| :AuthenticationError | Authentication Error |
| :MismatchSenderId | Mismatched Sender |
| :InvalidJSON | Invalid JSON |
| :MessageTooBig | Message Too Big |
| :InvalidDataKey | Invalid Data Key |
| :InvalidTtl | Invalid Time to Live |
| :Unavailable | Timeout |
| :InternalServerError | Internal Server Error |
| :DeviceMessageRateExceeded | Message Rate Exceeded |
| :TopicsMessageRateExceeded | Topics Message Rate Exceeded |
| :UnknownError | Unknown Error |
APNS
Pass an optional anonymous function as your second parameter.
n = Pigeon.APNS.Notification.new("your message", "your device token", "your push topic") Pigeon.APNS.push(n, fn(x) -> IO.inspect(x) end)Responses return a tuple of either
{:ok, notification}or{:error, reason, notification}. You could handle responses like so:on_response = fn(x) -> case x do {:ok, notification} -> Logger.debug "Push successful!" {:error, :BadDeviceToken, notification} -> Logger.error "Bad device token!" {:error, reason, notification} -> Logger.error "Some other error happened." end end n = Pigeon.APNS.Notification.new("your message", "your device token", "your push topic") Pigeon.APNS.push(n, on_response)
Error Responses
Taken from APNS Provider API
| Reason | Description |
|---|---|
| :PayloadEmpty | The message payload was empty. |
| :PayloadTooLarge | The message payload was too large. The maximum payload size is 4096 bytes. |
| :BadTopic | The apns-topic was invalid. |
| :TopicDisallowed | Pushing to this topic is not allowed. |
| :BadMessageId | The apns-id value is bad. |
| :BadExpirationDate | The apns-expiration value is bad. |
| :BadPriority | The apns-priority value is bad. |
| :MissingDeviceToken | The device token is not specified in the request :path. Verify that the :path header contains the device token. |
| :BadDeviceToken | The specified device token was bad. Verify that the request contains a valid token and that the token matches the environment. |
| :DeviceTokenNotForTopic | The device token does not match the specified topic. |
| :Unregistered | The device token is inactive for the specified topic. |
| :DuplicateHeaders | One or more headers were repeated. |
| :BadCertificateEnvironment | The client certificate was for the wrong environment. |
| :BadCertificate | The certificate was bad. |
| :Forbidden | The specified action is not allowed. |
| :BadPath | The request contained a bad :path value. |
| :MethodNotAllowed | The specified :method was not POST. |
| :TooManyRequests | Too many requests were made consecutively to the same device token. |
| :IdleTimeout | Idle time out. |
| :Shutdown | The server is shutting down. |
| :InternalServerError | An internal server error occurred. |
| :ServiceUnavailable | The service is unavailable. |
| :MissingTopic | The apns-topic header of the request was not specified and was required. The apns-topic header is mandatory when the client is connected using a certificate that supports multiple topics. |