> ## Documentation Index
> Fetch the complete documentation index at: https://docs.appdna.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# React Native Installation

> Add AppDNA to your React Native project

<Info>
  The React Native SDK requires the New Architecture.
  **Supported on:** iOS SDK `1.0.70+` · Android SDK `1.0.42+` · React Native SDK `1.0.7+` (New Architecture only)
</Info>

<Warning>
  The React Native SDK requires the **New Architecture**. Versions `1.0.6` and earlier shipped no
  podspec and no Android Gradle module, so they could not be linked into an app at all — install
  `1.0.7` or later.
</Warning>

## Requirements

Before integrating the AppDNA React Native SDK, ensure your project meets the following minimum requirements:

| Requirement    | Minimum Version       |
| -------------- | --------------------- |
| React Native   | 0.76.9+ (New Arch on) |
| Node           | 18+                   |
| iOS            | 16.0+                 |
| Android minSdk | 24                    |

**Bare React Native:** set `newArchEnabled=true` in `android/gradle.properties`, and run the iOS
`pod install` with `RCT_NEW_ARCH_ENABLED=1`.

**Expo:** the [config plugin](#expo) does both for you — it writes `newArchEnabled=true` into
`android/gradle.properties` and into `ios/Podfile.properties.json`, which is where Expo's Podfile
reads it from to set `RCT_NEW_ARCH_ENABLED`.

<Warning>
  The React Native SDK delegates rendering, storage, and network I/O to the native iOS and Android SDKs,
  so every paywall, onboarding flow, and in-app message looks and feels platform-native. Your project
  must meet the native platform requirements as well.
</Warning>

## Installation

Install the AppDNA SDK package:

```bash theme={null}
yarn add @appdna-ai/react-native-sdk
```

Or with npm:

```bash theme={null}
npm install @appdna-ai/react-native-sdk
```

Then install the iOS Pods with the New Architecture enabled:

```bash theme={null}
cd ios && RCT_NEW_ARCH_ENABLED=1 pod install && cd ..
```

### Bare RN, iOS: register the screen slot when your Podfile uses `use_frameworks!`

Expo apps can skip this section — the config plugin writes this override into the AppDelegate on
every prebuild. It applies to **bare React Native** only.

Skip it too if your app links pods as static libraries — nothing to do there. But if your `Podfile`
has `use_frameworks!` (which any app with Firebase in its pod graph ends up needing, and the AppDNA
core SDK depends on Firebase), you must hand the screen-slot view to React yourself.

React Native's generated component registry wraps its whole third-party component map in
`#ifndef RCT_DYNAMIC_FRAMEWORKS`, so with dynamic frameworks nothing registers `AppdnaScreenSlotView`.
There is no error and no warning — `<AppDNAScreenSlot>` simply renders React's placeholder,
`Unimplemented component: <AppdnaScreenSlotView>`, and the slot never appears.

Add the override below to `AppDelegate.mm`. `RCTAppDelegate` already exposes the hook:

```objc theme={null}
#import <appdna_sdk_react_native/AppdnaFabricComponents.h>

- (NSDictionary<NSString *, Class<RCTComponentViewProtocol>> *)thirdPartyFabricComponents
{
  NSMutableDictionary *components = [[super thirdPartyFabricComponents] mutableCopy];
  [components addEntriesFromDictionary:AppdnaFabricComponents()];
  return components;
}
```

Everything else — every method, every event, every delegate — works without this. Only the inline
`<AppDNAScreenSlot>` component needs it.

### Expo

The package ships a config plugin. Add it to `app.json` and run a prebuild:

```json theme={null}
{ "expo": { "plugins": ["@appdna-ai/react-native-sdk"] } }
```

```bash theme={null}
npx expo prebuild && npx expo run:ios
```

The plugin does five things, none of which Expo's defaults give you:

|   | What                                                                           | Why                                                                                                                                                                                                                                                          |
| - | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 1 | `newArchEnabled=true` in `gradle.properties` **and** `Podfile.properties.json` | The SDK is New-Architecture only. Expo SDK 52 leaves it off, and the legacy bridge installs no event emitters — every SDK callback would be silently dead.                                                                                                   |
| 2 | `ios.deploymentTarget = 16.0`                                                  | The native iOS SDK requires it; CocoaPods resolves the floor, so a lower target fails at `pod install`.                                                                                                                                                      |
| 3 | `ios.useFrameworks = dynamic`                                                  | FirebaseFirestore's pod graph does not install under static linkage.                                                                                                                                                                                         |
| 4 | The `thirdPartyFabricComponents` override in your AppDelegate                  | (3) makes React Native compile its third-party component registry out. Without this, `<AppDNAScreenSlot>` silently renders nothing. Expo regenerates the AppDelegate on every prebuild, so the plugin rewrites it each time — a hand edit would not survive. |
| 5 | `BGTaskSchedulerPermittedIdentifiers`                                          | The SDK registers a background upload task; an unlisted identifier is a launch-time crash.                                                                                                                                                                   |

Options — all optional:

```json theme={null}
{
  "expo": {
    "plugins": [
      ["@appdna-ai/react-native-sdk", {
        "enablePush": true,
        "deploymentTarget": "16.0",
        "useFrameworks": "dynamic",
        "screenSlot": "auto"
      }]
    ]
  }
}
```

<Warning>
  **Expo SDK 53+ has a Swift AppDelegate**, and the plugin cannot write the ObjC override (4) into it.
  Rather than leave `<AppDNAScreenSlot>` silently broken, `expo prebuild` **fails** with a directed
  error. Resolve it either by linking statically — `{ "useFrameworks": "static" }`, which makes the
  override unnecessary because React Native's own registry is then compiled in — or, if you do not use
  `<AppDNAScreenSlot>`, by acknowledging it with `{ "screenSlot": "skip" }`. Every other SDK feature
  works in both cases.
</Warning>

<Warning>
  Expo Go cannot host a native module. Use a development build.
</Warning>

<Info>
  Autolinking wires the native iOS and Android modules automatically — no manual linking step is required.
</Info>

## Firebase Configuration

The AppDNA SDK uses Firebase Firestore for real-time configuration delivery (paywalls, experiments, feature flags, onboarding flows). You must add Firebase configuration files for each platform your app targets.

### Step 1: Download Firebase Config Files

1. Log into your [AppDNA Console](https://console.appdna.ai)
2. Go to **Settings → SDK**
3. Click **Download Firebase Config** to download both:
   * `GoogleService-Info-AppDNA.plist` (for iOS)
   * `google-services-appdna.json` (for Android)

### Step 2: Add iOS Configuration

1. Open `ios/<YourApp>.xcworkspace` in Xcode
2. Drag `GoogleService-Info-AppDNA.plist` into your app target's folder in the project navigator
3. Ensure **"Copy items if needed"** is checked
4. Select your app target in the **"Add to targets"** section

### Step 3: Add Android Configuration

Place the `google-services-appdna.json` file in the Android app module directory:

```
your-project/
  android/
    app/
      google-services-appdna.json    <-- place here
```

Ensure the Google Services plugin is applied in your `android/app/build.gradle`:

```groovy theme={null}
apply plugin: 'com.google.gms.google-services'
```

And the classpath is added to `android/build.gradle`:

```groovy theme={null}
buildscript {
    dependencies {
        classpath 'com.google.gms:google-services:4.4.0'
    }
}
```

<Warning>
  Without the Firebase config files, the SDK cannot fetch remote configuration (paywalls, experiments, feature flags). Events will still be tracked, but remote features will not work.
</Warning>

<Note>
  If your app already uses Firebase for your own services (Realtime Database, Analytics, Crashlytics), AppDNA automatically initializes a separate named Firebase instance using `GoogleService-Info-AppDNA.plist` (iOS) and `google-services-appdna.json` (Android). Your existing Firebase setup is not affected. Just add the AppDNA config files alongside your own.
</Note>

## Architecture

The `@appdna-ai/react-native-sdk` package is a thin TypeScript facade over a TurboModule. Rendering,
storage, and network I/O all happen in the native iOS and Android SDKs; the facade marshals method
calls and receives native callbacks.

Method calls resolve through `TurboModuleRegistry`, and native events arrive on the generated event
emitters — not through `NativeEventEmitter`, which under the New Architecture would subscribe to a
channel nothing writes to.

### Callbacks that native waits for

Most callbacks are one-way notifications. Eight are **vetoes**: native pauses and waits for your
answer before it proceeds.

| Hook                   | Where it lives               | If you don't answer |
| ---------------------- | ---------------------------- | ------------------- |
| `onBeforeStepAdvance`  | `AppDNAOnboardingDelegate`   | proceed             |
| `onBeforeStepRender`   | `AppDNAOnboardingDelegate`   | render unchanged    |
| `onElementInteraction` | `AppDNAOnboardingDelegate`   | no state change     |
| `onPermissionRequest`  | `AppDNAOnboardingDelegate`   | run the OS prompt   |
| `onPromoCodeSubmit`    | `AppDNAPaywallDelegate`      | **reject the code** |
| `shouldShowMessage`    | `AppDNAInAppMessageDelegate` | show the message    |
| `shouldOpen`           | `AppDNADeepLinkDelegate`     | open the link       |
| `onScreenAction`       | `AppDNAScreenDelegate`       | perform the action  |

Each may return a value or a `Promise` of one, so a handler can ask your own backend. If it takes
longer than the veto timeout (5 seconds by default, `vetoTimeout` in `configure`), native applies the
default in the last column and moves on. `onPromoCodeSubmit` is the one hook whose default is to
**refuse** — a timeout means the code was never validated.

<Info>
  You never interact with the bridge directly. The `AppDNA` class and its module accessors provide a
  high-level TypeScript API.
</Info>

## Native Dependencies

The React Native SDK inherits the dependencies of the underlying native SDKs. These are resolved automatically by CocoaPods (iOS) and Gradle (Android):

| Platform | Dependency        | Version          | Purpose                             |
| -------- | ----------------- | ---------------- | ----------------------------------- |
| iOS      | KeychainAccess    | \~> 4.2          | Secure storage for tokens and IDs   |
| iOS      | FirebaseFirestore | >= 11.0, \< 13.0 | Real-time remote configuration sync |
| Android  | Firebase BoM      | latest           | Firestore + analytics + messaging   |
| Android  | Play Billing      | latest           | In-app purchases and subscriptions  |

<Info>
  If your project already includes these dependencies, ensure your version constraints are compatible with the versions above. CocoaPods and Gradle will resolve conflicts automatically in most cases.
</Info>

<Note>
  Lottie and Rive animation support is provided by the native SDKs. On iOS, add `lottie-ios` and `rive-ios` to your `Podfile` if you use those formats. On Android, the equivalent dependencies are bundled with the native AppDNA SDK.
</Note>

## Import

Import the SDK in any TypeScript / JavaScript file where you need to use it:

```typescript theme={null}
import { AppDNA } from '@appdna-ai/react-native-sdk';
```

This entry point exposes the `AppDNA` static class, every module accessor, the canonical delegate interfaces (`AppDNAPushDelegate`, `AppDNAPaywallDelegate`, `AppDNAOnboardingDelegate`, etc.), and all DTOs (`Entitlement`, `ProductInfo`, `TransactionInfo`, `PaywallContext`, ...).

## Verify Installation

After adding the dependency, verify the SDK is correctly installed by printing the version:

```typescript theme={null}
import { AppDNA } from '@appdna-ai/react-native-sdk';

async function bootstrap(): Promise<void> {
  const version = await AppDNA.getSdkVersion();
  console.log(version); // native version, e.g. iOS "1.0.71" or Android "1.0.43"
}
```

<Check>
  You should see a version string. If the call throws instead, the error names the exact cause: Expo Go,
  a missing `pod install`, an unsupported runtime, or the New Architecture being switched off.
</Check>

## Troubleshooting

If you encounter issues during integration, call `AppDNA.diagnose()` after configuration to get a full health report:

```typescript theme={null}
import { AppDNA } from '@appdna-ai/react-native-sdk';

// Call a few seconds after configure() to allow bootstrap to complete
setTimeout(() => {
  AppDNA.diagnose();
}, 5000);
```

This prints a diagnostic report to the platform console (Xcode debug area on iOS, Logcat on Android):

```
╔══════════════════════════════════════════
║  AppDNA SDK Diagnostic Report  v1.0.7
║  (iOS 1.0.71 / Android 1.0.43)
╠══════════════════════════════════════════
║ ✅ API Key: sandbox key (adn_test_...50ef)
║ ✅ Environment: sandbox
║ ✅ Bootstrap: orgId=..., appId=...
║ ✅ Firebase: secondary app 'appdna' configured
║ ✅ Identity: anonId=a1b2c3d4...
║ ✅ Event Queue: initialized
║ ✅ Remote Config: initialized
║ ✅ Modules: paywalls, onboarding, messages, surveys, billing, push, experiments
║ ✅ React Native bridge: 8 native events wired
╠══════════════════════════════════════════
║ ✅ SDK is fully operational
╚══════════════════════════════════════════
```

Any items marked with **❌** indicate a configuration issue. Common fixes:

| Issue                                               | Fix                                                                                                                                                                                                                        |
| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ❌ API Key: invalid format                           | Key must start with `adn_live_` or `adn_test_`. Copy directly from **Settings → SDK** in the AppDNA Console.                                                                                                               |
| ❌ Bootstrap: failed                                 | Check API key and internet connection.                                                                                                                                                                                     |
| ❌ Firebase: no secondary app                        | Add `GoogleService-Info-AppDNA.plist` to your iOS target AND `google-services-appdna.json` to `android/app/`.                                                                                                              |
| ⚠️ Firebase: using default app                      | Your own Firebase is being used instead of AppDNA's — add the AppDNA-specific config file.                                                                                                                                 |
| `Invariant Violation: Native module AppDNA is null` | Re-run `cd ios && pod install`, then rebuild the iOS app from Xcode. On Android, run `cd android && ./gradlew clean` and rebuild.                                                                                          |
| Build fails on iOS with `BGTaskScheduler`           | The iOS native SDK registers background event uploads. Ensure your iOS deployment target is 16.0+ (the SDK's floor) and the `Background Modes → Background fetch` capability is enabled if you customize background tasks. |

For more verbose output, set `logLevel: 'debug'` in `AppDNAOptions` during development to surface SDK activity.

## Next Steps

Once the SDK is installed, proceed to the [Quickstart](/sdks/react-native/quickstart) guide to configure the SDK and start tracking events.
