RailsFast Native - Notifications
RailsFast Native push is a three-part contract:
- Rails owns notification events, device storage, and the authenticated token endpoint.
- iOS owns APNs permission, token registration, and notification-tap routing.
- Android owns FCM setup, token registration, runtime notification permission, and notification-tap routing.
Native push is opt-in. The native shells can advertise and implement the native-push bridge component safely, but a downstream app should only render the Rails bridge tag once the matching server delivery credentials are configured for that platform. In particular, do not let Android register FCM tokens while the Rails server still has placeholder Google/FCM credentials.
The Contract
The web bridge component name is:
native-push
Rails renders a hidden bridge element on authenticated native pages. The web side sends:
{
"event": "register"
}
Native replies:
{
"token": "device-token-from-apns-or-fcm",
"platform": "ios"
}
Android replies with "platform": "android". Rails then POSTs that token from inside the WebView to the app's authenticated token endpoint, usually:
POST /notification_tokens
The POST should ride the existing Rails session cookie and CSRF token. Do not add a parallel mobile auth token just for push registration.
The server stores tokens against the current user. If you use action_push_native, translate the OS names that native sends into the transport names the gem stores:
ios->appleandroid->google
Notification payload routing uses two app-defined data keys:
pathfor app-owned Rails paths, such as/notificationsor/rides/123urlfor absolute URLs when a downstream app needs them
url wins over path. Native should route internal URLs in-app and open external URLs through the system browser.
Rails Server
The recommended Rails stack is:
noticedfor event orchestration and in-app feed rowsaction_push_nativefor APNs/FCM delivery and push-device records- a small app-owned
NotificationTokensController - a RailsFast-owned Stimulus bridge controller under
app/javascript/controllers/railsfast/native
The token controller is intentionally tiny because the POST originates inside the authenticated WebView:
class NotificationTokensController < ApplicationController
before_action :authenticate_user!
PLATFORMS = {
"ios" => "apple", "apple" => "apple",
"android" => "google", "google" => "google"
}.freeze
def create
platform = PLATFORMS[params.require(:platform).to_s.downcase]
head :unprocessable_entity and return if platform.blank?
device = ApplicationPushDevice.find_or_initialize_by(token: params.require(:token))
device.owner = current_user
device.platform = platform
device.name = params[:name].presence || "Mobile device"
device.save!
head :created
end
def destroy
current_user.application_push_devices.where(token: params.require(:token)).destroy_all
head :no_content
end
end
Server-side delivery credentials are platform-specific:
- APNs needs an Apple Developer account, an APNs
.p8key, key ID, team ID, and the app bundle ID as the APNs topic. - FCM needs a Firebase project, the Firebase project ID, and a service-account JSON private key for FCM v1 server auth.
Render the native bridge only when the native app advertises native-push. If Android FCM server credentials are missing, either do not render the bridge for Android or reject Android token registration so no google devices are stored until delivery can actually succeed.
iOS
railsfast-ios includes the native side:
NativePushComponentanswers theregisterbridge event.PushRegistrationServicerequests an APNs token and caches it for repeated WebView bridge reconnects.PushNotificationRouterroutespath/urlpayloads after a notification tap.AppDelegateimplements APNs registration callbacks andUNUserNotificationCenterDelegate.SceneDelegateconsumes notification responses on cold launch and while the app is already running.RailsFast.entitlementsdeclaresaps-environmentthroughRAILSFAST_APS_ENVIRONMENT.project.ymldeclaresUIBackgroundModes: remote-notification.
Before a downstream iOS app ships push:
- Register the explicit App ID for the production bundle identifier.
- Enable Push Notifications on that App ID.
- Keep Associated Domains enabled if notification taps route to Universal Link URLs.
- Set
RAILSFAST_APS_ENVIRONMENT = developmentfor Debug andproductionfor Release. - Configure Rails APNs credentials and set the APNs topic to the bundle identifier.
- Regenerate the project with
xcodegen generate. - Test on a real device. Simulator behavior is not enough for final APNs verification.
TestFlight and App Store builds use production APNs tokens. Xcode-installed development builds use development APNs tokens unless you explicitly configure the server to talk to APNs development for that environment.
Android
Android push uses Firebase Cloud Messaging. Play Console distribution and Firebase push are separate Google products; a Play account does not replace Firebase.
railsfast-android includes the native side:
NativePushComponentanswers the webnative-pushbridgeregisterevent.NativePushPermissionrequests Android 13+ notification permission and resumes the pending token request after the system dialog returns.RailsFastFirebaseMessagingServicereceives FCM messages, builds foreground notifications, and logs token refreshes.PushNotificationRouterroutespath/urlpayloads into the app or out to the system browser.- The Gradle build adds Firebase Messaging through the Firebase BoM and applies the Google Services plugin only when a local
google-services.jsonis present.
Before a downstream Android app ships push:
- Create a Firebase project.
- Add the Android app using the exact package/application ID.
- Download
google-services.json. - Put it in
app/google-services.json, or in a build-type/flavor-specific location if the app uses separate Firebase projects per environment. - Add Firebase Messaging through the Firebase BoM.
- Apply the Google Services Gradle plugin for builds that have a
google-services.json. - Add a
FirebaseMessagingServicein the manifest forcom.google.firebase.MESSAGING_EVENT. - Request
android.permission.POST_NOTIFICATIONSat runtime on Android 13+ before showing notifications. - Configure Rails FCM credentials before allowing Android tokens to register.
The Android native-push component should get the current FCM token, reply to the WebView bridge with {token, platform: "android"}, and let the WebView POST to Rails. The native service should handle foreground data messages by creating a notification with a PendingIntent back into the app. For background notification messages, FCM can display the notification through the system tray; the tap launches the app and data payload keys are delivered in the launcher intent extras.
Verification
Use this checklist before a release:
- Rails logs show successful token registration for the signed-in user.
- The stored device platform is
applefor iOS andgooglefor Android. - A notification with
path: "/notifications"opens the app to/notifications. - An internal absolute app URL routes in-app.
- An external absolute URL opens in the system browser.
- iOS foreground notifications are presented with alert, sound, and badge.
- Android foreground data messages produce a notification channel notification.
- Deleting/signing out removes the current token when the shell supports sign-out cleanup.
- Invalid/dead tokens self-clean through the push delivery layer or are explicitly removed on provider token errors.
References
- Apple, Registering your app with APNs: https://developer.apple.com/documentation/usernotifications/registering-your-app-with-apns
- Apple,
UNUserNotificationCenterDelegate: https://developer.apple.com/documentation/usernotifications/unusernotificationcenterdelegate - Firebase, Get started with Firebase Cloud Messaging in Android apps: https://firebase.google.com/docs/cloud-messaging/android/get-started
- Firebase, Receive messages in Android apps: https://firebase.google.com/docs/cloud-messaging/android/receive-messages
- Google, Google Services Gradle Plugin: https://developers.google.com/android/guides/google-services-plugin
- Android Developers, Notification runtime permission: https://developer.android.com/develop/ui/compose/notifications/notification-permission
- Rails
action_push_native: https://github.com/rails/action_push_native - Noticed: https://github.com/excid3/noticed