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

# React Native

> Use Permutive native Android and iOS SDKs from within your React Native application

## Overview

Permutive does not provide an official React Native library, but you can utilise our native Android and iOS SDKs from within your React Native application.

This involves creating Android and iOS Native Modules for communicating from JS to our Native SDKs. The full guide from React Native can be found [here](https://reactnative.dev/docs/legacy/native-modules-intro).

The functions in the modules created for both platforms must share equivalent function signatures to allow the JS code to call a single function which will work on both platforms.

## Android Native Module

The Android Native Module uses our native Android SDK, the full documentation for this can be found [here](/sdks/mobile/android/overview).

It's recommended to use Android Studio for developing the Android native parts of your React Native application. It provides code syntax feedback, errors and code completion making it much easier to write your Android code. You can download the latest version [here](https://developer.android.com/studio).

Start by importing the project into Android Studio from your `android/app` folder.

### Add the Permutive Dependency

To start with, add the Permutive dependency to your Android app module in your React Native project. To do this add the dependency to the `build.gradle` which you can find in the `android/app` folder in your project.

```kotlin theme={"dark"}
dependencies {
  // ...
  implementation("com.permutive.android:core:<version>")
  // ...
}
```

### Create the Permutive Native Module file

Then create a native module for Permutive in the Android app source code, this should be at `android/app/src/main/java/<your-app-package>/`. In this example the file is called `PermutiveModule.kt`.

This file provides the bridging between the JS functions and the Native Android functions. It extends `ReactContextBaseJavaModule`. Each function you would like to expose in JS must be annotated with `@ReactMethod`. The bridging code can only return and receive specific types when interfacing with JS, for full details see the React Native official documentation for Android Native Modules [here](https://reactnative.dev/docs/legacy/native-modules-android).

The following sample code demonstrates a Native Module which exposes a subset of the Permutive SDK functionality to JS:

```kotlin PermutiveModule.kt theme={"dark"}
package com.permutive.reactnativesample

import android.net.Uri
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.Callback
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.bridge.WritableArray
import com.facebook.react.bridge.WritableMap
import com.permutive.android.EventProperties
import com.permutive.android.PageTracker
import com.permutive.android.Permutive
import java.util.UUID

class PermutiveModule(
    private val reactContext: ReactApplicationContext
) : ReactContextBaseJavaModule(reactContext) {
    override fun getName(): String = "PermutiveModule"
    private lateinit var permutive: Permutive
    private var pageTracker: PageTracker? = null

    @ReactMethod(isBlockingSynchronousMethod = true)
    fun initializePermutive(
        workspaceId: String,
        apiKey: String,
    ) {
        permutive = Permutive(
            context = reactContext,
            workspaceId = UUID.fromString(workspaceId),
            apiKey = UUID.fromString(apiKey),
        )
    }

    @ReactMethod
    fun trackPageView(
        title: String?,
        url: String?,
        referrer: String?,
        eventProperties: ReadableMap?
    ) {
        pageTracker = permutive.trackPage(
            title = title,
            url = url?.let { Uri.parse(it) },
            referrer = referrer?.let { Uri.parse(it) },
            eventProperties = eventProperties?.let {
                EventProperties.from(
                    *it.toHashMap().map { (k, v) -> k to v }.toTypedArray()
                )
            }
        )
    }

    @ReactMethod
    fun trackPageviewComplete() {
        pageTracker?.close()
    }

    @ReactMethod(isBlockingSynchronousMethod = true)
    fun currentCohorts(): WritableArray {
        val array = Arguments.createArray()
        permutive.currentCohorts.forEach { array.pushString(it) }
        return array
    }

    @ReactMethod(isBlockingSynchronousMethod = true)
    fun currentActivations(): WritableMap {
        val map = Arguments.createMap()
        permutive.currentActivations.forEach { (activationId, cohorts) ->
            val array = Arguments.createArray()
            cohorts.forEach { array.pushString(it) }
            map.putArray(activationId, array)
        }
        return map
    }

    @ReactMethod
    fun listenForCohortUpdates(callback: Callback) {
        permutive.triggersProvider().cohorts { cohorts ->
            val array = Arguments.createArray()
            cohorts.forEach { array.pushString(it) }
            callback.invoke(array)
        }
    }
}
```

### Register the Native Module

On Android you need to register the Native Module with the Android application to allow the JS code to call it. To do this create a `ReactPackage` for your application where you can add your new Native Module. First create a file in your `android/app/src/main/java/<your-app-package>/` folder, in this example it's called `PermutiveAppPackage.kt`. Create a class which extends `ReactPackage` and override the `createNativeModules` method and add your Native Module to the list returned by the function. The following sample code demonstrates this:

```kotlin PermutiveAppPackage.kt theme={"dark"}
package com.permutive.reactnativesample

import android.view.View
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ReactShadowNode
import com.facebook.react.uimanager.ViewManager

class PermutiveAppPackage : ReactPackage {
    override fun createViewManagers(
        reactContext: ReactApplicationContext
    ): MutableList<ViewManager<View, ReactShadowNode<*>>> = mutableListOf()

    override fun createNativeModules(
        reactContext: ReactApplicationContext
    ): MutableList<NativeModule> = listOf(PermutiveModule(reactContext)).toMutableList()
}
```

You then need to add this package to the list of packages returned by the `ReactNativeHost`'s `getPackages` function. This can be found in the `MainApplication` file in your `android/app/src/main/java/<your-app-package>/` folder. The following sample code shows this:

```kotlin MainApplication.kt theme={"dark"}
package com.permutive.reactnativesample

// ...

class MainApplication : Application(), ReactApplication {

  override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper(
        this,
        object : DefaultReactNativeHost(this) {
          override fun getPackages(): List<ReactPackage> {
            // Packages that cannot be autolinked yet can be added manually here, for example:
            // packages.add(new MyReactNativePackage());
            return PackageList(this).packages.apply {
              // Add your custom package here
              add(PermutiveAppPackage())
            }
          }
          // ...
      }
  )
  // ...
}
```

Your Android native code is now callable from JS! How to do this is explained in a section below.

## iOS Native Module

The iOS Native Module sample uses our native iOS SDK, the full documentation for this can be found [here](/sdks/mobile/ios/overview).

It's recommended to use Xcode for developing the iOS native parts of your React Native application. It provides code syntax feedback, errors and code completion making it much easier to write your iOS code. You can download the latest version [here](https://developer.apple.com/xcode/).

Start by importing the iOS part of the React Native project into Xcode. The easiest way to do this is by navigating to your React Native project folder and opening the `ios/<your-app-name>.xcworkspace` file.

### Add the Permutive dependency

Add the Permutive iOS dependency to your project using Swift Package Manager. To do this, go to `File -> Add Package Dependencies`. Then enter `https://github.com/permutive-engineering/permutive-ios-spm` in the Search or Enter Package URL bar, on the top right, then select Add Package, select Package Product Permutive\_iOS and add to your React Native app Target, then select Add Package.

### Create the Native Module files

This guide uses Swift files which interact with the Permutive SDK and Objective-C bridging to connect these to JS.

Add a new Swift file to your project in the `ios/` folder. This should be the same name as your Android module file if you've already created that, for this sample we'll use 'PermutiveModule' again so we create `PermutiveModule.swift`.

Your project should have an Objective-C bridging header file which you can find at `ios/<your-app-name>/<your-app-name>-Bridging-Header.h`. You need to import the `ReactBridgeModule` in that file as shown here:

```objectivec <your-app-name>-Bridging-Header.h theme={"dark"}
//
//  Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "React/RCTBridgeModule.h"
```

You'll also need an Objective-C file which is used to expose the Swift methods to JS. Create a new Objective-C file with the same name as your Native Module file in the `ios/` folder. In this sample that is `PermutiveModule.m`.

The Swift class needs to be annotated as an Objective-C exposed class and the methods need to be annotated too. Only specific types can be used when receiving parameters and returning from functions for communicating with JS. For full details on this see the official React Native iOS Native Modules documentation [here](https://reactnative.dev/docs/native-modules-ios).

This sample shows a Swift module with the equivalent functionality to the Android Native Module:

```swift PermutiveModule.swift theme={"dark"}
import Foundation
import Permutive_iOS

@objc(PermutiveModule)
class PermutiveModule: NSObject {
  private var pageTracker: PageTrackerProtocol? = nil
  @objc
  func initializePermutive(
    _ workspaceId: NSString,
    _ key: NSString
  ) {
    guard let options = Options(
      apiKey: key as String,
      organisationId: workspaceId as String,
      workspaceId: workspaceId as String
    ) else {
      print("Error creating Permutive Options")
      return
    }
    Permutive.shared.start(with: options) { error in
      guard error != nil else {
        return
      }
      print("Error starting Permutive: \(String(describing: error))")
      return
    }
  }

  @objc
  func trackPageView(
    _ title: NSString?,
    _ url: NSString?,
    _ referrer: NSString?,
    _ eventProperties: NSDictionary?
  ) {
    do {
      // Convert NSDictionary to EventProperties
      let properties = try EventProperties(
          (eventProperties as? [String: Any])?
            .compactMapValues { propertyName in
              propertyName as? AnyHashable
            }.reduce(into: [:]) { outputDictionary, inputDictionary in
              outputDictionary[inputDictionary.key] = inputDictionary.value
            } ?? [:]
      )

      let context = (title != nil && url != nil && referrer != nil) ? Context(
          title: title! as String,
          url: URL(string: url! as String)!,
          referrer: URL(string: referrer! as String)!
      ) : nil

      pageTracker = try Permutive.shared.createPageTracker(
          properties: properties,
          context: context
      )
    } catch {
      print("Error starting page tracker: \(String(describing: error))")
    }
  }

  @objc
  func trackPageviewComplete() {
    pageTracker?.stop()
  }

  @objc
  func currentCohorts() -> NSArray {
    return Array(Permutive.shared.cohorts) as NSArray
  }

  @objc
  func currentActivations() -> NSDictionary {
    return Permutive.shared.activations as NSDictionary
  }

  @objc
  func listenForCohortUpdates(_ callback: @escaping RCTResponseSenderBlock) {
    let queryRange = Array(<relevant-cohort-ids>).map { queryId in String(queryId) }
    let action = Permutive.shared.triggerProvider?.action(boolFor: Set(queryRange)) { (_, _) in
      callback([Array(Permutive.shared.cohorts) as NSArray])
    }
  }
}
```

To be able to call this code from JS it requires bridging through Objective-C code.

To do this within the Objective-C native module file you created before, you import the same `RCTBridgeModule` and create an `RCT_EXTERN_MODULE` interface which references your Swift class.

Two Objective-C functions are used to expose the Swift methods in this example:

* `RCT_EXTERN_METHOD` - Exposes an asynchronous method to JS. It takes an argument in the following form: `functionName:(Parameter1Type)parameter1InternalName :(Parameter2Type)parameter2InternalName`.
* `RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD` - Exposes a synchronous method to JS. It takes arguments in the same form as `RCT_EXTERN_METHOD`.

The following sample shows the Objective-C code used to expose the sample Swift class:

```objectivec PermutiveModule.m theme={"dark"}
#import <Foundation/Foundation.h>

#import "React/RCTBridgeModule.h"

@interface RCT_EXTERN_MODULE(PermutiveModule, NSObject)

RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(initializePermutive:(NSString)workspaceId :(NSString)key)
RCT_EXTERN_METHOD(trackPageView:(NSString)title :(NSString)url :(NSString)referrer :(NSDictionary)eventProperties)
RCT_EXTERN_METHOD(trackPageviewComplete)
RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(currentCohorts)
RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(currentActivations)
RCT_EXTERN_METHOD(listenForCohortUpdates:(RCTResponseSenderBlock)callback)

@end
```

Your iOS code is now ready to be called from JS!

## Calling Native code from JS

To consume your native code from JS you can create a wrapper module around your native module. Create a new JS file in your `app/` folder with the same name as your Native Module files. In this sample that is `PermutiveModule.js` with the following content:

```javascript PermutiveModule.js theme={"dark"}
import {NativeModules} from 'react-native';
const {PermutiveModule} = NativeModules;
export default PermutiveModule;
```

You can then import this module into your React files and call into the native functions. This sample shows calling into the `PermutiveModule` in the `useEffect` function to initialize the Permutive SDK, track a Pageview, set the latest cohorts to some state and also listen for changes:

```javascript theme={"dark"}
import PermutiveModule from '../PermutiveModule'

export default function HomeScreen() {
  const [currentCohorts, setCurrentCohorts] = useState('');
  useEffect(() => {
    PermutiveModule.initializePermutive("e0039147-51e7-4224-a814-0e2d438aabcd", "da4d09b5-843a-4bd5-bd79-8cea7f69f730");
    PermutiveModule.trackPageView("Page title", null, null, null);
    setCurrentCohorts(PermutiveModule.currentCohorts().join(', '));
    PermutiveModule.listenForCohortUpdates((cohorts: any) => setCurrentCohorts(cohorts.join(', ')))
  }, [])
  return (
    // ...
  )
}
```

You can utilise these functions to implement Permutive within your app. If you require more functionality you can add it by creating new functions in the React Native Modules for each platform which call the relevant Permutive SDK functions.

Your React Native app is now ready to finish your Permutive integration.
