{"id":13509427,"url":"https://github.com/chvanikoff/apns4ex","last_synced_at":"2025-10-21T18:54:37.854Z","repository":{"id":57499540,"uuid":"42089133","full_name":"chvanikoff/apns4ex","owner":"chvanikoff","description":"APNS for Elixir","archived":false,"fork":false,"pushed_at":"2017-05-22T16:46:42.000Z","size":99,"stargazers_count":70,"open_issues_count":6,"forks_count":23,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-19T20:16:14.718Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chvanikoff.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-09-08T03:59:06.000Z","updated_at":"2024-04-18T15:27:50.000Z","dependencies_parsed_at":"2022-08-28T15:22:29.313Z","dependency_job_id":null,"html_url":"https://github.com/chvanikoff/apns4ex","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chvanikoff%2Fapns4ex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chvanikoff%2Fapns4ex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chvanikoff%2Fapns4ex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chvanikoff%2Fapns4ex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chvanikoff","download_url":"https://codeload.github.com/chvanikoff/apns4ex/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246324015,"owners_count":20759062,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T02:01:07.563Z","updated_at":"2025-10-21T18:54:32.799Z","avatar_url":"https://github.com/chvanikoff.png","language":"Elixir","funding_links":[],"categories":["Third Party APIs","Elixir"],"sub_categories":[],"readme":"# APNS\n\nThe library was inspired by [Apns4erl](https://github.com/inaka/apns4erl)\n\n## Warning\n\nThe older version of the library is available in `0.0.x-stable` branch\n\n## Installation\n\n  1. Add apns to your list of dependencies in mix.exs:\n\n        def deps do\n          [{:apns, \"~\u003e 0.9.6\"}]\n        end\n\n  2. Ensure apns is started before your application:\n\n        def application do\n          [applications: [:apns]]\n        end\n\n## Usage\n\nConfig the APNS app and define pools\n\n```elixir\nconfig :apns,\n  # Here goes \"global\" config applied as default to all pools started if not overwritten by pool-specific value\n  callback_module:    APNS.Callback,\n  timeout:            30,\n  feedback_interval:  1200,\n  support_old_ios:    true,\n  expiry:    60,\n  # Here are pools configs. Any value from \"global\" config can be overwritten in any single pool config\n  pools: [\n    # app1_dev_pool is the pool_name\n    app1_dev_pool: [\n      env: :dev,\n      pool_size: 10,\n      pool_max_overflow: 0,\n      certfile: \"/path/to/cert.pem\",\n      keyfile: \"/path/to/key.pem\"\n    ],\n    app1_prod_pool: [\n      env: :prod,\n      certfile: \"/path/to/cert.pem\",\n      keyfile: \"/path/to/key.pem\",\n      pool_size: 100,\n      pool_max_overflow: 0\n    ],\n  ]\n```\n\n### Config keys\n\n| Name              | Default value | Description                                                                                                      |\n|:------------------|:--------------|:-----------------------------------------------------------------------------------------------------------------|\n| cert              | nil           | Plaintext APNS certfile content (not needed if `certfile` is specified)                                          |\n| certfile          | nil           | Path to APNS certificate file or a tuple like `{:my_app, \"certs/cert.pem\"}`                                      |\n|                   |               | which will use a path relative to the `priv` folder of the given application (not needed if `cert` is specified) |\n| cert_password     | nil           | APNS certificate password (if any)                                                                               |\n| key               | nil           | Plaintext APNS keyfile content (not needed if `keyfile` is specified)                                            |\n| keyfile           | nil           | Path to APNS keyfile (not needed if `key` is specified)                                                          |\n| callback_module   | APNS.Callback | This module will receive all error and feedback messages from APNS                                               |\n| timeout           | 30            | Connection timeout in seconds                                                                                    |\n| feedback_interval | 1200          | The app will check Apple feedback server every `feedback_interval` seconds                                       |\n| support_old_ios   | true          | Push notifications are limited by 256 bytes (2kb if false), this option can be changed per message individually  |\n| expiry            | 60            | Seconds Apple will re-try to deliver the push notification*                                                      |\n| pools             | []            | List of pools to start                                                                                           |\n\n\\* It should be noted that Apple will always try to deliver the message at least once. If it takes longer to send the message to Apple than the expiry offset it will still be delivered.\n\n### Pool keys\n\n| Pool key          | Description                                                                  |\n|:------------------|:-----------------------------------------------------------------------------|\n| env               | :dev for Apple sandbox push server or :prod for Apple production push server |\n| pool_size         | Maximum pool size                                                            |\n| pool_max_overflow | Maximum number of workers created if pool is empty*                          |\n\n\\* WARNING: According to our tests a overflow other then zero is bad.\n\nAll pools defined in config will be started automatically\n\nFrom here and now you can start pushing your PNs via APNS.push/2 and APNS.push/3:\n```Elixir\nmessage = APNS.Message.new\nmessage = message\n|\u003e Map.put(:token, \"0000000000000000000000000000000000000000000000000000000000000000\")\n|\u003e Map.put(:alert, \"Hello world!\")\n|\u003e Map.put(:badge, 42)\n|\u003e Map.put(:extra, %{\n  \"var1\" =\u003e \"val1\",\n  \"var2\" =\u003e \"val2\"\n})\nAPNS.push :app1_dev_pool, message\n```\nor\n```Elixir\nAPNS.push :app1_prod_pool, \"0000000000000000000000000000000000000000000000000000000000000000\", \"Hello world!\"\n```\n\n## Handling APNS errors and feedback\n\nYou can define a callback handler module via config param `callback_module`. The module should implement 2 functions:\n\n* `error/2` which receives `%APNS.Error{}` and `token`\n* `feedback/1` which receives `%APNS.Feedback{}`\n\n```elixir\n  defmodule APNS.Callback do\n    def error(error = %APNS.Error{}, token) do\n      # handle error\n    end\n\n    def feedback(feedback = %APNS.Feedback{}) do\n      # handle feedback\n    end\n  end\n```\n\n\n## Structs\n\n- %APNS.Message{}\n```elixir\ndefstruct [\n  id: nil,\n  expiry: 60,\n  token: \"\",\n  content_available: nil,\n  alert: \"\",\n  badge: nil,\n  sound: \"default\",\n  mutable_content: nil,\n  priority: 10,\n  extra: [],\n  support_old_ios: nil\n]\n```\n- %APNS.Error{}\n```elixir\ndefstruct [\n  message_id: nil,\n  status: nil,\n  error: nil\n]\n```\n- %APNS.Feedback{}\n```elixir\ndefstruct [\n  time: nil,\n  token: nil\n]\n```\n- %APNS.Message.Loc{}\n```elixir\ndefstruct [\n  title: \"\",\n  body: \"\",\n  title_loc_key: nil,\n  title_loc_args: nil,\n  action_loc_key: nil,\n  loc_key: \"\",\n  loc_args: [],\n  launch_image: nil\n]\n```\n\n## Contribute\n\n    git clone git@github.com:chvanikoff/apns4ex.git\n    # update config/config.exs with the path to your cert (do not use your live cert)\n    mix test\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchvanikoff%2Fapns4ex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchvanikoff%2Fapns4ex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchvanikoff%2Fapns4ex/lists"}