# React Native Integrate the Airship SDK into your React Native applications for iOS and Android. # Deep Links > Configure deep link handling for Airship messaging. Deep linking allows Airship messaging to open your app to specific resources or screens. When a user interacts with a message (notification, in-app message, etc.), the deep link can navigate them directly to the relevant content in your app. ## Listening for deep links The SDK provides a way to listen for deep links so you can handle them in your app. This handler receives all deep links except for Message Center and Preference Center display requests, which are handled automatically by their respective features. > **Note:** For Message Center and Preference Center display requests, see [Message Center: Getting Started](https://www.airship.com/docs/developer/sdk-integration/react-native/message-center/getting-started/) and [Preference Center: Getting Started](https://www.airship.com/docs/developer/sdk-integration/react-native/preference-center/getting-started/). ```ts Airship.addListener(EventType.DeepLink, (event) => { const deepLink = event.deepLink; // Handle deep link }); ``` # Actions > Airship Actions provide a convenient way to automatically perform tasks by name in response to push notifications, Message Center App Page interactions, and JavaScript. An action describes a function, which takes an optional argument and performs a predefined task, producing an optional result. Actions may restrict or vary the work they perform depending on the arguments they receive, which may include type introspection and runtime context. The Airship SDK includes built-in actions for common tasks, and you can create custom actions to extend functionality. For a complete list of available built-in actions, see the [Actions User Guide](https://www.airship.com/docs/guides/messaging/messages/actions/). ## Running Actions You can run actions programmatically using the `Airship.actions.run()` method. The method returns a Promise that resolves with the action result. The action value can be a string, number, boolean, null, object, or array. **Running an action** ```typescript // Run an action with a string value using async/await try { const result = await Airship.actions.run("action_name", "action_value"); console.log("Action result:", result); } catch (error) { console.error("Action error:", error); } // Run an action with an object value try { const result = await Airship.actions.run("action_name", { key: "value", number: 42 }); console.log("Action result:", result); } catch (error) { console.error("Action error:", error); } // Run an action without a value try { const result = await Airship.actions.run("action_name"); console.log("Action result:", result); } catch (error) { console.error("Action error:", error); } // Run an action using Promise.then() Airship.actions.run("action_name", "action_value") .then((result) => { console.log("Action result:", result); }) .catch((error) => { console.error("Action error:", error); }); ``` ## Custom Actions You can register custom actions with an [Airship extender](https://www.airship.com/docs/developer/sdk-integration/react-native/installation/extending-airship/) and with native SDK APIs. See the native platform documentation for details: - [iOS Actions](https://www.airship.com/docs/developer/sdk-integration/apple/actions/) - [Android Actions](https://www.airship.com/docs/developer/sdk-integration/android/actions/) # Feature Flags > {{< glossary_definition "feature_flag" >}} ## Accessing flags The Airship SDK will refresh feature flags when the app is brought to the foreground. If a feature flag is accessed before the foreground refresh completes, or after the foreground refresh has failed, feature flags will be refreshed during flag access. Feature flags will only be updated once per session and will persist for the duration of each session. Once [defined in the dashboard](https://www.airship.com/docs/guides/experimentation/feature-flags/#create-feature-flags), a feature flag can be accessed by its name in the SDK after `takeOff`. ```ts const flag = await Airship.featureFlagManager.flag("YOUR_FLAG_NAME"); if (flag.isEligible) { // Do something with the flag } else { // Disable feature or use default behavior } ``` ## Tracking interaction To generate the [Feature Flag Interaction Event](https://www.airship.com/docs/developer/rest-api/connect/schemas/events/#feature-flag-interaction), you must manually call `trackInteraction` with the feature flag. Analytics must be enabled. See: [Data Collection: Privacy Manager](https://www.airship.com/docs/developer/sdk-integration/react-native/data-collection/privacy-manager/). ```ts await Airship.featureFlagManager.trackInteraction(flag); ``` ## Error handling If a feature flag allows evaluation with stale data, the SDK evaluates the flag if a definition for the flag is found. Otherwise, feature flag evaluation depends on updated local state. If the SDK cannot evaluate a flag because data cannot be fetched, the SDK returns or raises an error. The app can either treat the error as the flag being ineligible or retry at a later time. ```ts try { await Airship.featureFlagManager.flag("YOUR_FLAG_NAME"); } catch(error) { // Do something with the error } ``` # Live Activities > Integrate Live Activities into your React Native app to display real-time updates on the iOS Lock Screen and Dynamic Island. {{< badge "axp" >}} For the push API method, see the [iOS Live Activities](https://www.airship.com/docs/guides/messaging/features/ios-live-activities/) messaging guide. See also the [iOS Live Activities](https://www.airship.com/docs/guides/features/messaging/live-activities-updates/) feature guide. ### App setup Using the [AirshipPluginExtender](https://www.airship.com/docs/developer/sdk-integration/react-native/installation/extending-airship/), make a call to `LiveActivityManager.shared.setup` to configure any Live Activities for the app. Call `configurator.register` for each Live Activity type that your application defines and include a block on how to parse the name of the activity that you will use to track on Airship. This name will be used to send updates through APNS. ```swift import Foundation import AirshipKit import AirshipFrameworkProxy import ActivityKit // This class header is required to be automatically picked up by the Airship plugin: @objc(AirshipPluginExtender) public class AirshipPluginExtender: NSObject, AirshipPluginExtenderProtocol { public static func onAirshipReady() { if #available(iOS 16.1, *) { // Will throw if called more than once try? LiveActivityManager.shared.setup { configurator in // Call for each Live Activity type await configurator.register(forType: Activity.self) { attributes in // Track this property as the Airship name for updates attributes.gameID } } } // other setup } } ``` > **Important:** If you are using Expo, you must copy-paste your exact `ActivityAttributes` struct into your `AirshipPluginExtender.swift` so the compiler can find a definition in order to register the Live Activity. ### Starting Live Activities For any Live Activities configured, you can start a new one using the `start` method: ```typescript Airship.iOS.liveActivityManager.start({ attributesType: 'SportsActivityAttributes', content: { state: { status: 'Game Pending', }, relevanceScore: 0.0, }, attributes: { gameID: 'sports-game-123', }, }); ``` ### Updating Live Activities To update, use `update`, but you will need the activity ID. ```typescript const activities = await Airship.iOS.liveActivityManager.listAll(); const activity = activities.find( (activity) => activity.attributes.gameID === 'sports-game-123' ); if (activity) { Airship.iOS.liveActivityManager.update({ activityId: activity.id, content: { state: { status: "Game starting!" } relevanceScore: 0.0, }, }); } ``` ### Ending Live Activities To end is similar to `update`. Use `end` with the activity ID: ```typescript const activities = await Airship.iOS.liveActivityManager.listAll(); const activity = activities.find( (activity) => activity.attributes.gameID === 'sports-game-123' ); if (activity) { Airship.iOS.liveActivityManager.end({ activityId: activity.id, dismissalPolicy: { type: "default" } }); } ``` # Live Updates > Integrate Live Updates into your React Native app to update content in real-time without requiring an app update. {{< badge "axp" >}} For the push API method, see the [Android Live Updates](https://www.airship.com/docs/guides/messaging/features/android-live-updates/) messaging guide. See also the [Android Live Updates](https://www.airship.com/docs/guides/features/messaging/live-activities-updates/) feature guide. ### Creating a handler The Airship SDK supports two types of Live Update handlers: * `NotificationLiveUpdateHandler` — Displays a notification with a custom layout, with content updated by the Live Update. * `CustomLiveUpdateHandler` — Receives Live Update events and provides flexibility to display content using a custom implementation. This can be used to power home screen widgets, views embedded in the app, and more. Each handler type has two different interfaces that may be implemented, to support suspending or callback-based code: * `SuspendLiveUpdateNotificationHandler` * `CallbackLiveUpdateNotificationHandler` * `SuspendLiveUpdateCustomHandler` * `CallbackLiveUpdateCustomHandler` The following `SampleLiveUpdateHandler` reads content from the Live Update payload and displays scores for a sports game in a custom notification layout, using `RemoteViews`: ```kotlin class SampleLiveUpdateHandler : SuspendLiveUpdateNotificationHandler() { override suspend fun onUpdate( context: Context, event: LiveUpdateEvent, update: LiveUpdate ): LiveUpdateResult { // Read content_state fields from the Live Update payload val teamOneScore = update.content.opt("team_one_score").getInt(0).toString() val teamTwoScore = update.content.opt("team_two_score").getInt(0).toString() val statusUpdate = update.content.opt("status_update").optString() // Expanded notification layout val bigLayout = RemoteViews(context.packageName, R.layout.sports_big).apply { setTextViewText(R.id.teamOneScore, teamOneScore) setTextViewText(R.id.teamTwoScore, teamTwoScore) setTextViewText(R.id.statusUpdate, statusUpdate) } // Collapsed notification layout val smallLayout = RemoteViews(context.packageName, R.layout.sports_small).apply { setTextViewText(R.id.teamOneScore, teamOneScore) setTextViewText(R.id.teamTwoScore, teamTwoScore) } // Create the notification builder val builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification) .setPriority(NotificationCompat.PRIORITY_HIGH) .setCategory(NotificationCompat.CATEGORY_EVENT) .setStyle(NotificationCompat.DecoratedCustomViewStyle()) .setCustomContentView(smallLayout) .setCustomBigContentView(bigLayout) // Return 'ok' with the notification builder. // The Airship SDK will handle posting the notification. // Returning LiveUpdateResult.cancel() will end the Live Update and dismiss the notification. return LiveUpdateResult.ok(builder) } companion object { private const val NOTIFICATION_CHANNEL_ID = "sports" } } ``` ### Registering a handler Handlers must be registered with `LiveUpdateManager` in order to receive Live Update events. This should be done *once* after `takeOff`. Using the [AirshipPluginExtender](https://www.airship.com/docs/developer/sdk-integration/react-native/installation/extending-airship/), register the types. ```kotlin @Keep public final class AirshipExtender: AirshipPluginExtender { override fun onAirshipReady(context: Context, airship: UAirship) { LiveUpdateManager.shared().run { register(type = "notification", handler = SampleLiveUpdateHandler()) } } } ``` > **Note:** The `type` used above, `"notification"`, is used to map Live Update events to the corresponding handler in your app. > The value can be any string that is unique across all handlers registered by an app. This also allows a single handler to manage multiple Live Updates that each have a unique `name`. ### Starting Live Updates Live Updates can be started from within the app. ```typescript Airship.android.liveUpdateManager.start({ name: 'sports-game-123' type: 'notification', content: { team_one_score: 0, team_two_score: 0, status_update: 'Game started!' } }); ``` ### Updating Live Updates Live Updates can be updated from within the app. ```typescript Airship.android.liveUpdateManager.update({ name: 'sports-game-123' content: { team_one_score: 3, team_two_score: 0, status_update: 'Game started!' } }); ``` ### Ending Live Updates You can end a Live Update from within the app. ```typescript Airship.android.liveUpdateManager.end({ name: 'sports-game-123' content: { team_one_score: 9, team_two_score: 6, status_update: 'Game over!' } }); ``` ### Clearing all active Live Updates During development, it can be useful to reset Live Update tracking on app launch. This allows any Live Updates to be started fresh, even if they were already started during a previous launch. To end all currently active Live Updates, call the `clearAll()` method on `LiveUpdateManager`. ```typescript Airship.android.liveUpdateManager.clearAll(); ``` # React Native Module Changelog > The latest updates to the Airship React Native module. See the [SDK Support Policy](https://www.airship.com/docs/reference/sdk-support-policy/) for version coverage and maintenance windows. ## 26.5.0 May 2, 2026 Minor release that updates the Android SDK to 20.7.0 and the iOS SDK to 20.7.0. ### Changes - Updated Android SDK to [20.7.0](https://github.com/urbanairship/android-library/releases/tag/20.7.0) - Updated iOS SDK to [20.7.0](https://github.com/urbanairship/ios-library/releases/tag/20.7.0) ## 25.4.3 April 23, 2026 Patch release that updates the iOS SDK to 19.11.8 to fix Xcode 26.4 build issues with whole module optimization. ### Changes - Updated iOS SDK to [19.11.8](https://github.com/urbanairship/ios-library/releases/tag/19.11.8) ## 26.4.1 April 11, 2026 Patch release that fixes a `UIViewControllerHierarchyInconsistency` crash in the Airship embedded view wrapper on iOS when an embedded view is pushed and popped on a navigation stack. ### Changes - Fixed iOS embedded view wrapper to properly remove its hosted `UIHostingController` as a child view controller when its window is detached, avoiding a `UIViewControllerHierarchyInconsistency` crash on re-attachment. ## 25.4.2 April 11, 2026 Patch release that fixes a `UIViewControllerHierarchyInconsistency` crash in the Airship embedded view wrapper on iOS when an embedded view is pushed and popped on a navigation stack. ### Changes - Fixed iOS embedded view wrapper to properly remove its hosted `UIHostingController` as a child view controller when its window is detached, avoiding a `UIViewControllerHierarchyInconsistency` crash on re-attachment. ## 25.4.1 April 2, 2026 Patch release that fixes an Xcode 26.4 Swift compiler crash affecting iOS builds. ### Changes - Updated iOS SDK to [19.11.6](https://github.com/urbanairship/ios-library/releases/tag/19.11.6) to fix a Swift compiler crash ("Failed to produce diagnostic for expression") introduced in Xcode 26.4. ## 24.9.1 April 2, 2026 Patch release that fixes an Xcode 26.4 Swift compiler crash affecting iOS builds. ### Changes - Updated iOS SDK to [19.11.6](https://github.com/urbanairship/ios-library/releases/tag/19.11.6) to fix a Swift compiler crash ("Failed to produce diagnostic for expression") introduced in Xcode 26.4. ## 26.4.0 April 1, 2026 Minor release that updates the Android SDK to 20.6.1 and the iOS SDK to 20.6.0. ### Changes - Updated Android SDK to [20.6.1](https://github.com/urbanairship/android-library/releases/tag/20.6.1) - Updated iOS SDK to [20.6.0](https://github.com/urbanairship/ios-library/releases/tag/20.6.0) ## 26.3.0 March 18, 2026 Minor release that updates the Android SDK to 20.5.0 and the iOS SDK to 20.5.0. ### Changes - Updated Android SDK to [20.5.0](https://github.com/urbanairship/android-library/releases/tag/20.5.0) - Updated iOS SDK to [20.5.0](https://github.com/urbanairship/ios-library/releases/tag/20.5.0) ## 26.2.0 February 3, 2026 Minor release that updates the native SDKs, improves logging, and resolves UI event name conflicts. ### Changes - Updated Android SDK to [20.2.0](https://github.com/urbanairship/android-library/releases/tag/20.2.0) - Updated iOS SDK to [20.3.0](https://github.com/urbanairship/ios-library/releases/tag/20.3.0) - Pinned Swift version to 6.0 for the Airship React Native module - Resolved MessageView UI event name conflicts - Improved logging ## 25.4.0 February 3, 2026 Minor release that updates MessageView event names to avoid collisions and pins the Swift version for iOS builds. No breaking API changes. ### Changes - Namespaced MessageView UI event registration names - Set the Swift version for the Airship React Native module ## 24.9.0 February 3, 2026 Minor release that updates MessageView event names to avoid collisions and pins the Swift version for iOS builds. No breaking API changes. ### Changes - Namespaced MessageView UI event registration names - Set the Swift version for the Airship React Native module ## 26.1.0 January 23, 2026 Minor release that includes accessibility improvements for Message Center and fixes a potential crash on Android. ### Changes - Updated Android SDK to [20.1.1](https://github.com/urbanairship/android-library/releases/tag/20.1.1) - Updated iOS SDK to [20.1.1](https://github.com/urbanairship/ios-library/releases/tag/20.1.1) - Fixed a potential crash in Android Scenes with specific image and display settings. - Improved VoiceOver focus handling for Message Center on iOS. - Fixed an issue where the Message Center title was not being marked as a heading on Android. [Migration Guide](https://github.com/urbanairship/react-native-airship/blob/main/MIGRATION.md) ## 26.0.0 December 11, 2025 This major release updates the native Airship SDKs to 20.0 and adds support for React Native 0.82+. It includes breaking changes—primarily affecting build configurations and native customizations—as well as an updated support policy. For detailed upgrade instructions, please consult the [Migration Guide](https://github.com/urbanairship/react-native-airship/blob/main/MIGRATION.md). ### Changes - Updated Android SDK to [20.0.4](https://github.com/urbanairship/android-library/releases/tag/20.0.4) - Updated iOS SDK to [20.0.2](https://github.com/urbanairship/ios-library/releases/tag/20.0.2) - Added support for React Native 0.82+ - Updated minimum iOS deployment target to 16.0 - Xcode 26+ is now required - Removed deprecated `AirshipExtender` on Android - Removed deprecated forward listener/delegate interfaces - Removed support for React Native old architecture - Removed pre-generated code from the package ## 25.3.1 November 15, 2025 Patch release that fixes YouTube video playback in In-App Automation and Scenes. Applications that use YouTube videos in Scenes and non-html In-App Automations (IAA) must update to resolve playback errors. ### Changes - Updated Android SDK to [19.13.6](https://github.com/urbanairship/android-library/releases/tag/19.13.6) - Updated iOS SDK to [19.11.2](https://github.com/urbanairship/ios-library/releases/tag/19.11.2) - Fixed the HeadlessJSService from preventing the app from terminating right away on Android. ## 24.8.1 November 15, 2025 Patch release that fixes YouTube video playback in In-App Automation and Scenes. Applications that use YouTube videos in Scenes and non-html In-App Automations (IAA) must update to resolve playback errors. ### Changes - Updated Android SDK to [19.13.6](https://github.com/urbanairship/android-library/releases/tag/19.13.6) - Updated iOS SDK to [19.11.2](https://github.com/urbanairship/ios-library/releases/tag/19.11.2) - Fixed the HeadlessJSService from preventing the app from terminating right away on Android. ## 24.8.0 October 8, 2025 Minor release that updates the Android SDK to 19.13.4 and the iOS SDK to 19.11.0 ### Changes - Updated Android SDK to [19.13.4](https://github.com/urbanairship/android-library/releases/tag/19.13.4) - Updated iOS SDK to [19.11.0](https://github.com/urbanairship/ios-library/releases/tag/19.11.0) ## 25.3.0 October 8, 2025 Minor release that updates the Android SDK to 19.13.4 and the iOS SDK to 19.11.0. ### Changes - Updated Android SDK to [19.13.4](https://github.com/urbanairship/android-library/releases/tag/19.13.4) - Updated iOS SDK to [19.11.0](https://github.com/urbanairship/ios-library/releases/tag/19.11.0) ## 23.6.0 September 17, 2025 Minor release that updates the Android SDK to 19.13.1 and the iOS SDK to 19.9.2. ### Changes - Updated Android SDK to [19.13.1](https://github.com/urbanairship/android-library/releases/tag/19.13.1) - Updated iOS SDK to [19.9.2](https://github.com/urbanairship/ios-library/releases/tag/19.9.2) ## 21.9.0 September 17, 2025 Minor release that updates the Android SDK to 19.13.1 and the iOS SDK to 19.9.2. ### Changes - Updated Android SDK to [19.13.1](https://github.com/urbanairship/android-library/releases/tag/19.13.1) - Updated iOS SDK to [19.9.2](https://github.com/urbanairship/ios-library/releases/tag/19.9.2) ## 25.2.0 September 17, 2025 Minor release that updates the Android SDK to 19.13.1 and the iOS SDK to 19.9.2. ### Changes - Updated Android SDK to [19.13.1](https://github.com/urbanairship/android-library/releases/tag/19.13.1) - Updated iOS SDK to [19.9.2](https://github.com/urbanairship/ios-library/releases/tag/19.9.2) ## 24.7.0 September 17, 2025 Minor release that updates the Android SDK to 19.13.1 and the iOS SDK to 19.9.2. ### Changes - Updated Android SDK to [19.13.1](https://github.com/urbanairship/android-library/releases/tag/19.13.1) - Updated iOS SDK to [19.9.2](https://github.com/urbanairship/ios-library/releases/tag/19.9.2) [Migration Guides](https://github.com/urbanairship/react-native-airship/blob/main/MIGRATION.md) [All Releases](https://github.com/urbanairship/react-native-airship/releases) ## 25.1.0 August 27, 2025 Minor release that updates the Android SDK to 19.11.0 and the iOS SDK to 19.8.3 ### Changes - Updated Android SDK to [19.11.0](https://github.com/urbanairship/android-library/releases/tag/19.11.0) - Updated iOS SDK to [19.8.3](https://github.com/urbanairship/ios-library/releases/tag/19.8.3) - Fixed possible crash when dismissing a Message Center view. ## 24.6.0 August 27, 2025 Minor release that updates the Android SDK to 19.11.0 and the iOS SDK to 19.8.3 ### Changes - Updated Android SDK to [19.11.0](https://github.com/urbanairship/android-library/releases/tag/19.11.0) - Updated iOS SDK to [19.8.3](https://github.com/urbanairship/ios-library/releases/tag/19.8.3) - Fixed possible crash when dismissing a Message Center view. ## 25.0.0 August 21, 2025 Major release to support React Native 0.81. ### Changes - Added support for React Native 0.81 ## 24.5.1 August 20, 2025 Patch release with several bug fixes for Scenes, including an important reporting fix for embedded content. ### Changes - Updated Android SDK to [19.10.2](https://github.com/urbanairship/android-library/releases/tag/19.10.2) - Updated iOS SDK to [19.8.2](https://github.com/urbanairship/ios-library/releases/tag/19.8.2) ## 23.5.1 August 20, 2025 Patch release with several bug fixes for Scenes, including an important reporting fix for embedded content. ### Changes - Updated Android SDK to [19.10.2](https://github.com/urbanairship/android-library/releases/tag/19.10.2) - Updated iOS SDK to [19.8.2](https://github.com/urbanairship/ios-library/releases/tag/19.8.2) ## 21.8.1 August 20, 2025 Patch release with several bug fixes for Scenes, including an important reporting fix for embedded content. ### Changes - Updated Android SDK to [19.10.2](https://github.com/urbanairship/android-library/releases/tag/19.10.2) - Updated iOS SDK to [19.8.2](https://github.com/urbanairship/ios-library/releases/tag/19.8.2) ## 24.5.0 July 31, 2025 Minor release that updates the Android SDK to 19.10.0 and the iOS SDK to 19.7.0 ### Changes - Updated Android SDK to [19.10.0](https://github.com/urbanairship/android-library/releases/tag/19.10.0) - Updated iOS SDK to [19.7.0](https://github.com/urbanairship/ios-library/releases/tag/19.7.0) [Migration Guides](https://github.com/urbanairship/react-native-airship/blob/main/MIGRATION.md) [All Releases](https://github.com/urbanairship/react-native-airship/releases) ## 24.4.0 June 30, 2025 Minor release that updates the Android SDK to 19.9.1 and the iOS SDK to 19.6.1 ### Changes - Updated Android SDK to [19.9.1](https://github.com/urbanairship/android-library/releases/tag/19.9.1 - Updated iOS SDK to [19.6.1](https://github.com/urbanairship/ios-library/releases/tag/19.6.1 - Added Android `logPrivacyLevel` configuration support - Fixed issue with push received pushes when disabling headless JS task before the module initializes ## 23.5.0 June 30, 2025 Minor release that adds support for Android log privacy level configuration and updates the Android SDK to 19.9.1 and the iOS SDK to 19.6.1. The **23.x branch** is now considered **End of Cycle**. This branch supports React Native 0.78.x, which is no longer actively supported by the React Native team. ### Changes - Updated Android SDK to [19.9.1](https://github.com/urbanairship/android-library/releases/tag/19.9.1) - Updated iOS SDK to [19.6.1](https://github.com/urbanairship/ios-library/releases/tag/19.6.1) - Added Android `logPrivacyLevel` configuration support - Fixed issue with push received pushes when disabling headless JS task before the module initializes ## 21.8.0 June 30, 2025 Minor release that adds support for Android log privacy level configuration and updates the Android SDK to 19.9.1 and the iOS SDK to 19.6.1. The **21.x branch** is now considered **Unsupported**. This branch supports React Native 0.77.x and older, which is no longer supported by the React Native team. ### Changes - Updated Android SDK to [19.9.1](https://github.com/urbanairship/android-library/releases/tag/19.9.1) - Updated iOS SDK to [19.6.1](https://github.com/urbanairship/ios-library/releases/tag/19.6.1) - Added Android `logPrivacyLevel` configuration support - Fixed issue with push received pushes when disabling headless JS task before the module initializes ## 24.3.0 May 23, 2025 Minor release focused on performance improvements for Scenes. ### Changes - Updated Android SDK to [19.8.0](https://github.com/urbanairship/android-library/releases/tag/19.8.0) - Updated iOS SDK to [19.5.0](https://github.com/urbanairship/ios-library/releases/tag/19.5.0) ## 23.4.0 May 23, 2025 Minor release focused on performance improvements for Scenes. ### Changes - Updated Android SDK to [19.8.0](https://github.com/urbanairship/android-library/releases/tag/19.8.0) - Updated iOS SDK to [19.5.0](https://github.com/urbanairship/ios-library/releases/tag/19.5.0) ## 21.7.0 May 23, 2025 Minor release focused on performance improvements for Scenes. ### Changes - Updated Android SDK to [19.8.0](https://github.com/urbanairship/android-library/releases/tag/19.8.0) - Updated iOS SDK to [19.5.0](https://github.com/urbanairship/ios-library/releases/tag/19.5.0) ## 24.2.0 May 16, 2025 Minor release that adds support for using Feature Flags as an audience condition for other Feature Flags and Vimeo videos in Scenes. ### Changes - Added support for using Feature Flags as an audience condition for other Feature Flags. - Added support for Vimeo videos in Scenes. - Updated Android SDK to [19.7.0](https://github.com/urbanairship/android-library/releases/tag/19.7.0) - Updated iOS SDK to [19.4.0](https://github.com/urbanairship/ios-library/releases/tag/19.4.0) ## 23.3.0 May 16, 2025 Minor release that adds support for using Feature Flags as an audience condition for other Feature Flags and Vimeo videos in Scenes. ### Changes - Added support for using Feature Flags as an audience condition for other Feature Flags. - Added support for Vimeo videos in Scenes. - Updated Android SDK to [19.7.0](https://github.com/urbanairship/android-library/releases/tag/19.7.0) - Updated iOS SDK to [19.4.0](https://github.com/urbanairship/ios-library/releases/tag/19.4.0) ## 21.6.0 May 16, 2025 Minor release that adds support for using Feature Flags as an audience condition for other Feature Flags and Vimeo videos in Scenes. ### Changes - Added support for using Feature Flags as an audience condition for other Feature Flags. - Added support for Vimeo videos in Scenes. - Updated Android SDK to [19.7.0](https://github.com/urbanairship/android-library/releases/tag/19.7.0) - Updated iOS SDK to [19.4.0](https://github.com/urbanairship/ios-library/releases/tag/19.4.0) ## 24.1.1 May 9, 2025 Patch release with several bug fixes for iOS. ### Changes - Fixed `Airship.preferenceCenter.getConfig(preferenceCenterId)` on iOS - Updated iOS SDK to [19.3.2](https://github.com/urbanairship/ios-library/releases/tag/19.3.2) ## 23.2.1 May 9, 2025 Patch release with several bug fixes for iOS. ### Changes - Fixed `Airship.preferenceCenter.getConfig(preferenceCenterId)` on iOS - Updated iOS SDK to [19.3.2](https://github.com/urbanairship/ios-library/releases/tag/19.3.2) ## 21.5.1 May 9, 2025 Patch release with several bug fixes for iOS. ### Changes - Fixed `Airship.preferenceCenter.getConfig(preferenceCenterId)` on iOS - Updated iOS SDK to [19.3.2](https://github.com/urbanairship/ios-library/releases/tag/19.3.2) ## 24.1.0 May 1, 2025 Minor release that updates the Android SDK to 19.6.2 and the iOS SDK to 19.3.1. ### Changes - Updated Android SDK to [19.6.2](https://github.com/urbanairship/android-library/releases/tag/19.6.2) - Updated iOS SDK to [19.3.1](https://github.com/urbanairship/ios-library/releases/tag/19.3.1) - Added support for JSON attributes - Added new method `Airship.channel.waitForChannelId()` that waits for the channel ID to be created ## 23.2.0 May 1, 2025 Minor release that updates the Android SDK to 19.6.2 and the iOS SDK to 19.3.1. ### Changes - Updated Android SDK to [19.6.2](https://github.com/urbanairship/android-library/releases/tag/19.6.2) - Updated iOS SDK to [19.3.1](https://github.com/urbanairship/ios-library/releases/tag/19.3.1) - Added support for JSON attributes - Added new method `Airship.channel.waitForChannelId()` that waits for the channel ID to be created ## 21.5.0 May 1, 2025 Minor release that updates the Android SDK to 19.6.2 and the iOS SDK to 19.3.1. ### Changes - Updated Android SDK to [19.6.2](https://github.com/urbanairship/android-library/releases/tag/19.6.2) - Updated iOS SDK to [19.3.1](https://github.com/urbanairship/ios-library/releases/tag/19.3.1) - Added support for JSON attributes - Added new method `Airship.channel.waitForChannelId()` that waits for the channel ID to be created ## 24.0.0 April 18, 2025 Major release to support React Native 0.79. ### Changes - Added support for React Native 0.79 ## 23.1.1 April 18, 2025 Patch release that updates the Android SDK to 19.5.1 and the iOS SDK to 19.2.1 ### Changes - Updated Android SDK to [19.5.1](https://github.com/urbanairship/android-library/releases/tag/19.5.1 - Updated iOS SDK to [19.2.1](https://github.com/urbanairship/ios-library/releases/tag/19.2.1 ## 23.1.0 April 8, 2025 Minor release that updates the iOS SDK to 19.2.0 and remove commonjs in favor of ECM only to avoid [dual package hazard](https://nodejs.org/docs/latest-v19.x/api/packages.html#dual-package-hazard). ### Changes - Updated iOS SDK to [19.2.0](https://github.com/urbanairship/ios-library/releases/tag/19.2.0) - Drops commonjs package - Adds back `types` to package.json for apps that are having troubles discovering type definitions - Fixed null notification in Airship.push.iOS.setForegroundPresentationOptionsCallback ## 21.4.1 April 7, 2025 Patch release to fix the notification being null in `Airship.push.iOS.setForegroundPresentationOptionsCallback`. ### Changes - Fixed null notification in `Airship.push.iOS.setForegroundPresentationOptionsCallback` ## 21.4.0 April 4, 2025 Minor release that updates the iOS SDK to 19.2.0 and backports the new `AirshipPluginExtensions`. ### Changes - Updated iOS SDK to [19.2.0](https://github.com/urbanairship/ios-library/releases/tag/19.2.0) - Backported `AirshipPluginExtensions` from 23.0.0 - Deprecated `AirshipPluginForwardListeners` and `AirshipPluginForwardDelegates` ## 21.3.0 April 1, 2025 Minor release that updates the Android SDK to 19.5.0 and the iOS SDK to 19.1.2. ### Changes - Updated Android SDK to [19.5.0](https://github.com/urbanairship/android-library/releases/tag/19.5.0) - Updated iOS SDK to [19.1.2](https://github.com/urbanairship/ios-library/releases/tag/19.1.2) ## 23.0.0 April 1, 2025 Major release that updates the Android SDK to 19.5.0 and the iOS SDK to 19.1.2. The only breaking change is related to the native plugin hooks, which make it easier to integrate the plugin with hybrid apps. Most applications won't be affected. ### Changes - Updated Android SDK to [19.5.0](https://github.com/urbanairship/android-library/releases/tag/19.5.0 - Updated iOS SDK to [19.1.2](https://github.com/urbanairship/ios-library/releases/tag/19.1.2 - Updated the native plugin hooks on Android: - Renamed the class `AirshipPluginForwardListeners` to `AirshipPluginExtenders` - Renamed `AirshipPluginForwardListeners.notificationListener` to `AirshipPluginExtenders.forwardNotificationListner` - Replaced `AirshipPluginForwardDelegates.deepLinkListener` with `AirshipPluginExtenders.onDeepLink` - Added `AirshipPluginExtenders.onShouldDisplayForegroundNotification` to allow overriding foreground notification display behavior - Updated the native plugin hooks on iOS: - Renamed the class `AirshipPluginForwardDelegates` to `AirshipPluginExtenders` - Renamed `AirshipPluginForwardDelegates.pushNotificationDelegate` to `AirshipPluginExtenders.pushNotificationForwardDelegate`. The delegate must now implement the protocol `AirshipPluginPushNotificationDelegate` which is the same as `PushNotificationDelegate` but without the `extendPresentationOptions` method. - Renamed `AirshipPluginForwardDelegates.registrationDelegate` to `AirshipPluginExtenders.registrationForwardDelegate` - Replaced `AirshipPluginForwardDelegates.deepLinkDelegate` with `AirshipPluginExtenders.onDeepLink` - Added `AirshipPluginExtenders.onWillPresentForegroundNotification` to allow overriding foreground notification display behavior ## 22.1.0 March 26, 2025 Minor release that updates the Android SDK to 19.4.0 and the iOS SDK to 19.1.1 and fixes a privacy manager bug. ### Changes - Updated Android SDK to [19.4.0](https://github.com/urbanairship/android-library/releases/tag/19.4.0) - Updated iOS SDK to [19.1.1](https://github.com/urbanairship/ios-library/releases/tag/19.1.1) - Fixed an issue where the Privacy Manager sent multiple opt-out requests after features were disabled following being enabled. ## 22.0.0 March 11, 2025 Major release that regenerates the plugin for React Native 0.78 and updates Android SDK. ### Changes - Update plugin to be compatible with React Native 0.78 - Updated Android SDK to [19.3.0](https://github.com/urbanairship/android-library/releases/tag/19.3.0) ## 21.2.0 February 25, 2025 Patch release that updates the Android SDK to 19.2.0 and the iOS SDK to 19.1.0. ### Changes - Updated Android SDK to [19.2.0](https://github.com/urbanairship/android-library/releases/tag/19.2.0) - Updated iOS SDK to [19.1.0](https://github.com/urbanairship/ios-library/releases/tag/19.1.0) ## 21.1.0 February 12, 2025 Patch release that updates the Android SDK to 19.1.0 and fixes the `messageUnreadCount` on the `MessageCenterUpdated` event. ### Changes - Updated Android SDK to [19.1.0](https://github.com/urbanairship/android-library/releases/tag/19.1.0) - Fixed MessageCenterUpdatedEvent.messageUnreadCount on iOS. ## 21.0.2 February 7, 2025 Patch release that updates the iOS SDK to 19.0.3 and fixes a Swift 5 warning. ### Changes - Updated iOS SDK to [19.0.3](https://github.com/urbanairship/ios-library/releases/tag/19.0.3) ## 21.0.1 February 3, 2025 Patch release that updates the iOS SDK to 19.0.2 ### Changes - Updated iOS SDK to [19.0.2](https://github.com/urbanairship/ios-library/releases/tag/19.0.2) ## 21.0.0 January 25, 2025 Major release that updates the native SDKs to 19.0.0. ### Changes - Updated Android SDK to [19.0.0](https://github.com/urbanairship/android-library/releases/tag/19.0.0). - Updated iOS SDK to [19.0.0](https://github.com/urbanairship/ios-library/releases/tag/19.0.0). - Xcode 16.2+ is required. - Updated min version to iOS 15+ & Android 23+. - Added manifest entry to disable the headless JS service when a background push is received before the module is loaded. This is not recommended to use unless its conflicting with a hybrid application. To disable the task, set the metadata entry to false for key `"com.urbanairship.reactnative.ALLOW_HEADLESS_JS_TASK_BEFORE_MODULE"`. ## 20.2.0 December 20, 2024 Minor release that updates to the latest Airship SDKs and adds new Feature Flag APIs. ### Changes - Updated Android SDK to [18.6.0](https://github.com/urbanairship/android-library/releases/tag/18.6.0). - Updated iOS SDK to [18.14.1](https://github.com/urbanairship/ios-library/releases/tag/18.14.1). - Adds `Airship.featureFlagManager.resultCache` to cache a result that can be used when `Airship.featureFlagManager.flag` fails to resolve a result. ## 20.1.0 December 6, 2024 Minor release that updates the Android Airship SDK to 18.5.0 and iOS Airship SDK to 18.13.0 ### Changes - Updated Android SDK to [18.5.0](https://github.com/urbanairship/android-library/releases/tag/18.5.0). - Updated iOS SDK to [18.13.0](https://github.com/urbanairship/ios-library/releases/tag/18.13.0). ## 20.0.4 November 27, 2024 Patch release that updates the iOS Airship SDK to 18.12.2 and Android Airship SDK to 18.4.2 ### Changes - Updated Android SDK to [18.4.2](https://github.com/urbanairship/android-library/releases/tag/18.4.2). - Updated iOS SDK to [18.12.2](https://github.com/urbanairship/ios-library/releases/tag/18.12.2). ## 20.0.3 November 22, 2024 Patch release that updates the Android build to no longer require the react-native path and updates the Airship Android SDK to 18.4.1. ### Changes - Updated Airship Android SDK to [18.4.1](https://github.com/urbanairship/android-library/releases/tag/18.4.1) - Updated Android build.gradle file to no longer look up the React Native version ## 20.0.2 November 8, 2024 Patch release that resolves an issue with Firebase integrations and fixes an issue with opt-in checks when requestAuthorizationToUseNotifications is set to false on iOS. ### Changes - Updated Airship iOS SDK to [18.12.1](https://github.com/urbanairship/ios-library/releases/tag/18.12.1) - Fixed issues caused by swizzling conflicts with some Firebase framework integrations. - Fixed opt-in check permissions querying when requestAuthorizationToUseNotifications is set to false on iOS. ## 20.0.1 November 7, 2024 Patch release that fixes a crash when using both Airship and `@react-native-firebase/messaging`. ### Changes - Updated Airship iOS SDK to [18.12.1](https://github.com/urbanairship/ios-library/releases/tag/18.12.1) - Updated Airship Android SDK to [18.4.0](https://github.com/urbanairship/android-library/releases/tag/18.4.0) ## 20.0.0 October 26, 2024 Major version that makes it easier to include Airship in a hybrid app. The only breaking change is when extending the `AirshipPluginExtender` protocol on Java there is a new `extendConfig(Context, AirshipConfigOptions.Builder)` method to implement. Applications that are not using `AirshipPluginExtender` or using Kotlin are not affected by the breaking change. ### Changes - Fixed tracking live activities started from a push notification - Added methods to plugin extenders to extend the Airship Config options - Exposed forward listeners on Android with `AirshipPluginForwardListeners` and delegates on iOS with `AirshipPluginForwardDelegates`. These listeners and delegates are useful for hybrid apps that need to listen for events both natively and in React Native context ## 19.4.2 October 23, 2024 Patch release to fix live activities and live updates on react old architecture and update Android and iOS SDK. ### Changes - Fixed live activities and live updates on react old architecture. - Updated Airship Android SDK to [18.3.3](https://github.com/urbanairship/android-library/releases/tag/18.3.3) - Updated Airship iOS SDK to [18.11.1](https://github.com/urbanairship/ios-library/releases/tag/18.11.1) ## 19.4.1 October 9, 2024 Patch release to fix a compile issue with the old Architecture on Android. ### Changes - Fixed compile issue when using old architecture on Android. ## 19.4.0 October 4, 2024 ### Changes - Updated Airship Android SDK to [18.3.2](https://github.com/urbanairship/android-library/releases/tag/18.3.2) - Updated Airship iOS SDK to [18.10.0](https://github.com/urbanairship/ios-library/releases/tag/18.10.0) - Added `notificationPermissionStatus` to `PushNotificationStatus` - Added options to `enableUserNotifications` to specify the `PromptPermissionFallback` when enabling user notifications - Added new `showMessageCenter(messageId?: string)` and `showMessageView(messageId: string)` to `MessageCenter` to display the OOTB UI even if `autoLaunchDefaultMessageCenter` is disabled - Added new APIs to manage [iOS Live Activities](https://docs.airship.com/platform/mobile/ios-live-activities/) - Added new APIs to manage [Android Live Updates](https://docs.airship.com/platform/mobile/android-live-updates/) - Added a new [iOS plugin extender](https://docs.airship.com/platform/mobile/setup/sdk/react-native/#ios-2) to modify the native Airship SDK after takeOff - Added new [Android plugin extender](https://docs.airship.com/platform/mobile/setup/sdk/react-native/#android-2) to modify the native Airship SDK after takeOff - Deprecated `com.urbanairship.reactnative.AirshipExtender` for the common `com.urbanairship.android.framework.proxy.AirshipPluginExtender`. The manifest name also changed from `com.urbanairship.reactnative.AIRSHIP_EXTENDER` to `com.urbanairship.plugin.extender` ## 19.3.2 September 13, 2024 Patch release to fix a compile issue with the new Architecture on iOS and to fix a potential race condition on the event listeners when refreshing the JS bridge. ### Changes - Fixed compile issue when using new architecture on iOS - Fixed potential race condition on events listeners when the JS bridge refreshes ## 19.3.1 September 5, 2024 Patch release to fix compile issue with 19.3.0 when using the old architecture on Android. ### Changes - Fix compile issue when using old architecture on Android ## 19.3.0 August 30, 2024 Minor release that adds early access support for Embedded Content. ### Changes - Adds AirshipEmbeddedView and listener methods to Airship.inApp for Embedded Content. - Exposes the Airship session ID on Airship.analytics. ## 19.2.1 August 23, 2024 Patch release that fixes an issue with extras parsing on notifications ### Changes - Allow JsonObject accept undefined values - Adds support for dynamic frameworks on iOS ## 19.2.0 August 13, 2024 Minor release that fixes test devices audience check, holdout group experiments displays and in-app experience displays when resuming from a paused state. Apps that use in-app experiences are encouraged to update. ### Changes - Updated Android SDK to 18.1.6. - Updated iOS SDK to 18.7.2. - Fixed test devices audience check. - Fixed holdout group experiments displays. - Fixed in-app experience displays when resuming from a paused state. ## 19.1.0 July 17, 2024 Minor release that fixes enabling or disabling all Airship features using `FEATURES_ALL` and adds possibility to enable and disable `Feature.FeatureFlags`. ### Changes - Fixed enabling or disabling features using `FEATURE_ALL`. - Added possibility to enable and disable `Feature.FeatureFlags` using the privacy manager. ## 19.0.0 July 9, 2024 Major release that updates the Android Airship SDK to 18. ### Changes - Updated iOS SDK to 18.5.0 - Updated Android SDK to 18.1.1 - Added iOS logPrivacyLevel that can be set in the environments when calling takeOff ## 18.0.5 June 21, 2024 Patch release to fix a regression on iOS with In-App Automations, Scenes, and Surveys ignoring screen, version, and custom event triggers. Apps using those triggers that are on 18.0.4 should update. ### Changes - Updated iOS SDK to 18.4.1 - Fixed regression with triggers ## 18.0.4 June 21, 2024 Patch release that updates iOS SDK to 18.4.0 and updates the airship mobile framework proxy to 6.3.0 which includes a fix for event management. ### Changes - Updated iOS SDK to 18.4.0 - Updated airship-mobile-framework-proxy to 6.3.0 - Fixed Event Emitter bug ## 18.0.3 May 17, 2024 Patch release that updates to latest iOS SDK. ### Changes - Updated iOS SDK to 18.2.2 [View Older Releases](https://github.com/urbanairship/react-native-airship/releases?q=created%3A%3C2024-05-15&expanded=true) # React Native Module Resources > API documentation, source code, and changelogs for the Airship React Native module. ## Platform Support {#platform-support} | Feature | iOS | Android | |----------------------------------------|-----|---------| | Push Notifications | ✅ | ✅ | | Live Activities | ✅ | ❌ | | Live Updates | ❌ | ✅ | | In-App Experiences | ✅ | ✅ | | Custom Views | ✅ | ✅ | | Embedded Content | ✅ | ✅ | | Message Center | ✅ | ✅ | | Preference Center | ✅ | ✅ | | Feature Flags | ✅ | ✅ | | Analytics | ✅ | ✅ | | Contacts | ✅ | ✅ | | Tags, Attributes & Subscription Lists | ✅ | ✅ | | Privacy Controls | ✅ | ✅ | ## API References * [React Native API Documentation](https://www.airship.com/docs/reference/libraries/react-native/latest/) ## GitHub Samples * [React Native Sample App](https://github.com/urbanairship/react-native-airship/tree/main/example) * [Expo Sample App](https://github.com/urbanairship/airship-expo-sample) ## Source * [Source](https://github.com/urbanairship/react-native-airship) ## Changelog * [React Native Changelog](https://www.airship.com/docs/developer/sdk-integration/react-native/changelog/) ## License All Airship SDKs and frameworks are open sourced and licensed under Apache Software License 2.0. * [React Native License](https://github.com/urbanairship/react-native-airship/blob/main/LICENSE) ## SDK Installation Complete installation and configuration guides for the Airship React Native module. # Install and Set Up the React Native Module > How to install the Airship React Native module. The Airship React Native module provides a TypeScript-first interface for React Native apps. It wraps the native iOS and Android Airship SDKs, giving you full access to all platform features while maintaining a JavaScript/TypeScript developer experience with strong typing and modern async/await patterns. ## Requirements For supported versions and React Native compatibility, see [Supported Versions](https://github.com/urbanairship/react-native-airship?tab=readme-ov-file#supported-versions). ### iOS * Xcode `15.3+` * minimum deployment target iOS `15+` ### Android * minSdkVersion `23+` * compileSdkVersion `36+` ## Standard React Native Setup Install the plugin using yarn or npm: `yarn add @ua/react-native-airship` ## Expo Setup Apps using Expo's managed workflows can use the `airship-expo-plugin` to configure the project. `expo install airship-expo-plugin` `yarn add @ua/react-native-airship` ### Configure the plugin Add the plugin to the `app.json` with the app's config: ```js "plugins":[ [ "airship-expo-plugin", { "android":{ "icon": "./assets/ic_notification.png", "customNotificationChannels": "./assets/notification_channels.xml", "airshipExtender": "./assets/AirshipExtender.kt" }, "ios":{ "mode": "development", "notificationService": "./assets/NotificationService.swift", "notificationServiceInfo": "./assets/NotificationServiceExtension-Info.plist", "notificationServiceTargetName": "NotificationServiceExtension", "developmentTeamID": "MY_TEAM_ID", "deploymentTarget": "15", "airshipExtender": "./assets/AirshipPluginExtender.swift" } } ] ] ``` Android Config: - icon: Required. Local path to an image to use as the icon for push notifications. 96x96 all-white png with transparency. The name of the icon will be the resource name. - customNotificationChannels: Optional. The local path to a Custom Notification Channels resource file. - airshipExtender: Optional. The local path to a AirshipExtender.kt file. iOS Config: - mode: Required. The APNS entitlement. Either `development` or `production`. - notificationService: Optional. The local path to a custom Notification Service Extension or `DEFAULT_AIRSHIP_SERVICE_EXTENSION` for Airship's default one. - notificationServiceInfo: Optional. Airship will use a default one if not provided. The local path to a Notification Service Extension Info.plist. - notificationServiceTargetName: Optional. Defaults to NotificationServiceExtension if not provided. - developmentTeamID: Optional. The Apple Development Team ID used to configure the Notification Service Extension target. - deploymentTarget: Optional. The minimum Deployment Target version used to configure the Notification Service Extension target. Defaults to iOS 15. - airshipExtender: Optional. The local path to a AirshipPluginExtender.swift file. ## Calling TakeOff `takeOff` should be called in a standard application at the beginning of the lifecycle. Once `takeOff` is called, the config will be stored and applied for future app inits. If `takeOff` is called again with a different config, the new config will not be applied until the next app init. ```ts import Airship from '@ua/react-native-airship'; Airship.takeOff({ default: { appKey: "YOUR_APP_KEY", appSecret: "YOUR_APP_SECRET" }, site: "us", // use "eu" for EU cloud projects urlAllowList: ["*"], android: { notificationConfig: { icon: "ic_notification", accentColor: "#00ff00" } } }); ``` For a complete list of configuration options, see the [AirshipConfig reference](https://www.airship.com/docs/reference/libraries/react-native/latest/interfaces/AirshipConfig.html). ## Test the integration After completing the setup, verify your integration: 1. **Build and run your app** on your iOS or Android device/simulator/emulator. 2. **Check the console output** for Airship channel creation: - **iOS**: Look for a log message in Xcode console: `Channel ID: ` - **Android**: Look for a log message in logcat: `Airship channel created: ` - The channel ID confirms successful SDK initialization. - For more detailed logging, see [Logging](https://www.airship.com/docs/developer/sdk-integration/react-native/installation/logging/). If you see the channel ID in the console and no errors, your integration is successful. ## Next steps - [Advanced Configuration](https://www.airship.com/docs/developer/sdk-integration/react-native/installation/advanced-configuration/): Configure URL allowlists and other advanced settings - [Extending Airship](https://www.airship.com/docs/developer/sdk-integration/react-native/installation/extending-airship/): Access native SDK features for advanced customization - [Push Notifications](https://www.airship.com/docs/developer/sdk-integration/react-native/push-notifications/getting-started/): Configure push notifications - [Deep Links](https://www.airship.com/docs/developer/sdk-integration/react-native/deep-links/): Handle deep links in your app If you don't see a channel ID or encounter errors during initialization, see [Troubleshooting Initialization](https://www.airship.com/docs/developer/sdk-integration/react-native/troubleshooting/initialization/) for common problems and solutions. # Logging > Configure log levels and privacy settings to control how the Airship SDK logs messages. The Airship SDK provides configurable log levels to help you debug issues without overwhelming the console. By default, the log level is set to **Info** for development builds and **Error** for production builds to ensure clean logs in a live environment. ## Log levels The following log levels are available, ordered from most to least verbose. | Log Level | Description | | :-------- | :---------- | | **Verbose** | Reports highly detailed SDK status, which is useful for deep debugging and troubleshooting. | | **Debug** | Reports general SDK status with more detailed information than `Info`. | | **Info** | Reports general SDK status and lifecycle events. | | **Warning** | Used for API deprecations, invalid setup, and other potentially problematic situations that are generally recoverable. | | **Error** | Used for critical errors, exceptions, and other situations that the SDK cannot gracefully handle. | | **None** | Disables all logging. | ## Configuring log levels You can set the log level in the Airship config options that are passed during takeOff. This setting acts as a minimum, and only logs at that level and higher will be logged. ```typescript // Available log levels: verbose, debug, info, warning, none await Airship.takeOff({ default: { logLevel: "verbose" }, ... }); ``` > **Note:** Due to how takeOff caches config, you may need to restart the app after the new takeOff before the log levels take effect. ## Log privacy levels For better security in production environments, you can control the visibility of log contents using privacy levels. This is especially useful when you need to debug a release build without exposing sensitive information. ### private (default) This is the default setting, designed to protect data in a production environment. * **iOS**: Uses `os.Logger` to log all messages at the `private` level. The content of most logs will be redacted and will not be visible in the Console app unless a special profile is installed on the device. * **Android**: Uses the standard `android.util.Log`. In production builds, `verbose` and `debug` messages are completely dropped and will not be logged. ### public This setting increases log visibility, making it easier to capture detailed information from release builds. * **iOS**: All logs are sent to `os.Logger` with a `public` privacy level, preventing their content from being redacted. * **Android & iOS**: To ensure visibility in production builds, `verbose` and `debug` messages are automatically elevated to the `info` log level. ## Setting the privacy level You can set the privacy level in the Airship config options that are passed during takeOff. ```typescript await Airship.takeOff({ default: { logLevel: "verbose", ios: { logPrivacyLevel: "public" }, android: { logPrivacyLevel: "public" } }, ... }); ``` > **Note:** Due to how takeOff caches config, you may need to restart the app after the new takeOff before the log levels take effect. # Locale > Configure locale behavior and override the default locale that Airship uses. The Airship SDK is localized in 48 different languages for all strings included within the SDK. The strings within the app will automatically use the device's or app's configured [Locale](https://www.airship.com/docs/reference/glossary/#locale). Airship uses the user's locale for various locale-sensitive tasks, including selecting the language for messages and reporting for analytics. Apps can override the locale so that Airship uses a different locale than the device's current locale for messaging. ## Overriding the locale You can override the locale programmatically at runtime, which takes precedence over the device's locale settings. ```typescript await Airship.locale.setLocaleOverride("de"); ``` ## Clearing the locale override To remove a locale override and return to using the device's locale: ```typescript await Airship.locale.clearLocaleOverride(); ``` ## Getting the current locale To retrieve the locale that Airship is currently using: ```typescript const locale = await Airship.locale.getCurrentLocale(); ``` # Advanced Configuration > Configure advanced settings like URL allowlists and other options for the Airship React Native module. ## URL Allowlist The URL allowlist controls which URLs the Airship SDK is able to act on. Configure the URL allowlist in your `takeOff` config options using the following properties: - `urlAllowListScopeOpenUrl`: Only URLs allowed for this scope can be opened from an action, displayed in landing page, displayed in an HTML in-app message, or displayed as media in an In-App Automation. Defaults to any Airship-originated URLs and YouTube URLs. - `urlAllowListScopeJavaScriptInterface`: These URLs are checked before the Airship JavaScript interface is injected into the webview. Defaults to any Airship-originated URLs. - `urlAllowList`: Both scopes are applied to these URLs. ```ts Airship.takeOff({ default: { appKey: "YOUR_APP_KEY", appSecret: "YOUR_APP_SECRET" }, site: "us", urlAllowList: ["*"], // Accept all URLs // Or configure specific scopes: urlAllowListScopeOpenUrl: ["https://example.com/*", "https://*.youtube.com/*"], urlAllowListScopeJavaScriptInterface: ["https://example.com/*"] }); ``` **Valid URL pattern syntax** ```text := '*' | '://'/ | '://' | ':/' | ':///' := := '*' | '*.' | := ``` To accept any URL within the SDK, set the `urlAllowList` to `["*"]`. For a complete list of configuration options, see the [AirshipConfig reference](https://www.airship.com/docs/reference/libraries/react-native/latest/interfaces/AirshipConfig.html). # Extend Airship > How to extend the Airship React Native module to access native iOS and Android SDK features not exposed through the React Native API. You can provide a plugin extender that will be automatically loaded for the app. The extender can be used to modify the Airship config before SDK initialization and to access the underlying native SDK once Airship is ready. This gives the app a chance to customize parts of Airship that are not configurable through React Native, such as setting up [iOS Live Activities](https://www.airship.com/docs/developer/sdk-integration/react-native/live-activities/) and [Android Live Updates](https://www.airship.com/docs/developer/sdk-integration/react-native/live-updates/). ## iOS For iOS, create a Swift file named `AirshipPluginExtender.swift` and needs to be included in the main app target. Make sure the class has the `@objc(AirshipPluginExtender)` annotation and inherits `AirshipPluginExtenderProtocol`. ```swift import Foundation import AirshipKit import AirshipFrameworkProxy import ActivityKit @objc(AirshipPluginExtender) public class AirshipPluginExtender: NSObject, AirshipPluginExtenderProtocol { public static func onAirshipReady() { // Called when Airship is ready on the MainActor } public static func extendConfig(config: inout AirshipConfig) { // Called to extend the AirshipConfig before SDK initialization } } ``` ## Android Create a file in the App's src directory named `AirshipExtender`. It needs to extend `com.urbanairship.android.framework.proxy.AirshipPluginExtender` and have an empty constructor. ```kotlin // Replace with your package package com.example import android.content.Context import androidx.annotation.Keep import com.urbanairship.AirshipConfigOptions import com.urbanairship.UAirship import com.urbanairship.android.framework.proxy.AirshipPluginExtender @Keep public final class AirshipExtender: AirshipPluginExtender { override fun onAirshipReady(context: Context, airship: UAirship) { // Called when Airship is ready on a background thread. // Avoid doing long running, blocking work or it will delay Airship } override fun extendConfig( context: Context, configBuilder: AirshipConfigOptions.Builder ): AirshipConfigOptions.Builder { // Called to extend the AirshipConfig before SDK initialization return configBuilder } } ``` Register the extender in the manifest: ```xml ``` ## Push Notifications Configure and implement push notifications for iOS and Android platforms. # Push Notifications > How to configure your application to receive and respond to notifications. Before setting up push notifications in your app, you need to configure push services in the Airship dashboard. See [iOS Channel Configuration](https://www.airship.com/docs/guides/getting-started/developers/configure-channels/#ios-channel-configuration) for APNs setup and [Android Channel Configuration](https://www.airship.com/docs/guides/getting-started/developers/configure-channels/#android-channel-configuration) for FCM setup. ## Platform Setup Before you can send and receive push notifications, you need to configure your app for the platform(s) you're targeting. ### iOS #### Standard React Native #### Enable Push Notifications Capability 1. Open your project in Xcode. 2. Click on your project in the Project Navigator. 3. Select your main app target and then click the **Signing & Capabilities** tab. 4. If you do not see Push Notifications enabled, click **+ Capability** and add **Push Notifications**. ![Adding the Push Notifications capability in Xcode](https://www.airship.com/docs/images/ios-enable-push-notifications-capabilities_hu_2e1789fffb02612b.webp) *Adding the Push Notifications capability in Xcode* #### Enable Background Modes 1. Select your main app target and then click the **Signing & Capabilities** tab. 2. Click **+ Capability** and add **Background Modes**. ![Adding the Background Modes capability in Xcode](https://www.airship.com/docs/images/ios-enable-background-mode-capabilities_hu_f135d9fec0ba0d06.webp) *Adding the Background Modes capability in Xcode* 3. In the **Background Modes** section, select the **Remote notifications** checkbox. ![Enabling Remote notifications in Background Modes](https://www.airship.com/docs/images/ios-background-mode-remote-notifications_hu_7e38b08288fcd7b2.webp) *Enabling Remote notifications in Background Modes* #### Notification Service Extension

