Action Push Native is a Rails push notification gem for mobile platforms, supporting APNs (Apple) and FCM (Google).
1. bundle add action_push_native
2. bin/rails g action_push_native:install
3. bin/rails action_push_native:install:migrations
4. bin/rails db:migrateThis will install the gem and run the necessary migrations to set up the database.
The installation will create:
app/models/application_push_notification.rbapp/jobs/application_push_notification_job.rbapp/models/application_push_device.rbconfig/push.yml
app/models/application_push_notification.rb:
class ApplicationPushNotification < ActionPushNative::Notification
# Set a custom job queue_name
queue_as :realtime
# Controls whether push notifications are enabled (default: !Rails.env.test?)
self.enabled = Rails.env.production?
# Define a custom callback to modify or abort the notification before it is sent
before_delivery do |notification|
throw :abort if Notification.find(notification.context[:notification_id]).expired?
end
endUsed to create and send push notifications. You can customize it by subclassing or you can change the application defaults by editing it directly.
app/jobs/application_push_notification_job.rb:
class ApplicationPushNotificationJob < ActionPushNative::NotificationJob
# Enable logging job arguments (default: false)
self.log_arguments = true
# Report job retries via the `Rails.error` reporter (default: false)
self.report_job_retries = true
endJob class that processes the push notifications. You can customize it by editing it directly in your application.
app/models/application_push_device.rb:
class ApplicationPushDevice < ActionPushNative::Device
# Customize TokenError handling (default: destroy!)
# rescue_from (ActionPushNative::TokenError) { Rails.logger.error("Device #{id} token is invalid") }
endThis represents a push notification device. You can customize it by editing it directly in your application.
config/push.yml:
shared:
apple:
# Token auth params
# See https://developer.apple.com/documentation/usernotifications/establishing-a-token-based-connection-to-apns
key_id: <%= Rails.application.credentials.dig(:action_push_native, :apns, :key_id) %>
encryption_key: <%= Rails.application.credentials.dig(:action_push_native, :apns, :encryption_key)&.dump %>
team_id: your_apple_team_id
# Your identifier found on https://developer.apple.com/account/resources/identifiers/list
topic: your.bundle.identifier
google:
# Your Firebase project service account credentials
# See https://firebase.google.com/docs/cloud-messaging/auth-server
encryption_key: <%= Rails.application.credentials.dig(:action_push_native, :fcm, :encryption_key)&.dump %>
# Firebase project_id
project_id: your_project_idThis file contains the configuration for the push notification services you want to use.
The push notification services supported are apple (APNs) and google (FCM).
If you're configuring more than one app, see the section Configuring multiple apps below.
You can send push notifications to multiple apps using different notification classes.
Each notification class need to inherit from ApplicationPushNotification and set self.application, to a key set in push.yml
for each supported platform. You can also (optionally) set a shared application option in push.yml.
This acts as the base configuration for that platform, and its values will be merged (and overridden) with the matching app-specific configuration.
In the example below we are configuring two apps: calendar and email using respectively the
CalendarPushNotification and EmailPushNotification notification classes.
class CalendarPushNotification < ApplicationPushNotification
self.application = "calendar"
# Custom notification logic for calendar app
end
class EmailPushNotification < ApplicationPushNotification
self.application = "email"
# Custom notification logic for email app
endshared:
apple:
# Base configuration for Apple platform
# This will be merged with the app-specific configuration
application:
team_id: your_apple_team_id
calendar:
# Token auth params
# See https://developer.apple.com/documentation/usernotifications/establishing-a-token-based-connection-to-apns
key_id: <%= Rails.application.credentials.dig(:action_push_native, :apns, :calendar, :key_id) %>
encryption_key: <%= Rails.application.credentials.dig(:action_push_native, :apns, :calendar, :encryption_key)&.dump %>
# Your identifier found on https://developer.apple.com/account/resources/identifiers/list
topic: calendar.bundle.identifier
email:
# Token auth params
# See https://developer.apple.com/documentation/usernotifications/establishing-a-token-based-connection-to-apns
key_id: <%= Rails.application.credentials.dig(:action_push_native, :apns, :email, :key_id) %>
encryption_key: <%= Rails.application.credentials.dig(:action_push_native, :apns, :email, :encryption_key)&.dump %>
# Your identifier found on https://developer.apple.com/account/resources/identifiers/list
topic: email.bundle.identifier
google:
calendar:
# Your Firebase project service account credentials
# See https://firebase.google.com/docs/cloud-messaging/auth-server
encryption_key: <%= Rails.application.credentials.dig(:action_push_native, :fcm, :calendar, :encryption_key)&.dump %>
# Firebase project_id
project_id: calendar_project_id
email:
# Your Firebase project service account credentials
# See https://firebase.google.com/docs/cloud-messaging/auth-server
encryption_key: <%= Rails.application.credentials.dig(:action_push_native, :fcm, :email, :encryption_key)&.dump %>
# Firebase project_id
project_id: email_project_iddevice = ApplicationPushDevice.create! \
name: "iPhone 16",
token: "6c267f26b173cd9595ae2f6702b1ab560371a60e7c8a9e27419bd0fa4a42e58f",
platform: "apple"
notification = ApplicationPushNotification.new \
title: "Hello world!",
body: "Welcome to Action Push Native"
notification.deliver_later_to(device)deliver_later_to supports also an array of devices:
notification.deliver_later_to([ device1, device2 ])A notification can also be delivered synchronously using deliver_to:
notification.deliver_to(device)It is recommended to send notifications asynchronously using deliver_later_to.
This ensures error handling and retry logic are in place, and avoids blocking your application's execution.
You can pass custom data to the application using the with_data method:
notification = ApplicationPushNotification
.with_data({ badge: "1" })
.new(title: "Welcome to Action Push Native")You can configure custom platform payload to be sent with the notification. This is useful when you need to send additional data that is specific to the platform you are using.
You can use with_apple for Apple and with_google for Google:
notification = ApplicationPushNotification
.with_apple(aps: { category: "observable", "thread-id": "greeting"}, "apns-priority": "1")
.with_google(data: { badge: 1 })
.new(title: "Hello world!")The platform payload takes precedence over the other fields, and you can use it to override the default behaviour:
notification = ApplicationPushNotification
.with_google(android: { notification: { notification_count: nil } })
.new(title: "Hello world!", body: "Welcome to Action Push Native", badge: 1)This will unset the default notification_count (badge) field in the Google payload, while keeping title
and body.
You can create a silent notification via the silent method:
notification = ApplicationPushNotification.silent.with_data(id: 1).newThis will create a silent notification for both Apple and Google platforms and sets an application
data field of { id: 1 } for both platforms. Silent push notification must not contain any attribute which would trigger
a visual notification on the device, such as title, body, badge, etc.
A Device can be associated with any record in your application via the owner polymorphic association:
user = User.find_by_email_address("jacopo@37signals.com")
ApplicationPushDevice.create! \
name: "iPhone 16",
token: "6c267f26b173cd9595ae2f6702b1ab560371a60e7c8a9e27419bd0fa4a42e58f",
platform: "apple",
owner: userYou can specify Active Record like callbacks for the delivery method. For example, you can modify
or cancel the notification by specifying a custom before_delivery block. The callback has access
to the notification object. You can also pass additional context data to the notification
by adding extra arguments to the notification constructor:
class CalendarPushNotification < ApplicationPushNotification
before_delivery do |notification|
throw :abort if Calendar.find(notification.context[:calendar_id]).expired?
end
end
data = { calendar_id: @calendar.id, identity_id: @identity.id }
notification = CalendarPushNotification
.with_apple(data)
.with_google(data: data)
.new(calendar_id: 123)
notification.deliver_later_to(device)If using the default ApplicationPushDevice model does not fit your needs, you can create a custom
device model, as long as:
- It can be serialized and deserialized by
ActiveJob. - It responds to the
tokenandplatformmethods. - It implements a
pushmethod like this:
class CustomDevice
# Your custom device attributes and methods...
def push(notification)
notification.token = token
ActionPushNative.service_for(platform, notification).push(notification)
rescue ActionPushNative::TokenError => error
# Custom token error handling
end
end| Name | Description |
|---|---|
| :title | The title of the notification. |
| :body | The body of the notification. |
| :badge | The badge number to display on the app icon. |
| :thread_id | The thread identifier for grouping notifications. |
| :sound | The sound to play when the notification is received. |
| :high_priority | Whether the notification should be sent with high priority (default: true). |
| :google_data | The Google-specific payload for the notification. |
| :apple_data | The Apple-specific payload for the notification. It can also be used to override APNs request headers, such as apns-push-type, apns-priority, etc. |
| :data | The data payload for the notification, sent to all platforms. |
| ** | Any additional attributes passed to the constructor will be merged in the context hash. |
| Name | Description |
|---|---|
| :with_apple | Set the Apple-specific payload for the notification. |
| :with_google | Set the Google-specific payload for the notification. It can also be used to override APNs request headers, such as apns-push-type, apns-priority, etc. |
| :with_data | Set the data payload for the notification, sent to all platforms. |
| :silent | Create a silent notification that does not trigger a visual alert on the device. |
Action Push Native is licensed under MIT.