---
title: React Native
slug: v4-8/install-guides/react-native
icon: {"faIcon":"fa-brands fa-react"}
docTags: 
createdAt: 2024-03-11T23:03:38.932Z
---

This article provides instructions on adding the Ditto package to your project by importing, initializing, and preparing Ditto to be integrated successfully with your React Native apps.

- [Bare React Native Support](./#react-native-cli-support)
- [Prerequisites](docId\:Zk-H_ViBxHvZz2jg9uTSJ)
- [Integrating Ditto](docId\:Zk-H_ViBxHvZz2jg9uTSJ)
- [Configuring Sync](./#configuring-sync)
- [Enabling smallPeerInfo Feature](docId\:Zk-H_ViBxHvZz2jg9uTSJ)
- [Setting Up Presence](./#setting-up-presence)
- [Setting Logs to Debug Level](./#setting-logs-to-debug-level)
- [Troubleshooting JSI Bindings Error](docId\:Zk-H_ViBxHvZz2jg9uTSJ)

# React Native CLI Support

The Ditto SDK is designed for apps built with [bare React Native CLI](https://reactnative.dev/docs/getting-started-without-a-framework).&#x20;

:::hint{type="warning"}
Expo Go is not currently support. Support for other Expo workflows including CNG and DIY are limited. This work is in active develepoment.
:::

Once you've confirmed that you have the necessary prerequisites, integrate Ditto within your React Native app:

::::WorkflowBlock
:::WorkflowBlockItem
Set up a React Native CLI project. ([Creating Your Project](./#creating-your-project))
:::

:::WorkflowBlockItem
Install the Ditto package into your project. ([Installing the Ditto SDK](./#installing-the-ditto-sdk))
:::

:::WorkflowBlockItem
Install the project dependencies. ([Installing Dependencies](./#installing-dependencies))
:::

:::WorkflowBlockItem
Enable your app to sync with nearby devices. ([Setting Up Transport Configurations](./#configuring-permissions))
:::

:::WorkflowBlockItem
Import the previously installed Ditto SDK package in your app. ([Initializing Ditto](./#initializing-ditto))
:::

:::WorkflowBlockItem
Set up permissions handling. ([Handling Permissions](./#handling-permissions))
:::

:::WorkflowBlockItem
Set up authentication. ([Setting Up Authentication](./#setting-up-authentication))
:::

:::WorkflowBlockItem
Specify how Ditto should handle sync. ([Creating a New Instance of Ditto](./#creating-a-new-instance-of-ditto))
:::

:::WorkflowBlockItem
Set up transport configurations. ([Setting Transport Configurations](./#setting-transport-configurations))
:::

:::WorkflowBlockItem
Initiate sync at global scope. ([Starting the Sync Process](docId\:Zk-H_ViBxHvZz2jg9uTSJ))
:::

:::WorkflowBlockItem
If desired, enable the Small Peer Information feature. ([Enabling smallPeerInfo](docId\:Zk-H_ViBxHvZz2jg9uTSJ))
:::

:::WorkflowBlockItem
If desired, monitor the activity of remote peers in the mesh by logging relevant information in logs or using Ditto’s Presence Viewer app. ([Setting Up Presence](./#setting-up-presence))
:::

:::WorkflowBlockItem
If desired, set the log level to debug. ([Setting the Logs to Debug Level](./#setting-logs-to-debug-level))
:::

:::WorkflowBlockItem
Create your subscription logic. ([Constructing Subscription Logic](docId\:Zk-H_ViBxHvZz2jg9uTSJ))
:::
::::

## Creating Your Project

First, set up your environment and initialize your React Native CLI project. For instructions, see React Native's official documentation on [Setting up the development environment](https://reactnative.dev/docs/set-up-your-environment).

:::hint{type="info"}
To verify that you’ve set up your environment correctly, install and run the React Native CLI doctor. For more information, see the official [Meet Doctor, a new React Native command React Native](https://reactnative.dev/blog/2019/11/18/react-native-doctor) blog post.
:::

## Installing the Ditto SDK

From a terminal, navigate to the folder containing your React Native project, and then, using your preferred package manager, run the Ditto package:

:::CodeblockTabs
Yarn

```none
yarn add @dittolive/ditto
```

npm

```bash
npm install @dittolive/ditto
```
:::

## Installing Dependencies

From the root of your project, install project dependencies based on the `package.json` file:

:::CodeblockTabs
Yarn

```none
yarn install
```

npm

```none
npm install
```
:::

## Configuring Permissions

Once you've added dependencies, set up the prerequisites to enable Ditto Transports for iOS and Android.

### iOS

From Xcode, enable Bluetooth LE and local network services in your app:

:::::WorkflowBlock
::::WorkflowBlockItem
From your project's `Info.plist` file, add the following key-value pairs:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>NSBluetoothAlwaysUsageDescription</key>
  <string>Uses Bluetooth to connect and sync with nearby devices.</string>
  <key>NSLocalNetworkUsageDescription</key>
  <string>Uses WiFi to connect and sync with nearby devices.</string>
  <key>NSBonjourServices</key>
  <array>
  <string>_http-alt._tcp.</string>
  </array>
  <!-- Your other keys -->
</dict>
</plist>
```

:::hint{type="info"}
Tip: To view `Info.plist` as source code, right-click the file from the left sidebar in Xcode > click **Open As** > and then select **Source Code** from the menu.
:::

:::hint{type="info"}
If desired, customize the default values for the permission prompts by replacing them with your preferred text.&#x20;

For example, if your end users prefer a language other than English, you can replace the default English strings with their language equivalents.
:::

Once implemented, these string values display to your end users as dismissable prompts explaining why the app requires certain permissions.


::::

::::WorkflowBlockItem
Ensure your app continues to sync while it runs in the background by enabling Bluetooth LE background modes. Once enabled, your app continuously syncs in the background, even while the device is locked.&#x20;

:::hint{type="info"}
For official instructions, see [Configuring background execution modes](https://developer.apple.com/documentation/xcode/configuring-background-execution-modes) from Apple.
:::

1. From the left sidebar, click to select your project.
2. Click **Signing & Capabilities**.
3. Click **+ Capability,** and then from the modal that appears, search and select **Background Modes**.
4. From **TARGETS**, select your app from the list.
5. From **Background Modes**, toggle the following:
   - **Uses Bluetooth LE** **accessories**
   - **Acts as a Bluetooth LE accessory**

![](https://api.archbee.com/api/optimize/qoRkNxW5fJ81r_NqVpc8C/xv0Ddcn7wgvhnTwkzOp5q_image.png)
::::
:::::

### Android

From Android Studio, set up transport configurations for the Android target:

:::::WorkflowBlock
::::WorkflowBlockItem
Update Android's minimum SDK version to `24` or higher:

1. Open the project-level `build.gradle` located in the `android` root directory.
2. Set the `minSDKVersion` to `24`.

:::hint{type="info"}
For newer projects, set the SDK version in `android/gradle.properties`.
:::
::::

::::WorkflowBlockItem
Add the Ditto SDK as a dependency:

1. Open the module-level `build.gradle` located in the `android/app` directory.
2. Add the following line into the `dependencies` block located at the bottom of the file:

:::CodeblockTabs
&#x20;

```none
implementation "live.ditto:ditto:4.8.1"
```
:::
::::

:::WorkflowBlockItem
Android permissions
:::

::::WorkflowBlockItem
If using [React Native's  Architecture](https://reactnative.dev/docs/the-new-architecture/landing-page), you must add the following code snippet to the module-level `build.gradle` located in the `android/app` directory:

:::CodeblockTabs
&#x20;

```none
android {
    packagingOptions {
        pickFirst 'lib/x86/libjsi.so'
        pickFirst 'lib/x86_64/libjsi.so'
        pickFirst 'lib/armeabi-v7a/libjsi.so'
        pickFirst 'lib/arm64-v8a/libjsi.so'
    }
    // Rest of the file
}
```
:::

:::hint{type="info"}
If you encounter other issues, see [Troubleshooting JSI Bindings Error](docId\:Zk-H_ViBxHvZz2jg9uTSJ).
:::
::::

::::WorkflowBlockItem
Start the app in Metro:

:::CodeblockTabs
&#x20;

```none
yarn start
```
:::
::::
:::::



## Initializing Ditto

Within the top-most scope of your app, import the Ditto package with the necessary modules and components from the Ditto's SDK library:

:::CodeblockTabs
&#x20;

```javascript
import {Ditto} from '@dittolive/ditto';
```
:::

## Handling Permissions

Within your default React component (`App`), use this helper function to request permissions if developing for the Android target:

:::CodeblockTabs
&#x20;

```typescript
import {useEffect} from 'react';
import {PermissionsAndroid} from 'react-native';

export default function App() {

  async function requestPermissions() {
    const granted = await PermissionsAndroid.requestMultiple([
      PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
      PermissionsAndroid.PERMISSIONS.BLUETOOTH_ADVERTISE,
      PermissionsAndroid.PERMISSIONS.NEARBY_WIFI_DEVICES,
      PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
    ]);
    
    Object.entries(granted).forEach(([permission, result]) => {
      if (result === PermissionsAndroid.RESULTS.GRANTED) {
        console.log(`${permission} granted`);
      } else {
        console.log(`${permission} denied`);
      }
    });
  }

  useEffect(() => {
    requestPermissions();
  }, []);
  
}
```
:::

# Configuring Sync

Using an asynchronous function, let's say, `startSync()`, do the following:

::::WorkflowBlock
:::WorkflowBlockItem
Define an identity configuration with authentication settings. ([Setting Up Authentication](./#setting-up-authentication))
:::

:::WorkflowBlockItem
Instantiate a `ditto` object with the specified identity. ([Creating a New Ditto Instance](./#creating-a-new-instance-of-ditto))
:::

:::WorkflowBlockItem
Configure peer-to-peer transport settings and enable transports. ([Setting Transport Configurations](./#setting-transport-configurations))
:::

:::WorkflowBlockItem
Initiate sync. ([Starting the Sync Process](docId\:Zk-H_ViBxHvZz2jg9uTSJ))
:::
::::

## Setting Up Authentication

Create an identity object, define your *authentication type*, and then provide access credentials. Each instance of Ditto running in your app must prove its identity to other peers to sync.&#x20;

There are two types of identities you can use to authenticate:

- `onlinePlayground` — Explore platform features and functionality without setting up your authentication mechanism.
- `onlineWithAuthentication` — If developing a production-level app, integrate your own identity provider, such as Auth0, identify users, give users read or write control, and integrate with your existing authentication systems.&#x20;

For more information, see [Cloud Authentication](docId\:D0B4xrfN45yeM15qCYcOb) .

### onlinePlayground

Use an online playground identity for development. You can find authentication details for your app on the [Ditto Portal.](https://portal.ditto.live) Use these to set up your identity:

:::CodeblockTabs
&#x20;

```javascript
import type {Identity} from '@dittolive/ditto';

const identity = {
  type: 'onlinePlayground',
  appID: '<your-app-id>',
  token: '<your-online-playground-token>',
};
```
:::

### onlineWithAuthentication

Use the `onlineWithAuthentication` identity when developing a production app for deployment.

:::CodeblockTabs
&#x20;

```javascript
const identity = {
  type: 'onlineWithAuthentication',
  appID: '<your-app-id>',
  authHandler: {
    authenticationRequired(authenticator) {
      if (authenticator.loginSupported) {
        authenticator.loginWithToken(
          'will-accept-any-password',
          'auth-webhook'
        );
        console.log('Successfully logged in');
      }
    },
    authenticationExpiringSoon: function (authenticator) {
      authenticator.loginWithToken('will-accept-any-password', 'auth-webhook');
      console.log('Successfully relogged');
    },
  },
};
```
:::

## Creating a New Instance of Ditto

Within a `try` statement, instantiate a new `Ditto` object with the identity you’ve specified:

:::CodeblockTabs
&#x20;

```javascript
import {Ditto, DittoError} from '@dittolive/ditto';

try {
  const ditto = new Ditto(identity);
} catch (error) {
  if (error instanceof DittoError) {
    // handle errors starting Ditto
  }
  throw error
}    
```
:::

## Setting Transport Configurations

Using a `TransportConfig` instance, do the following to set up transport configurations in your app:

:::::WorkflowBlock
:::WorkflowBlockItem
Configure peer-to-peer transport settings so that all desired transport types available on the end-user device are available to Ditto.
:::

::::WorkflowBlockItem
Specify how you want Ditto to handle which transports to sync data across the mesh.

:::CodeblockTabs
&#x20;

```javascript
import {TransportConfig} from '@dittolive/ditto';
import {Platform} from 'react-native';

const transportsConfig = new TransportConfig();
transportsConfig.peerToPeer.bluetoothLE.isEnabled = true;
transportsConfig.peerToPeer.lan.isEnabled = true;
transportsConfig.peerToPeer.lan.isMdnsEnabled = true;

// Apple Wireless Direct Link is only available on Apple devices
if (Platform.OS === 'ios') {
  transportsConfig.peerToPeer.awdl.isEnabled = true;
}

ditto.setTransportConfig(transportsConfig);
```
:::
::::
:::::

## Constructing Sync Subscription Logic

Create the logic that performs sync and data operations in your app, including registering subscriptions, executing store operations, and observing changes in the given collection. For more information, see [Data-Handling Essentials](docId\:Z6tbFllqieU_CtkJR845E) and [Managing Sync Subscriptions](docId:6fiOPaeoNMv1kfc90sMhO).

For example, the following snippet defines a document object (`document`), creates a subscription for the `Cars` collection, executes database operations and logs the results, registers an observer for watching changes in the `Cars` collection:

:::CodeblockTabs
&#x20;

```javascript
ditto.sync.registerSubscription(`SELECT * FROM cars`);

const document = {
  id: 987654,
  _id: 123131,
  model: "CX-5",
  make: "Mazda",
  color: "blue",
};

const queryResult = await ditto.store.execute(
  "INSERT INTO cars DOCUMENTS (:document) ON ID CONFLICT DO UPDATE",
  { document }
  );
  console.log(queryResult.items.map((item) => item.value));
  console.log(
    "mutated",
    queryResult.mutatedDocumentIDs().map((docId) => docId.value)
  );
}

ditto.store.registerObserver(`SELECT * FROM cars`, (response) => {
  const parsedDocuments = response.items.map((doc) => {
    return doc.value;
  });

  // save state or other use cases
});

```
:::

## Starting the Sync Process

To start syncing with other peers in the mesh:

:::CodeblockTabs
&#x20;

```javascript
ditto.startSync();
```
:::

# Enabling Small Peer Info

Enabling the smallPeerInfo feature allows you to gather and store peer-to-peer sync and network details automatically rather than continuously query Ditto for this data.&#x20;

Once enabled, collected details are available within the Ditto portal. For more information, see [Using the Device Dashboard](docId\:lD343-2LgT0_3NKaw2Qnr).

You can configure `smallPeerInfo` directly on the Ditto instance.

:::CodeblockTabs
&#x20;

```javascript
ditto.smallPeerInfo.isEnabled = true;
await ditto.smallPeerInfo.getSyncScope();
await ditto.smallPeerInfo.setSyncScope('BigPeerOnly');
ditto.smallPeerInfo.metadata = { test: 'metadata' };
```
:::

# Setting Up Presence

Monitor remote peers in the logs or using Ditto’s Presence Viewer app. For more information, see the blog post “[An explanation of the Ditto Presence Viewer.](https://ditto.live/blog/ditto-presence-viewer)”

To set up presence observations:

:::CodeblockTabs
&#x20;

```javascript
// This closure is called every time the mesh of
// connected Ditto peers changes:
ditto.presence.observe((graph) => {
  console.log('Peers: ', graph.remotePeers);
});
```
:::

# Setting Logs to Debug Level

Capture database debug logs by setting the Ditto log level to Debug mode. That way, any potential issues are tracked.

To set the minimum log level to `Debug`:

:::CodeblockTabs
&#x20;

```javascript
Logger.minimumLogLevel = 'Debug';
```
:::

# Troubleshooting JSI Bindings Error

When using the Ditto SDK for React Native in the iOS simulator, you may encounter issues related to the JSI bindings not being installed for the DittoRNSDK module when using the Hermes JavaScript engine.

To resolve the issue, modify your project settings and dependencies:

:::::WorkflowBlock
::::WorkflowBlockItem
From the `ios/Podfile` file in your project, set the minimum deployment target for iOS:

:::CodeblockTabs
&#x20;

```none
platform :ios, 14
```
:::
::::

::::WorkflowBlockItem
From the `ios` directory in your project, update CocoaPods dependencies:&#x20;

:::CodeblockTabs
&#x20;

```none
pod install
```
:::
::::

:::WorkflowBlockItem
If you encounter a filesystem permissions error after updating CocoaPods dependencies:

1. &#x20;From Xcode, disable the macOS App sandbox. For instructions, see the official [Configuring the macOS App Sandbox](https://developer.apple.com/documentation/xcode/configuring-the-macos-app-sandbox) from Apple.
2. Using the `sudo` command, run your project with elevated privileges.
:::
:::::