To take advantage of notification attachments, such as images, animated gifs, and video, you will need to create a notification service extension.

Follow the steps in the [iOS Notification Service Extension Guide](https://www.airship.com/docs/developer/sdk-integration/apple/push-notifications/notification-service-extension/). #### Expo The Airship Expo plugin automatically configures iOS capabilities (Push Notifications and Background Modes) and the Notification Service Extension. No manual Xcode configuration is required. ### Android Configure Firebase Cloud Messaging (FCM) to enable push notifications on Android. #### FCM Setup #### Standard React Native 1. Download the Android Firebase configuration file `google-services.json` from the application's Firebase console into the root directory at `android/app/google-services.json`. If your react-native application does not have an associated app in the Firebase console, follow the [FCM setup instructions](https://www.airship.com/docs/developer/sdk-integration/android/installation/getting-started/#fcm-setup) to set one up. #### Expo Expo automatically handles the `google-services.json` file through its build process. See the [Expo documentation](https://docs.expo.dev/push-notifications/fcm-credentials/) for details on configuring FCM credentials. #### HMS Setup 1. Follow [Huawei's documentation](https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/android-integrating-sdk-0000001050040084) to set up the HMS SDK. > **Note:** Airship requires HMS Core Push SDK 6.3.0.304 or newer. 2. Add `airshipHmsEnabled=true` to the app's gradle.properties. #### Notification Configuration Configure the notification icon and accent color in your `takeOff` config: ```ts Airship.takeOff({ default: { appKey: "YOUR_APP_KEY", appSecret: "YOUR_APP_SECRET" }, site: "us", android: { notificationConfig: { icon: "ic_notification", accentColor: "#00ff00" } } }); ``` See the [React Native Setup guide](https://www.airship.com/docs/developer/sdk-integration/react-native/installation/getting-started/) for complete `takeOff` configuration options. ## Enable User Notifications The Airship SDK distinguishes between *user notifications* (visible to users) and *silent push notifications* (background data delivery). User notifications require explicit permission from the user. By default, user notifications are disabled. Enable them when you want to show visible notifications to users. ### Basic Enablement The simplest way to enable user notifications is with `setUserNotificationsEnabled()`: ```typescript await Airship.push.setUserNotificationsEnabled(true); ``` This will prompt the user for permission if not already granted. However, it does not provide feedback on whether the user accepted or denied the permission. > **Note:** For apps that target Android 13 (API 33) and above, enabling user notifications will display a runtime permission prompt. > > To increase the likelihood that the user will accept, you should avoid prompting the user for permission immediately on app startup, and instead wait for a more appropriate time to prompt for notification permission. ### Async Enablement with Fallback For more control over the permission flow, use `enableUserNotifications()` which returns the permission result and supports a fallback option: ```typescript // Enable with system settings fallback const granted = await Airship.push.enableUserNotifications({ fallback: PromptPermissionFallback.SystemSettings }); if (granted) { console.log('Notifications enabled'); } else { console.log('Notifications denied'); } ``` The `SystemSettings` fallback option will prompt the user to open system settings if permission is denied on iOS or denied silently on Android. This gives users a second chance to enable notifications if they initially declined. ### Checking Notification Status To check if user notifications are currently enabled: ```typescript const enabled = await Airship.push.isUserNotificationsEnabled(); ``` For more detailed status information, use `getNotificationStatus()`: ```typescript const status = await Airship.push.getNotificationStatus(); console.log('Are notifications allowed:', status.areNotificationsAllowed); console.log('Is opted in:', status.isOptedIn); ``` To monitor notification status changes in real-time: ```typescript Airship.addListener(EventType.PushNotificationStatusChangedStatus, (event) => { console.log('Notification status changed:', event.status); console.log('Is opted in:', event.status.isOptedIn); }); ``` ### Getting the Registration Token To get the platform-specific push token (APNs token on iOS, FCM token on Android): ```typescript const token = await Airship.push.getRegistrationToken(); ``` For more advanced event handling and token updates, see [Handling Notification Events](https://www.airship.com/docs/developer/sdk-integration/react-native/push-notifications/handling-notification-events/). If push notifications aren't working as expected, see [Troubleshooting Push Notifications](https://www.airship.com/docs/developer/sdk-integration/react-native/troubleshooting/push-notifications/) to check notification status and fix common issues. # Notification Events > Listen for push notification events, handle user responses, and manage active notifications. The Airship SDK provides event listeners for when a push is received or a notification is interacted with. Apps can use these events for custom push processing. ## Notification Events The SDK provides several event listeners for handling push notifications at different stages. ### Push Received Listen for when a push notification is received: ```typescript Airship.addListener(EventType.PushReceived, (event) => { console.log('Push received:', event.pushPayload); // Handle push received event }); ``` This event fires when a push notification arrives, regardless of whether the app is in the foreground or background. ### Notification Response Listen for when a user interacts with a notification: ```typescript Airship.addListener(EventType.NotificationResponse, (response) => { console.log('Notification tapped:', response); console.log('Action ID:', response.actionId); // Handle the notification response if (response.actionId === 'custom_action') { // Handle custom action } }); ``` This event fires when a user taps on a notification or a notification action button. ### Registration Token Updates Listen for when the push registration token is generated or updated: ```typescript Airship.addListener(EventType.PushTokenReceived, (event) => { console.log('Push token:', event.pushToken); // Send token to your backend if needed }); ``` You can also retrieve the current token at any time: ```typescript const token = await Airship.push.getRegistrationToken(); ``` ### Notification Status Changes Monitor changes to notification permission status: ```typescript Airship.addListener(EventType.PushNotificationStatusChangedStatus, (event) => { console.log('Notification status changed:', event.status); console.log('Is opted in:', event.status.isOptedIn); }); ``` ## Managing Active Notifications You can retrieve and clear notifications that are currently displayed in the notification center. ### Get Active Notifications Retrieve the list of currently displayed notifications: ```typescript const notifications = await Airship.push.getActiveNotifications(); console.log('Active notifications:', notifications); ``` > **Note:** On Android, this list only includes notifications sent through Airship. ### Clear Notifications Clear all notifications for the app: ```typescript Airship.push.clearNotifications(); ``` Clear a specific notification by identifier: ```typescript Airship.push.clearNotification(identifier); ``` > **Note:** On Android, you can use this method to clear notifications outside of Airship. The identifier is in the format `:`. ## Silent Notifications Silent notifications are push messages that do not present a notification to the user. These are typically used to briefly wake the app from a background state to perform processing tasks or fetch remote content. > **Important:** We recommend that you thoroughly test your implementation to confirm that silent notifications do not generate any device notifications. ### Platform Configuration **iOS**: Set the `content_available` property to `true` in the [iOS override object](https://www.airship.com/docs/developer/rest-api/ua/schemas/platform-overrides/#iosoverrideobject). **Android**: All push messages are delivered in the background. By default, Airship will treat messages without an `alert` as silent. > **Note:** Silent pushes do not have guaranteed delivery. Factors affecting delivery include battery life, WiFi connectivity, and the number of silent pushes sent within a recent time period. These metrics are determined solely by iOS/Android and APNs/FCM. > > Silent push is best used for supplementing regular app behavior rather than providing critical functionality. For example, an app could use a silent push to pre-fetch new data ahead of time to reduce load times when the app is later launched by the user. ### Handling Silent Notifications Silent notifications will trigger the `PushReceived` event but will not display a notification to the user: ```typescript Airship.addListener(EventType.PushReceived, (event) => { if (!event.pushPayload.alert) { console.log('Silent push received'); // Perform background work } }); ``` # Customize Notifications > Configure notification options, foreground presentation, badges, and custom categories. ## iOS Notification Options By default, the Airship SDK will request `Alert`, `Badge`, and `Sound` notification options for remote notifications. This can be configured by setting notification options before enabling user notifications. ```typescript await Airship.push.iOS.setNotificationOptions([ iOS.NotificationOption.Alert, iOS.NotificationOption.Badge, iOS.NotificationOption.Sound, ]); ``` ### Provisional Authorization Apps can request provisional authorization along with the usual notification options. When requesting provisional authorization apps do not need to prompt the user for permission initially, and notifications will be delivered in a non-interruptive manner to the Notification Center until the user explicitly chooses to keep delivering messages either prominently or quietly. ```typescript await Airship.push.iOS.setNotificationOptions([ iOS.NotificationOption.Alert, iOS.NotificationOption.Badge, iOS.NotificationOption.Sound, iOS.NotificationOption.Provisional, ]); ``` ### Foreground Presentation Options When a push is received in the foreground on iOS, how the notification is displayed to the user is controlled by foreground presentation options. By default, the SDK will not set any options so the notification will be silenced. #### Global Foreground Presentation Options Set default foreground presentation options for all notifications: ```typescript await Airship.push.iOS.setForegroundPresentationOptions([ iOS.ForegroundPresentationOption.List, iOS.ForegroundPresentationOption.Badge, iOS.ForegroundPresentationOption.Sound, ]); ``` #### Per-Notification Foreground Presentation Options For more control, you can override presentation options on a per-notification basis using a callback: ```typescript Airship.push.iOS.setForegroundPresentationOptionsCallback(async (pushPayload) => { // Check the push payload and return custom options if (pushPayload.extras?.highPriority) { // Show high priority notifications with all options return [ iOS.ForegroundPresentationOption.List, iOS.ForegroundPresentationOption.Banner, iOS.ForegroundPresentationOption.Sound, iOS.ForegroundPresentationOption.Badge ]; } // Return null to use the default options return null; }); ``` The callback receives the full push payload and should return quickly to avoid delaying notification delivery. Returning `null` uses the default options set with `setForegroundPresentationOptions()`. ### Badges The badge on iOS presents a counter on top of the application icon. You can control this directly through Airship. ```typescript // Set badge number await Airship.push.iOS.setBadgeNumber(20); // Reset badge await Airship.push.iOS.setBadgeNumber(0); // Enable auto-badge await Airship.push.iOS.setAutobadgeEnabled(true); ``` > **Important:** When using auto-badge, only modify the badge value through Airship methods to ensure the value stays in sync. ### Quiet Time Quiet time allows you to suppress notifications during specific hours. Notifications are still received but won't be displayed to the user during the quiet time window. > **Note:** Quiet time is only supported on iOS. ## Android Notification Configuration You can configure Android-specific notification behaviors and settings. ### Foreground Display Control By default, push notifications received while the app is in the foreground on Android are displayed to the user. You can control this behavior on a per-notification basis using a predicate: ```typescript Airship.push.android.setForegroundDisplayPredicate(async (pushPayload) => { // Check the push payload and return true to display, false to suppress if (pushPayload.extras?.silent) { return false; // Don't display notifications marked as silent } // Display all other notifications return true; }); ``` The predicate receives the full push payload and should return quickly to avoid delaying notification delivery. Return `true` to display the notification or `false` to suppress it. ## Adding Custom Notification Categories The Airship module supports adding custom notification categories on iOS, and custom notification action button groups on Android, by way of a specially named plist and XML file, respectively. Once these files are added to your iOS and Android projects, the module will load this file at runtime and automatically register your custom categories with the Airship API. ### iOS Setup Add a new plist file to your app's Xcode project, named `UACustomNotificationCategories.plist`, and make sure to add the file to your application's target. The structure of the plist file follows the format used by the core Airship SDK for its default categories. As a starting point, see the example below. Note that key and string values prefixed with **"ua_"** are reserved by the Airship SDK. **UACustomNotificationCategories.plist** ```xml yes_no_background authenticationRequired foreground identifier yes title Yes title_resource notification_button_yes authenticationRequired foreground identifier no title No title_resource notification_button_no yes_no_foreground foreground identifier yes title Yes title_resource notification_button_yes authenticationRequired foreground identifier no title No title_resource notification_button_no ``` ### Android Setup First, add a new xml file to your app's `main/res/xml` directory, named `ua_custom_notification_buttons.xml`. As with the iOS example above, the structure of this XML file follows the format used by the core Airship SDK for its default categories. And as before, entities and resource names with the **"ua_"** prefix are reserved by the Airship SDK. A similar example is given below. The icon and label resources shown are only examples; to create custom categories of your own, you should either use built-in Android resources or supply resources defined by your app. **ua_custom_notification_buttons.xml** ```xml ``` ## Adding Custom Notification Channels (Android) The Airship module also supports adding custom notification channels on Android, by supplying a specially named XML file. First, add a new xml file to your app's `main/res/xml` directory, named `ua_custom_notification_channels.xml`. The structure of this XML file follows the format used by the core Airship SDK for its default notification channels. A simple example is shown below. Note that entities and resource names with the **"ua_"** prefix are reserved by the Airship SDK. To create custom notification channels of your own, you should either use built-in Android resources or supply resources defined by your app. **ua_custom_notification_channels.xml** ```xml ``` ## In-App Experiences Configure and control In-App Experiences in React Native applications. # In-App Experiences > Pause, resume, and control display timing for In-App Experiences. In-App Experiences are automatically enabled when you integrate the Airship SDK. Use these methods to control when and how they are displayed. ## Pausing and Resuming Display You can pause and resume In-App Experiences to control when they are displayed to users. ```typescript // Pause in-app experiences await Airship.inApp.setPaused(true) // Resume in-app experiences await Airship.inApp.setPaused(false) // Check if paused const isPaused = await Airship.inApp.isPaused() ``` ### Auto-Pause on Launch You can configure the SDK to automatically pause In-App Experiences on launch. This is useful if you want to defer showing In-App Experiences until after onboarding or other critical app flows. ```typescript await Airship.takeOff({ production: { appKey: "", appSecret: "" }, development: { appKey: "", appSecret: "" }, inProduction: true, site: "us", autoPauseInAppAutomationOnLaunch: true }) ``` See the [React Native Plugin Setup guide](https://www.airship.com/docs/developer/sdk-integration/react-native/installation/getting-started/) for complete `takeOff` configuration options. When you're ready to display In-App Experiences, call `setPaused(false)`: ```typescript await Airship.inApp.setPaused(false) ``` ## Display Interval Control the minimum time between In-App Experience displays to avoid overwhelming users. ```typescript // Set display interval to 5 seconds await Airship.inApp.setDisplayInterval(5000) // Get current display interval const interval = await Airship.inApp.getDisplayInterval() ``` The display interval is the minimum time (in milliseconds) that must pass between displaying In-App Experiences. # Embedded Content > Integrate Embedded Content into your React Native app to display Scene content directly within your app's screens. For information about Embedded Content, including overview, use cases, and how to create Embedded Content view styles and Scenes, see [Embedded Content]({{< ref "/guides/features/messaging/scenes/embedded-content.md" >}}). ## Adding an embedded view The `AirshipEmbeddedView` component defines a place for Airship Embedded Content to be displayed. When defining an `AirshipEmbeddedView`, specify the `embeddedId` for the content it should display. The value of the `embeddedId` must be the ID of an Embedded Content view style in your project. **Basic integration** ```typescript import { AirshipEmbeddedView } from '@ua/react-native-airship' // Show any "home_banner" Embedded Content ``` ## Sizing The `AirshipEmbeddedView` accepts an optional `style` prop for controlling its dimensions and layout. You can use standard React Native `ViewStyle` properties to set width, height, and other layout constraints. **Custom sizing** ```typescript ``` ## Checking if embedded content is ready Use `Airship.inApp.isEmbeddedReady` to check if embedded content is currently available for a given ID: ```typescript import Airship from '@ua/react-native-airship' const isReady = Airship.inApp.isEmbeddedReady("home_banner") ``` ## Listening for embedded content updates Use `Airship.inApp.addEmbeddedReadyListener` to listen for changes in the availability of embedded content for a given ID. The listener receives a boolean indicating whether content is ready to display. The listener is called immediately with the current state when first added, and then again whenever the state changes. **Embedded ready listener** ```typescript import Airship from '@ua/react-native-airship' const subscription = Airship.inApp.addEmbeddedReadyListener("home_banner", (isReady) => { console.log("home_banner is ready:", isReady) }) // Remove the listener when no longer needed subscription.remove() ``` ## Showing a placeholder when content is unavailable The `AirshipEmbeddedView` renders nothing when no content is available. Use `addEmbeddedReadyListener` to toggle between a placeholder and the embedded view based on content availability. **Embedded view with placeholder** ```typescript import React, { useState, useEffect } from 'react' import { View, Text, StyleSheet } from 'react-native' import Airship, { AirshipEmbeddedView } from '@ua/react-native-airship' function HomeBanner() { const [isReady, setIsReady] = useState( Airship.inApp.isEmbeddedReady("home_banner") ) useEffect(() => { const subscription = Airship.inApp.addEmbeddedReadyListener( "home_banner", (ready) => { setIsReady(ready) } ) return () => { subscription.remove() } }, []) if (!isReady) { return ( No content available ) } return ( ) } const styles = StyleSheet.create({ placeholder: { width: '100%', height: 200, justifyContent: 'center', alignItems: 'center', }, banner: { width: '100%', minHeight: 200, }, }) ``` # Custom Views > Register custom native views to use within Scenes. A *Custom View* is a native view from your mobile or web application embedded into a Scene. Custom Views can display any native content your app exposes, so you can reuse that existing content within any screen in a Scene. Custom Views allow you to embed native iOS and Android views within Scenes, giving you full control over design and layout while leveraging Airship's targeting and orchestration capabilities. ## Requirements To use Custom Views in React Native, you must extend the native Airship modules using the `AirshipPluginExtender`. See [Extending Airship](https://www.airship.com/docs/developer/sdk-integration/react-native/installation/extending-airship/) for setup instructions. ## Registering Custom Views Custom Views must be registered on each native platform separately: ### iOS See the [Apple Custom Views documentation](https://www.airship.com/docs/developer/sdk-integration/apple/in-app-experiences/custom-views/) for detailed implementation instructions. Custom Views should be registered after takeOff in your native iOS code: ```swift import AirshipKit @objc(AirshipExtender) class AirshipExtender: NSObject, AirshipPluginExtenderDelegate { func onAirshipReady() { // Register custom views AirshipCustomViewManager.shared.register(name: "my-custom-view") { args in // Return your SwiftUI view MyCustomView(args: args) } } } ``` ### Android See the [Android Custom Views documentation](https://www.airship.com/docs/developer/sdk-integration/android/in-app-experiences/custom-views/) for detailed implementation instructions. Custom Views should be registered during the `onAirshipReady` callback in your native Android code: ```kotlin import com.urbanairship.AirshipCustomViewManager class AirshipExtender : AirshipPluginExtender { override fun onAirshipReady(context: Context) { // Register custom views AirshipCustomViewManager.register("my-custom-view") { context, args -> // Return your Android View MyCustomView(context, args) } } } ``` ## Using Custom Views Once registered, Custom Views can be added to Scenes in the Airship dashboard: 1. Create or edit a Scene 2. Add the **Custom View** content element to a screen 3. Enter the view name (e.g., `my-custom-view`) that matches the name you registered in your native code 4. Optionally add key-value pairs to pass custom properties to the view The native view will be displayed within the Scene with the properties you configured. ## Message Center Implement Message Center to provide an inbox for rich HTML-based messages. # Message Center > The default Message Center is available for React Native with minimal integration required. Basic theming options are supported. Message Center provides an inbox for rich, HTML-based messages. Learn more about Message Center in our [feature guide](https://www.airship.com/docs/guides/features/messaging/message-center/). ## Display the Message Center Display the Message Center with a single method call: ```ts await Airship.messageCenter.display(); ``` To customize the Message Center UI or navigation, see [Embedding the Message Center](https://www.airship.com/docs/developer/sdk-integration/react-native/message-center/embedding/). ## Fetch Messages Retrieve messages from the inbox: ```ts const messages = await Airship.messageCenter.getMessages(); ``` ## Listen for Message Updates Subscribe to message updates using event listeners: ```ts Airship.addListener(EventType.MessageCenterUpdated, () => { // Update your UI Airship.messageCenter.getMessages().then((messages) => { // Handle messages }); }); ``` ## Listen for Unread Count Changes Subscribe to unread count updates: ```ts const unreadCount = await Airship.messageCenter.getUnreadCount(); // Update badge or UI ``` ## Refresh Messages Manually refresh the message list from the server: ```ts try { await Airship.messageCenter.refreshMessages(); } catch (error) { console.log('Unable to refresh inbox: ', error); } ``` ## Mark Messages as Read Mark one or more messages as read: ```ts try { await Airship.messageCenter.markMessageRead('message-id'); } catch (error) { console.log('Unable to mark message as read: ', error); } ``` ## Delete Messages Delete one or more messages: ```ts try { await Airship.messageCenter.deleteMessage('message-id'); } catch (error) { console.log('Unable to delete message: ', error); } ``` # Embed the Message Center > Airship's SDK provides a simple interface for managing the Message Center within your application. This guide covers creating custom Message Center implementations for React Native applications. ## Override Default Display Behavior To use a custom Message Center implementation instead of the default UI, disable auto-launch and add a listener to handle display events: ```ts // Disable the default UI Airship.messageCenter.setAutoLaunchDefaultMessageCenter(false); // Add a listener to handle display events Airship.addListener(EventType.DisplayMessageCenter, (event) => { if (event.messageId) { // Navigate to specific message } else { // Navigate to message center } }); ``` ## Custom Message Center Implementation For complete control over Message Center placement and navigation, create a custom implementation using the Message Center components. ### Using the MessageView The `MessageView` component can be used to display individual messages: ```ts ``` ### Example: Custom Message Center Inbox Here's an example of a complete Message Center inbox implementation: ```ts import * as React from 'react'; import { Text, View, FlatList, TouchableHighlight, RefreshControl, } from 'react-native'; import Moment from 'moment'; import Airship, { Subscription, EventType, InboxMessage } from '@ua/react-native-airship'; interface MessageCenterScreenProps { navigation: any; } function Item({ message, navigation }: { message: any; navigation: any }) { return ( navigation.navigate('MessageDetails', { messageId: message.id, title: message.title, }) } > {message.title} {Moment(message.sentDate).format('MM/DD/YYYY')} ); } export default class MessageCenterScreen extends React.Component< MessageCenterScreenProps, { messages: InboxMessage[]; refreshing: boolean; } > { private updateSubscription?: Subscription; constructor(props: MessageCenterScreenProps) { super(props); this.state = { messages: [], refreshing: true, }; this.refreshMessageCenter = this.refreshMessageCenter.bind(this); this.handleUpdateMessageList = this.handleUpdateMessageList.bind(this); } componentDidMount(): void { this.updateSubscription = Airship.addListener( EventType.MessageCenterUpdated, this.handleUpdateMessageList ); this.handleUpdateMessageList(); } componentWillUnmount(): void { this.updateSubscription?.remove(); } handleUpdateMessageList() { Airship.messageCenter.getMessages().then((data) => { this.setState({ messages: data, refreshing: false, }); }); } refreshMessageCenter() { Airship.messageCenter .refreshMessages() .then(() => { this.setState({ refreshing: false, }); }) .catch((error) => { console.log('failed to refresh', error); }); } render() { return ( ( )} keyExtractor={(item) => item.id} refreshControl={ } /> ); } } ``` ### Example: Message Detail Screen Here's an example of a message detail screen: ```ts import * as React from 'react'; import { View, ActivityIndicator, Alert } from 'react-native'; import { MessageView } from '@ua/react-native-airship'; interface MessageScreenProps { navigation: any; route: any; } export default class MessageScreen extends React.Component< MessageScreenProps, { animating: boolean; } > { constructor(props: MessageScreenProps) { super(props); this.state = { animating: true, }; this.startLoading = this.startLoading.bind(this); this.finishLoading = this.finishLoading.bind(this); this.failedLoading = this.failedLoading.bind(this); } startLoading() { this.setState({ animating: true }); } finishLoading() { this.setState({ animating: false }); } failedLoading() { this.setState({ animating: false }); Alert.alert('Error', 'Unable to load message. Please try again later', [ { text: 'OK', onPress: () => this.props.navigation.goBack() }, ]); } render() { const { params } = this.props.route; const messageId = params ? params.messageId : ''; return ( {this.state.animating && ( )} ); } } ``` For more examples, see our [sample app](https://github.com/urbanairship/react-native-module/tree/main/example). ## Preference Center Implement Preference Center to let users control their subscription preferences. # Preference Center > Preference Center allows users to opt in and out of subscription lists configured via the Airship Dashboard. > **Important:** Airship Preference Centers are widgets that can be embedded in a page in an app or website. Please verify with your legal team that your full Preference Center page, including any web page for email Preference Centers, is compliant with local privacy regulations. Preference Center provides a pre-built UI for users to manage their subscription preferences. Learn more in the [Preference Center user guide](https://www.airship.com/docs/guides/messaging/features/preference-centers/). ## Display a Preference Center Display a Preference Center with a single method call: ```ts await Airship.preferenceCenter.display("preference-center-id"); ``` To build a custom Preference Center UI, see [Embedding the Preference Center](https://www.airship.com/docs/developer/sdk-integration/react-native/preference-center/embedding/). # Embed the Preference Center > Create custom Preference Center UIs by fetching the config and building your own subscription management interface. This guide covers creating custom Preference Center UIs for React Native applications. Unlike the default Preference Center, you'll build your own UI from scratch using the Preference Center configuration and subscription list APIs. ## Override Default Display Behavior To use a custom Preference Center instead of the default UI, disable auto-launch for the specific Preference Center ID and handle display events: ```ts // Disable the OOTB UI for this Preference Center Airship.preferenceCenter.setAutoLaunchDefaultPreferenceCenter( "preference-center-id", false ); // Add a listener to handle display events Airship.addListener(EventType.DisplayPreferenceCenter, (event) => { const preferenceCenterId = event.preferenceCenterId; // Navigate to your custom preference center UI navigateToCustomPreferenceCenter(preferenceCenterId); }); ``` ## Fetching Preference Center Config The Preference Center config contains all the information needed to build your UI, including subscription lists, sections, and display settings. ```ts const config = await Airship.preferenceCenter.getConfig("preference-center-id"); ``` > **Note:** The config might not be available immediately on first app start. Implement exponential backoff if automatically retrying, or provide a UI for users to manually retry. ## Building Your Custom UI You'll need to: 1. **Fetch the config** to get the list of subscription lists and their current state 2. **Build your UI** using the config data (sections, subscription lists, display settings) 3. **Update subscription lists** when users make changes using the [Subscription List APIs](https://www.airship.com/docs/developer/sdk-integration/react-native/audience/subscription-lists/) ### Example Implementation See a complete example in our [React Native sample app](https://github.com/urbanairship/react-native-airship/blob/main/example/src/screens/PreferenceCenterScreen.tsx). ```ts import React, { useEffect, useState } from 'react'; import { View, Text, Switch } from 'react-native'; import Airship from '@ua/react-native-airship'; export function CustomPreferenceCenterScreen({ preferenceCenterId }) { const [config, setConfig] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { loadConfig(); }, [preferenceCenterId]); async function loadConfig() { try { const cfg = await Airship.preferenceCenter.getConfig(preferenceCenterId); setConfig(cfg); } catch (error) { console.error('Failed to load config:', error); } finally { setLoading(false); } } async function toggleSubscription(listId: string, subscribe: boolean) { if (subscribe) { await Airship.contact.subscriptionLists.subscribe(listId); } else { await Airship.contact.subscriptionLists.unsubscribe(listId); } } if (loading) { return Loading...; } if (!config) { return Failed to load Preference Center; } return ( {config.display.name} {config.sections.map((section) => ( {section.display.name} {section.items.map((item) => ( {item.display.name} {item.display.description} toggleSubscription(item.subscriptionId, value) } /> ))} ))} ); } ``` > **Important:** Preference Center configuration is currently limited to subscription lists only. Use the [Subscription List APIs](https://www.airship.com/docs/developer/sdk-integration/react-native/audience/subscription-lists/) to manage user subscriptions. ## Audience Management Integrate audience management features into your React Native app. This guide covers how to identify contacts, access channel IDs, and set tags, attributes, and subscription lists on channels and contacts. For information about using these features for segmentation and targeting, see the [Audience User Guide]({{< ref "/guides/audience/segmentation/segmentation.md" >}}). # Channels > Access and manage channel IDs and listen for channel creation. Each device/app install will generate a unique identifier known as the Channel ID. Once a Channel ID is created, it will persist in the application until the app is reinstalled, or has its internal data is cleared. For information about finding Channel IDs, using the Channel Capture tool, and other methods to access Channel IDs, see [Finding Channel IDs](https://www.airship.com/docs/guides/getting-started/developers/identifiers/). ## Accessing the Airship Channel ID Apps can access the Channel ID directly through the SDK. ```ts // Get the channel ID (may return null if not yet created) const channelId = await Airship.channel.getChannelId(); // Wait for the channel ID to be created (returns the channel ID once available) const channelId = await Airship.channel.waitForChannelId(); ``` The Channel ID is asynchronously created, so it may not be available right away on the first run. Use `waitForChannelId()` if you need to wait for the channel to be created before proceeding. Changes to Channel data will automatically be batched and applied when the Channel is created, so there is no need to wait for the Channel to be available before modifying any data. Applications that need to access the Channel ID can use a listener to be notified when it is available. ```ts Airship.addListener(EventType.ChannelCreated, (event) => { console.log('Channel created: ', event.channelId); }); ``` ## Channel Capture tool The Channel Capture tool is a feature built into the SDK that helps users find their Channel ID. For detailed information about how it works and how to use it, see [Finding Channel IDs](https://www.airship.com/docs/guides/getting-started/developers/identifiers/). The Channel Capture tool can be disabled through the Airship Config options passed to `takeOff` during SDK initialization. For information about setting up the Airship SDK and configuring the takeOff options, see [React Native SDK Setup](https://www.airship.com/docs/developer/sdk-integration/react-native/installation/getting-started/). ```ts await Airship.takeoff({ ... isChannelCaptureEnabled: false, }) ``` ## Delaying channel creation Airship creates the channel if at least one feature is enabled in the Privacy Manager. To delay channel creation, use the Privacy Manager to disable all features during takeOff. For more information about Privacy Manager, see [SDK Data Collection](https://www.airship.com/docs/reference/data-collection/sdk-data-collection/). # Contacts > Identify contacts, reset contacts, and get named user IDs. A Contact is any user in your project. Contacts are identified as either an Anonymous Contact or a Named User. Airship can set targeting data on these identifiers, which are also used to map devices and channels to a specific user. For detailed information about contacts and named users, see [Named users](https://www.airship.com/docs/guides/audience/named-users/). ## Managing the Contact's identifier (Named User ID) Identify can be called multiple times with the same Named User ID. The SDK will automatically deduplicate `identify` calls made with the same Named User ID. If the ID is changed from a previous value, the Contact will automatically be dissociated from the previous Named User ID. ```typescript await Airship.contact.identify(namedUserId); ``` If the user logs out of the device, you may want to reset the contact. This will clear any anonymous data and dissociate the contact from the Named User ID, if set. This should only be called when the user manually logs out of the app, otherwise you will not be able to target the Channel by its Contact data. ```ts await Airship.contact.reset(); ``` You can get the Named User ID only if you set it through the SDK. ```ts const namedUser = await Airship.contact.getNamedUserId(); ``` # Tags > Set device tags, contact tags, and tag groups for audience segmentation. For information about tags, including how to use them for segmentation and targeting, see the [Tags user guide](https://www.airship.com/docs/guides/audience/tags/). ## Channel Tags Channel tags are tags managed on the Channel by the SDK. Device tags (tags without a group) can be modified or fetched from the Channel. ```ts Airship.channel.editTags() .addTags(["one", "two", "three"]) .removeTags(["some_tag"]) .apply() // Accessing channel tags const tags = await Airship.channel.getTags(); ``` ## Channel Tag Groups Tag groups are tags scoped within a group. Tag groups can be modified from the SDK but cannot be fetched. Device tags (tags without a group) can be fetched. If you need to be able to fetch tag groups, consider using subscription lists. ```ts Airship.channel.editTagGroups() .addTags("loyalty", ["silver-member"]) .removeTags("loyalty", ["bronze-member"]) .apply() ``` ## Contact Tag Groups Contact tag groups are tags scoped within a group at the Contact level. Tag groups can be modified from the SDK but cannot be fetched. If you need to be able to fetch tag groups, consider using subscription lists. ```ts Airship.contact.editTagGroups() .addTags("loyalty", ["silver-member"]) .removeTags("loyalty", ["bronze-member"]) .apply() ``` ## Verifying Tags To verify that tags have been set correctly, look up the channel or contact in the [Contact Management](https://www.airship.com/docs/guides/audience/contact-management/) view. You can search by Channel ID or Named User ID to view the tags and tag groups associated with a channel or contact. # Attributes > Set channel and contact attributes as key-value pairs for personalization. For information about Attributes, including overview, use cases, and how to target Attributes, see [About Attributes](https://www.airship.com/docs/guides/audience/attributes/about/). ## Channel Attributes Channel attributes are attributes managed on the Channel by the SDK. ```ts Airship.channel.editAttributes() .setAttribute("device_name", "Bobby's Phone") .setAttribute("average_rating", 4.99) .removeAttribute("vip_status") .apply(); ``` ## Contact Attributes Contact attributes are attributes managed on the Contact by the SDK. ```ts Airship.contact.editAttributes() .setAttribute("first_name", "Bobby") .apply(); ``` ## JSON Attributes JSON Attributes are data objects containing one or more string, number, date, or boolean key-value pairs. ```ts Airship.contact.editAttributes() .setJsonAttribute("attribute_name", "instance_id", {"key":"value", "another_key":"another_value"}) .removeJsonAttribute("some_attribute_name", "some_instance_id") .apply() ``` ## Verifying Attributes To verify that attributes have been set correctly, look up the channel or contact in the [Contact Management](https://www.airship.com/docs/guides/audience/contact-management/) view. You can search by Channel ID or Named User ID to view the attributes associated with a channel or contact. # Subscription Lists > Manage channel and contact subscription lists for topic-based messaging. For information about Subscription Lists, including overview, use cases, and how to create subscription lists, see [Subscription Lists](https://www.airship.com/docs/guides/audience/segmentation/audience-lists/subscription/). ## Channel Subscription Lists Channel subscriptions apply only to the single channel. ```ts // Modifying channel subscription lists Airship.channel.editSubscriptionLists() .subscribe("food") .unsubscribe("sports") .apply() // Fetching channel subscription lists const channelSubscriptions = await Airship.channel.getSubscriptionLists(); ``` ## Contact Subscription Lists Contact subscriptions are set at the user-level and require a Channel scope specifying the types that the subscription list applies to. ```ts // Modifying contact subscription lists Airship.contact.editSubscriptionLists() .subscribe("food", SubscriptionScope.App) .unsubscribe("sports", SubscriptionScope.Sms) .apply() // Fetching contact subscription lists const contactSubscriptions = await Airship.contact.getSubscriptionLists(); ``` ## Verifying Subscription Lists To verify that subscription lists have been set correctly, look up the channel or contact in the [Contact Management](https://www.airship.com/docs/guides/audience/contact-management/) view. You can search by Channel ID or Named User ID to view the subscription lists associated with a channel or contact. ## Data Collection Overview of data collection and controls provided by the Airship React Native SDK. # Privacy Manager > Use Privacy Manager to enable or disable Airship SDK features for privacy and consent management. Privacy Manager allows you to control which Airship SDK features are enabled. This is particularly useful for consent opt-in flows where you need to disable all features initially, then enable them as users grant consent. For information about what data is collected for each Privacy Manager flag, see [SDK Data Collection](https://www.airship.com/docs/reference/data-collection/sdk-data-collection/). When all features are disabled, the SDK operates in a no-op mode—it doesn't store data or make network requests. Once features are enabled, you can enable or disable specific features at runtime based on user consent. ## Privacy Manager flags Each Privacy Manager flag controls a group of related Airship features. Enabling a flag enables all features within that group: | Privacy Manager Flag | Features | |----------------------|----------| | `push` | Push notifications | | `in_app_automation` | In-App Automation, In-App Messages, Scenes, and Landing Pages | | `message_center` | Message Center | | `tags_and_attributes` | [Tags](https://www.airship.com/docs/guides/audience/tags/), [Attributes](https://www.airship.com/docs/guides/audience/attributes/about/), Subscription Lists, and Preference Center | | `contacts` | Contact Tags, Attributes, and Subscription Lists; Named User; and Associated Channels | | `analytics` | Associated identifiers, Custom events, Screen tracking, Surveys, email address, Feature Flag interaction | | `feature_flags` | Feature Flag evaluation and interaction | | `all` | All features | | `none` | No features | ## Configuring default enabled features You can configure which features are enabled by default when the SDK initializes. This is done in your Airship config during `takeOff`. For information about setting up the Airship SDK and configuring the takeOff options, see [React Native SDK Setup](https://www.airship.com/docs/developer/sdk-integration/react-native/installation/getting-started/). ### Default configuration (all features enabled) By default, all features are enabled. The SDK will collect data and make network requests as configured. ### Disabling all features To disable all features by default (useful for consent opt-in flows), set the enabled features to an empty array: ```typescript await Airship.takeOff({ default: { enabledFeatures: [] }, ... }); ``` ### Enabling specific features To enable only specific features by default: ```typescript await Airship.takeOff({ default: { enabledFeatures: ["push", "analytics"] }, ... }); ``` ## Modifying enabled features at runtime You can enable or disable features at any time after takeOff. Once you modify the enabled features from the default, those settings are persisted between app launches. ### Enabling features ```typescript await Airship.privacyManager.enableFeatures(["push", "analytics"]); ``` ### Disabling features ```typescript await Airship.privacyManager.disableFeatures(["push", "analytics"]); ``` ## Consent opt-in flow example A common use case is to start with all features disabled, then enable them as users grant consent: ```typescript // Start with all features disabled await Airship.takeOff({ default: { enabledFeatures: [] }, ... }); // Later, when user grants consent: async function userGrantedConsent() { // Enable features based on user's consent choices await Airship.privacyManager.enableFeatures(["push", "analytics"]); } ``` > **Note:** If features are disabled after being previously enabled, the SDK may make a few network requests to opt the channel out to prevent notifications. ## Related documentation - [SDK Data Collection](https://www.airship.com/docs/reference/data-collection/sdk-data-collection/) - Comprehensive overview of what data Airship collects for each Privacy Manager flag - [Apple Privacy Manifest](https://www.airship.com/docs/reference/data-collection/apple-privacy-manifest/) - Declare data collection practices to Apple (iOS) - [Google Play Data Safety](https://www.airship.com/docs/reference/data-collection/google-play-data-safety/) - Reference for Google Play's Data Safety section (Android) - [Analytics](https://www.airship.com/docs/developer/sdk-integration/react-native/data-collection/analytics/) - Track user engagement with custom events, screen tracking, and associated identifiers # Analytics > Track user engagement and app performance with Airship analytics, including custom events, screen tracking, and associated identifiers. For information about controlling what data Airship collects, see [Privacy Manager](https://www.airship.com/docs/developer/sdk-integration/react-native/data-collection/privacy-manager/). > **Note:** Analytics events are batched and uploaded asynchronously in the background to minimize battery impact. The database size is fixed, so events are safely stored even when offline. Events may not upload immediately and may wait until the next app initialization if the app is closed before the upload completes. ## Custom Events Track user activities and key conversions with custom events. They require enabling analytics for your app. For detailed information, see the [Custom Events guide](https://www.airship.com/docs/guides/audience/events/custom-events/). ```typescript // Import CustomEvent import Airship, { CustomEvent } from '@ua/react-native-airship'; // ... var customEvent: CustomEvent = { eventName: "event_name", eventValue: 123.12, properties: { "my_custom_property": "some custom value", "is_neat": true, "any_json": { "foo": "bar" } } } await Airship.analytics.addCustomEvent(customEvent); ``` ## Associated Identifiers Associated identifiers (also called custom identifiers) associate an external identifier with a [Channel ID](https://www.airship.com/docs/reference/glossary/#channel_id). They are visible in [Real-Time Data Streaming](https://www.airship.com/docs/reference/glossary/#rtds). We recommend adding any IDs that you may want to be visible in your event stream. You can assign up to 20 associated identifiers to a device. Unlike other identifiers (e.g., tags), you cannot use associated identifiers to target your users. ```typescript await Airship.analytics.associateIdentifier("key", "value"); ``` ## Screen Tracking The Airship SDK gives you the ability to track which screens a user views within the application, how long a user stayed on each screen, and also includes the user's previous screen. These events then come through [Real-Time Data Streaming](https://www.airship.com/docs/reference/glossary/#rtds), allowing you to see the path a user took through the application, or trigger actions based on a user visiting a particular area of the application. ```typescript await Airship.analytics.trackScreen("MainScreen"); ``` ## Troubleshooting Common issues and solutions for Airship module setup, initialization, and integration. # Troubleshooting Initialization > Troubleshoot common initialization issues and apply solutions. When following steps in [Getting Started](https://www.airship.com/docs/developer/sdk-integration/react-native/installation/getting-started/) or [Advanced Configuration](https://www.airship.com/docs/developer/sdk-integration/react-native/installation/advanced-configuration/), if you don't see a channel ID in the logs or encounter errors during initialization, review the following common problems and solutions. ## Installation Errors If you encounter errors during installation: - Verify that you're using a compatible version of React Native. See [Requirements](https://www.airship.com/docs/developer/sdk-integration/react-native/installation/getting-started/#requirements) in *Getting Started*. - Ensure all native dependencies are properly linked. - Check that your iOS and Android projects are correctly configured. ## Initialization Errors If you encounter errors during SDK initialization: - Verify your credentials in the Airship dashboard. The credentials used by `takeOff` are your Airship project's [App Key](https://www.airship.com/docs/reference/glossary/#app_key) and [App Secret](https://www.airship.com/docs/reference/glossary/#app_secret). To find them, select the dropdown menu (▼) next to your project name, and then **Project details**. - Check that `takeOff` is called correctly in your app. - Ensure both iOS and Android native modules are properly installed. ## Expo: iOS Build Errors with Missing Headers If you encounter iOS build errors with messages like `'tuple' file not found`, `'iosfwd' file not found`, or `'generated/RNAirshipSpec/RNAirshipSpec.h' file not found`, this is typically caused by a compatibility issue between Expo and React Native's C++ headers. This usually happens when: - You're using `use_frameworks! :linkage => :static` in your Podfile - Your Expo SDK version has an incompatible `expo-dev-menu` dependency To fix this issue: - Add a resolution to your `package.json` to force a compatible version: ```json { "resolutions": { "expo-dev-menu": "X.X.X" // Replace with compatible version (e.g., 6.0.21) } } ``` - Or update `expo-dev-client` to the latest version. - Run `npm install` and `pod install` again. If you're running Firebase alongside Airship, see [Extending the FirebaseMessagingService](https://www.airship.com/docs/developer/sdk-integration/android/installation/getting-started/#extending-the-firebasemessagingservice) for Android configuration. # Troubleshooting Push Notifications > Check push notification status and fix common issues. If [push notifications](https://www.airship.com/docs/developer/sdk-integration/react-native/push-notifications/) aren't working as expected, you can check the notification status to diagnose the issue. ## Push Notifications Not Working If push notifications are not being received: - Verify that push notifications are enabled for both iOS and Android. - Check that APNs (iOS) and FCM (Android) are properly configured. - Ensure the app has notification permissions. ## Checking Push Notification Status If push notifications aren't working as expected, you can check the notification status to diagnose the issue: ```typescript const status = await Airship.push.getNotificationStatus(); console.log('User notifications enabled:', await Airship.push.isUserNotificationsEnabled()); console.log('Notifications allowed:', status.areNotificationsAllowed); console.log('Push token registered:', status.isPushTokenRegistered); console.log('Privacy feature enabled:', status.isPushPrivacyFeatureEnabled); console.log('User opted in:', status.isUserOptedIn); console.log('Fully opted in:', status.isOptedIn); ``` You can also listen for status changes: ```typescript Airship.addListener(EventType.PushNotificationStatusChangedStatus, (event) => { console.log('Notification status changed:', event.status); console.log('Is opted in:', event.status.isOptedIn); }); ``` ## Common Status Scenarios - `isUserOptedIn = false`: Check if `userNotificationsEnabled` is set to `true` and if the user granted permission. - `isPushPrivacyFeatureEnabled = false`: Push privacy feature is disabled in Privacy Manager. - `isPushTokenRegistered = false`: Device hasn't received a push token yet. Check network connectivity and platform configuration. - `isUserOptedIn = true` but `isOptedIn = false`: Push token registration is pending or failed. Check console logs for errors. ## Expo: Push Notifications Not Received If you don't receive Airship pushes in your Expo app, make sure you didn't previously install `expo-notifications` or another push provider by mistake. There can only be one service in each app that receives FCM messages, so it might create conflicts with Airship. If you do want to have another push provider alongside Airship, you will need to create your own `FirebaseMessagingService` to forward `onNewToken` and `onMessageReceived` calls to the Airship SDK. Follow the steps for [Extending the FirebaseMessagingService](https://www.airship.com/docs/developer/sdk-integration/android/installation/getting-started/#extending-the-firebasemessagingservice) in the *Android SDK Setup* documentation. If you're running Firebase alongside Airship, see [Extending the FirebaseMessagingService](https://www.airship.com/docs/developer/sdk-integration/android/installation/getting-started/#extending-the-firebasemessagingservice) for Android configuration.