React Native SDK
Set up Expo or a bare React Native app for registration and notification taps.
@exostack/carillon-react-native requires the React Native New Architecture.
It supports Expo through a config plugin and bare apps through native callback forwarding.
Samples on this page show placeholders. Sign in to the dashboard in this browser and they fill in with your own organization, app and mobile key.
Install
yarn add @exostack/carillon-react-nativeConfigure
import Carillon from '@exostack/carillon-react-native'Carillon.configure({ key: 'carillon_mk_live_your_mobile_key', debug: __DEV__ })// Call when your app should request notification permission.// 'allowed' | 'denied' | 'provisional' | 'undetermined'const permission = await Carillon.requestPermission()Carillon.identify('user-42') // null forgets the identifierCarillon.setTags({ plan: 'pro', seats: 12 }) // replaced whole, never mergedCarillon.optOut()Carillon.optIn()const off = Carillon.onOpened((notification) => {const orderId = notification.payload.order_idif (typeof orderId === 'string') { // Open this order in your app.}})await Carillon.debugInfo() // registration diagnosticsrequestPermission() takes nothing on either platform. Android's native call needs the activity its
dialogue belongs to, and the module supplies the current one. With no activity in the foreground the
promise rejects, since there is no screen to show a prompt on.
Expo
The config plugin ships inside this package.
{
"expo": {
"plugins": ["@exostack/carillon-react-native"],
"android": { "googleServicesFile": "./google-services.json" }
}
}Run expo prebuild, then rebuild the native app. The plugin configures iOS push entitlements
and callbacks, the Android messaging service, and Google services when the JSON file is present.
For Kotlin MainActivity, it also forwards cold-start and warm notification taps
from onCreate and onNewIntent. Existing callbacks are preserved. Java activities
require conversion to Kotlin for automatic configuration; bare apps can use the
manual forwarding below.
The SDK detects the APNs environment from the signed build.
Bare workflow
Add the push capability, then forward the three callbacks. Import CarillonReactNative, not
Carillon: your app links this package, and the Swift SDK is resolved for this package's pod alone.
import CarillonReactNative
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
CarillonBridge.didRegister(token: deviceToken)
}
func application(
_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error
) {
CarillonBridge.didFailToRegister(error)
}
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void
) {
CarillonBridge.didOpen(response)
completionHandler()
}Set UNUserNotificationCenter.current().delegate before anything else in didFinishLaunching.
Opened payloads
onOpened exposes the reserved payload.carillon field as an object on both
platforms. The bridge parses the Android JSON stamp without changing customer
payload fields. deliveryId is also available directly on the notification.
Whole JavaScript numbers in setTags are sent as integers rather than as 12.0. Values that are
not strings, numbers or booleans are refused by TypeScript and dropped at the bridge.
Related pages
Track opens · SDK overview · Troubleshooting
Foreground notifications
const unsubscribe = Carillon.onReceived(async (notification) => {
// Read notification.data; return 'suppress' for your own in-app UI.
return 'show'
})
Carillon.clearNotifications()A new onReceived call replaces the previous handler. Unsubscribe when the handler is no
longer needed. The native SDK shows the notification if JavaScript does not answer within
three seconds. A thrown or rejected handler also falls back to showing it.
The listener attaches before native observation starts.
The Expo plugin forwards iOS willPresent. In a bare app, forward it explicitly:
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completion: @escaping (UNNotificationPresentationOptions) -> Void) {
CarillonBridge.willPresent(notification, completionHandler: completion)
}Use override when your AppDelegate superclass implements this method. Keep the notification
center delegate installed at launch. Android's foreground renderer
uses the native notification permission and channels.
Images on iOS
The Expo plugin creates a CarillonNotificationExtension target and declares it under
extra.eas.build.experimental.ios.appExtensions, with bundle identifier
<ios.bundleIdentifier>.CarillonNotificationExtension. Set ios.bundleIdentifier in your Expo
configuration. EAS needs a provisioning profile for this target; no App Group is required.
Run prebuild again, then rebuild the native app. Expo Go cannot load this native extension.
For a bare app, follow the Swift extension setup. When migrating from OneSignal, replace its notification service extension instead of keeping two service extensions.
Device ID
const deviceId = await Carillon.getDeviceId() // null before registration
const stopObserving = Carillon.onDeviceIdChanged((id) => {
// Update a stored equipment-to-device mapping if needed.
})The ID survives token rotation when the native installation proof is available. It is a routing identifier, not a login credential. See device identity.