Action Push Native

repository·main·Indexed 19 days ago

https://github.com/rails/action_push_native

A Rails gem providing a unified interface for sending push notifications to mobile devices via APNs (Apple) and FCM (Google). It features asynchronous delivery via ActiveJob, support for multiple app configurations in push.yml, silent notifications, and platform-specific payload overrides. The library includes structured error handling for provider responses and Active Support instrumentation for monitoring delivery round trips.

Tokens
5.1K
Snippets
18
Records
23
Agent score
67%

What's inside action_push_native

  1. Configure multiple apps in push.yml

    main

    To support multiple apps (e.g., a 'calendar' app and an 'email' app), define unique keys in config/push.yml under the platform section (apple or google). You can also define a shared configuration for a platform that gets merged into app-specific settings.

    In your notification classes, set self.application to match the key used in push.yml.

    class CalendarPushNotification < ApplicationPushNotification
      self.application = "calendar"
    end
    shared:
      apple:
        application:
          team_id: your_apple_team_id
        calendar:
          key_id: <%= ... %>
          topic: calendar.bundle.identifier
  2. Install Action Push Native

    main

    To install the gem and set up the necessary database migrations, run the following commands in your terminal:

    bundle add action_push_native
    bin/rails g action_push_native:install
    bin/rails action_push_native:install:migrations
    bin/rails db:migrate
  3. Configure Token Authentication Parameters

    main
    When setting up connections to APNs (Apple Push Notification service), ensure you provide the necessary token authentication parameters as required by Apple's documentation for establishing a token-based connection.
  4. Configure Action Push Native

    main

    The installation generates several files that you can customize to control notification behavior:

    app/models/application_push_notification.rb

    Used to create and send notifications. You can:

    • Set a custom job queue using queue_as :queue_name.
    • Enable/disable notifications using self.enabled = boolean (defaults to !Rails.env.test?).
    • Use before_delivery callbacks to modify or abort a notification before it is sent.

    app/jobs/application_push_notification_job.rb

    Processes the push notifications. You can:

    • Enable argument logging with self.log_arguments = true (defaults to false).
    • Report retries via Rails.error with self.report_job_retries = true (defaults to false).

    app/models/application_push_device.rb

    Represents a push notification device. You can customize TokenError handling here (default is destroy!).

    config/push.yml

    Contains service credentials for apple (APNs) and google (FCM).

  5. Use delivery callbacks in ActionPushNative::Notification

    main

    The ActionPushNative::Notification class extends ActiveModel::Callbacks and defines delivery callbacks. You can use these to run logic (like logging or modifying the notification) immediately before or after a notification is delivered via deliver_to.

    To use them, define your logic within the delivery callback lifecycle in your notification subclass.

    class MyNotification < ActionPushNative::Notification
      define_model_callbacks :delivery
    
      after_delivery do
        Rails.logger.info "Notification delivered!"
      end
    end
  6. How platform and application configuration works

    main

    The library uses a hierarchical configuration lookup via ActionPushNative.config_for(platform, notification):

    1. Platform Level: It first looks up the configuration for the specified :platform (e.g., :apple).
    2. Application Level: If the notification.application is present, it looks for a key matching that application name within the platform configuration.
    3. Merging: It merges the application-specific settings into the base :application configuration block of that platform. This allows you to define common platform settings under an :application key and override them for specific apps.

    If the platform is not configured in config/push.yml, an error is raised.

  7. Implement a custom Device model

    main

    If ApplicationPushDevice does not meet your needs, you can use a custom class. The custom object must:

    1. Be serializable/deserializable by ActiveJob.
    2. Respond to token and platform methods.
    3. Implement a push(notification) method.
    class CustomDevice
      def token; @token; end
      def platform; @platform; end
    
      def push(notification)
        notification.token = token
        ActionPushNative.service_for(platform, notification).push(notification)
      rescue ActionPushNative::TokenError => error
        # Custom token error handling
      end
    end
  8. Send push notifications to devices

    main

    You can deliver notifications to a single device or an array of devices. It is highly recommended to use deliver_later_to for asynchronous delivery to ensure retry logic and error handling are utilized.

    • deliver_later_to(device): Asynchronous delivery (recommended).
    • deliver_later_to([device1, device2]): Asynchronous delivery to multiple devices.
    • deliver_to(device): Synchronous delivery.
    device = ApplicationPushDevice.create!(name: "iPhone", token: "token", platform: "apple")
    
    notification = ApplicationPushNotification.new(
      title: "Hello world!",
      body: "Welcome to Action Push Native"
    )
    
    # Recommended
    notification.deliver_later_to(device)
    
    # Or multiple
    notification.deliver_later_to([device1, device2])
    
    # Synchronous
    notification.deliver_to(device)
  9. Use `before_delivery` callbacks

    main

    You can define Active Record-style callbacks in your notification class to modify or abort delivery. The callback block receives the notification object. You can access extra context passed during initialization via notification.context.

    class CalendarPushNotification < ApplicationPushNotification
      before_delivery do |notification|
        # Abort if the calendar is expired
        throw :abort if Calendar.find(notification.context[:calendar_id]).expired?
      end
    end
    
    # Usage with context
    data = { calendar_id: 123 }
    notification = CalendarPushNotification.with_apple(data).new(calendar_id: 123)
    notification.deliver_later_to(device)
  10. Create silent notifications

    main

    Silent notifications can be created using the .silent method. This creates a notification for both Apple and Google that does not trigger a visual alert (no title, body, or badge). You can still attach data using .with_data.

    notification = ApplicationPushNotification.silent.with_data(id: 1).new
  11. Add custom data and platform-specific payloads

    main

    You can enrich notifications with custom data or platform-specific overrides.

    Application Data

    Use .with_data(hash) to pass custom data to the application.

    Platform Payloads

    Use .with_apple(payload_hash) for APNs or .with_google(payload_hash) for FCM. Platform payloads take precedence and can override default fields like badge or notification_count.

    # Adding custom data
    notification = ApplicationPushNotification
      .with_data({ badge: "1" })
      .new(title: "Welcome")
    
    # Adding platform-specific payloads
    notification = ApplicationPushNotification
      .with_apple(aps: { category: "observable" }, "apns-priority": "1")
      .with_google(data: { badge: 1 })
      .new(title: "Hello world!")
    
    # Overriding default behavior with Google payload
    notification = ApplicationPushNotification
      .with_google(android: { notification: { notification_count: nil } })
      .new(title: "Hello", body: "World", badge: 1)
  12. Configure Action Push Native via config/push.yml

    main

    Action Push Native loads its configuration from a YAML file located at config/push.yml within your Rails application.

    Configuration is organized by platform (e.g., :apple, :google). You can also provide application-specific overrides. If a notification has an application attribute, the configuration for that specific application will be merged into the platform's base configuration, with the application-specific settings taking precedence.

    # Example config/push.yml structure
    apple:
      application:
        key_id: "YOUR_KEY_ID"
        team_id: "YOUR_TEAM_ID"
      my_app_name:
        key_id: "OVERRIDE_KEY_ID"
    
    google:
      server_key: "YOUR_FCM_SERVER_KEY"