This is documentation for Stream Chat React Native SDK v4, which is nolonger actively maintained. For up-to-date documentation, see the latest version (v5).

Troubleshooting

There are a few common problems users have reported when setting up Stream Chat for React Native, to help you if you run afoul of these problems we have created a list of common issues and solutions. If you encounter something that is not listed here, try searching for the issue in GitHub.

Cannot run remote debugger

React Native is undergoing major architecture changes, Reanimated 2 has capitalized on the already released improvements and taken advantage of the JSI to provide an amazingly powerful library. Currently though there are a list of limitations that Reanimated 2 has, one of which is that the use of the JSI prevents debugging without using Flipper, therefore you must use Flipper for remote debugging.

Messages sending in thread instead of channel

There is an internal thread state that is used to track the current thread. When you click on a thread and take an action such as navigating to another screen the thread is set within the Channel component in the current screen to the selected thread. When you return to the original screen you need to reset the thread to ensure it is not being set on the messages when they are sent. We suggest you keep track of a thread state on your own and provide it to any Channel component you use whether on a channel or thread.

<Chat client={chatClient} i18nInstance={streami18n}>
  <Channel channel={channel} thread={thread}>
    <MessageList onThreadSelect={setThread} />
    <MessageInput />
  </Channel>
</Chat>
<Chat client={chatClient} i18nInstance={streami18n}>
  <Channel channel={channel} thread={thread} threadList>
    <Thread onThreadDismount={() => setThread(null)} />
  </Channel>
</Chat>

You may be wondering why this is all necessary, this is because in most cases there is only a single OverlayProvider. The OverlayProvider keeps track of the currently selected images in the image picker, and the images available to view in the image gallery from a given channel or thread. To keep these in sync with the currently visible screen some logic is used to determine whether or not they should update, this logic is dependant on the thread state.

Undefined is not a function

Stream Chat for React Native relies heavily on context, in instances where the Render Error undefined is not a function occurs it is almost always the case that a context provider is not wrapping a component appropriately. If you encounter this error please ensure the OverlayProvider, Chat, and Channel components are wrapping your application correctly.

Incorrect input position

If the MessageInput is at the incorrect height when the keyboard is displayed a setting could being incorrect.

Ensure the keyboardVerticalOffset prop passed to Channel is correct and accounts for any header height that may need to be adjusted for.

Android

On Android if the StatusBar is set to translucent, that is StatusBar.setTranslucent(true) then there may be some inaccurate layout calculations occurring.

If you are using the standard React Native Android keyboard setting of android:windowSoftInputMode="adjustResize", you can disable to layout adjustments on Android using the prop disableKeyboardCompatibleView and this will ignore the incorrect measurements.

The image viewer is created in the OverlayProvider so it can cover the entire screen, thus if you are wrapping your navigation in the OverlayProvider there is only copy present throughout the application. The images present in the viewer are determined by logic based off of both the current channel and thread provided to the Channel component. You therefore must keep these props up to date as you navigate to ensure when returning to a channel from a thread the images in the viewer are once again updated to those from the channel.

To do this make sure your Channel components are always aware of the thread state, even when being used for a channel.

<Channel channel={channel} thread={thread}>
  <MessageList onThreadSelect={setThread} />
  <MessageInput />
</Channel>
<Channel channel={channel} thread={thread} threadList>
  <Thread onThreadDismount={() => setThread(null)} />
</Channel>

If the image viewer or message overlay is not covering the full screen, for instance it is rendering below or behind a Header, it is likely the OverlayProvider is not setup in the correct location within the application. Please refer to the Stream Chat with Navigation documentation to properly place the OverlayProvider in relation to your navigation solution or other components.

Image picker incorrect height

The image picker opens the gallery to a height based on the location of the MessageInput, if there is space below the MessageInput, for instance a Safe Area or a Tab Bar, this must be taken into account. To account for this the prop bottomInset can be provided to the OverlayProvider.

<OverlayProvider bottomInset={/** number */}>

Similarly if the gallery fully open is not at the desired height, this can be adjusted using the OverlayProvider prop topInset.

<OverlayProvider topInset={/** number */}>

topInset prior to version 3.6.0 needed to be set before the image picker would render. Additionally it could only be set one time via either props or the setTopInset function, otherwise the gallery would open to incorrect heights. Both bottomInset & topInset can be set via the appropriate functions, setBottomInset and setTopInset, that are accessible via the useAttachmentPickerContext hook.

Android

On Android if the StatusBar is set to translucent, that is StatusBar.setTranslucent(true) then you need to provide the prop translucentStatusBar to the OverlayProvider. This prop is a boolean that adjusts for differences in the measurements of the screen height when the StatusBar on Android is translucent. It is important to note that since Expo 38 true is the default for transparent on Android.

Image picker not working

If the image picker is appearing incorrectly, for instance behind a bottom Tab Bar, it is likely the OverlayProvider is not setup in the correct location within the application. Please refer to the Stream Chat with Navigation documentation to properly place the OverlayProvider in relation to your navigation solution.

iOS

Add the NSPhotoLibraryUsageDescription key in your Info.plist with a description of use.
Add the NSPhotoLibraryAddUsageDescription key in your Info.plist with a description of use.

Android

The standard storage permissions are required for the image picker to work on Android, and must be included in the AndroidManifest.xml file.

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

In addition, and often overlooked, within the application tag you must included the requestLegacyExternalStorage attribute.

<application
  android:requestLegacyExternalStorage="true"
  ...
/>

Without this some Android devices will fail to load images despite permissions being granted within the settings.

Camera not working

iOS

Add the NSCameraUsageDescription key in your Info.plist with a description of use.
Add the NSPhotoLibraryUsageDescription key in your Info.plist with a description of use.
Add the NSMicrophoneUsageDescription key in your Info.plist with a description of use.

Android

The standard camera permissions are required for the camera to work on Android, and must be included in the AndroidManifest.xml file.

<uses-permission android:name="android.permission.CAMERA"/>

Add maven { url 'https://maven.google.com' } to android/build.gradle

allprojects {
  repositories {
    mavenLocal()
    maven {
      // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
      url("$rootDir/../node_modules/react-native/android")
    }
    maven {
      // Android JSC is installed from npm
      url("$rootDir/../node_modules/jsc-android/dist")
    }

    google()
    jcenter()
    maven { url 'https://maven.google.com' }
    maven { url 'https://www.jitpack.io' }
  }
}

Ensure buildToolsVersion, compileSdkVersion, and targetSdkVersion are all >= 26 in android/build.gradle

buildscript {
  ext {
    buildToolsVersion = "29.0.3"
    compileSdkVersion = 29
    targetSdkVersion = 29
    ...
  }
  ...
}

Add vectorDrawables.useSupportLibrary = true to android/app/build.gradle

android {
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
        ...
    }
    ...
}

Android

Opening an external link doesn’t work without permissions on targetSdkVersion >= 30. So, the following permission must be included in the AndroidManifest.xml file.

<queries>
  <intent>
    <action android:name="android.intent.action.VIEW" />
    <data android:scheme="http" android:host="*" />
  </intent>
  <intent>
    <action android:name="android.intent.action.VIEW" />
    <data android:scheme="https" android:host="*" />
  </intent>
</queries>

GIF and WebP not displaying

Android

GIF and WebP do not work without additional modules by default on Android.

You will need to add some modules in your android/app/build.gradle

dependencies {
  // For Android versions less than Ice Cream Sandwich (API level 14)
  implementation 'com.facebook.fresco:animated-base-support:1.3.0'

  // For GIF support
  implementation 'com.facebook.fresco:animated-gif:2.0.0'

  // For WebP support, with animations
  implementation 'com.facebook.fresco:animated-webp:2.1.0'

  // For WebP support, without animations
  implementation 'com.facebook.fresco:webpsupport:2.0.0'
  ...
}

Blank screen when channel gets delete

When a channel is deleted, and if some user is active on that channel, a blank screen appears by default (as per the default logic) as we return null in this case. It might be confusing for end user to see a blank screen and appropriate UX would be to navigate back to channel list screen. You can implement such UX by listening to channel.deleted event on channel screen, and navigate to channel list screen with appropriate notification on app.

client.on('channel.deleted', event => {
  if (event.cid === channel.cid) {
    // add your action here
  }
});

Touchables not working

If you are having trouble with pressing, swiping, or otherwise interacting with components it is likely the result of React Native Gesture Handler not being properly setup.

If your React Native version is (>=0.68) you will need a version of >=2.0.0 for react-native-gesture-handler for your app to build.

Be sure to follow all needed additional steps to complete the installation.

This includes ensuring you import react-native-gesture-handler at the top of your app entry file.

import 'react-native-gesture-handler';

Also do not forget to wrap your component tree(probably above OverlayProvider) with <GestureHandlerRootView> or gestureHandlerRootHOC as mentioned in RNGH Installation docs. Not doing so, can cause unusual behaviour with the MessageOverlay and Imagegallery gestures.

<GestureHandlerRootView style={{ flex: 1 }}>
  <OverlayProvider>// Other underlying components</OverlayProvider>
</GestureHandlerRootView>

If you are using v1 of react-native-gesture-handler library, then you will need extra setup steps for Android. Update MainActivity.java to override the method for creating the ReactRootView as mentioned in RNGH Installation docs.

package com.swmansion.gesturehandler.react.example;

import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
public class MainActivity extends ReactActivity {

  @Override
  protected String getMainComponentName() {
    return "Example";
  }
  @Override
  protected ReactActivityDelegate createReactActivityDelegate() {
    return new ReactActivityDelegate(this, getMainComponentName()) {
      @Override
      protected ReactRootView createRootView() {
        return new RNGestureHandlerEnabledRootView(MainActivity.this);
      }
    };
  }
}

Touchables Inside Custom Components Are Not Working

If you find that a customization that includes a touchable is not working, or the wrong element is receiving the touch event, this is likely related to React Native Gesture Handler. The following could be the reasons behind the issues you might be facing:

  • Your component may be being rendered inside of a gesture handler.
  • Nested gesture handlers and touchables need special treatment and can act differently on iOS & Android. If you want Nested Touchables to work on Android you should add the prop disallowInterruption as mentioned here.

There are solutions available for almost all use cases so looking into your specific use case in relation to React Native Gesture Handler is suggested. The solution may require using a different touchable from React Native Gesture Handler and React Native depending on the platform.

Reanimated 2

We rely on Reanimated 2 heavily for gesture based interactions and animations. It is vital you follow the Reanimated 2 installation instructions for the library to work properly.

Failed to create a Worklet

If you are encountering errors related to Reanimated 2 failed to create a worklet you must likely forgot to add the react-native-reanimated/plugin to your project’s babel config file. Below is an example of adding Reanimated babel plugin to babel.config.js:

  module.exports = {
      ...
      plugins: [
          ...
          'react-native-reanimated/plugin',
      ],
  };

Reanimated plugin has to be listed last.

Blank screen on Android

If you are encountering errors on Android and the screen is blank it is likely you forgot to finish the Reanimated 2 Android setup.

Ensure Hermes is enabled in android/app/build.gradle:

project.ext.react = [
  enableHermes: true  // clean and rebuild if changing
]

Add Reanimated in MainApplication.java

import com.facebook.react.bridge.JSIModulePackage;
import com.swmansion.reanimated.ReanimatedJSIModulePackage;
...

private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
  ...

  @Override
  protected String getJSMainModuleName() {
    return "index";
  }

  @Override
  protected JSIModulePackage getJSIModulePackage() {
    return new ReanimatedJSIModulePackage();
  }
};
...

Android release bundle is crashing

This is likely due to ProGuard removing reanimated 2 related classes. If you’re using ProGuard, make sure to add the rules below:

-keep class com.swmansion.reanimated.** { *; }
-keep class com.facebook.react.turbomodule.** { *; }

Project won’t build on a MacBook with Apple M1

On newer MacBooks with the Apple M1 SoC, there are a few required steps that need to be followed for an app to build. The user aiba has written a guide to make the necessary changes to your project.

The iOS build version can be changed to suit your needs, but keep in mind to change the version to the same major and minor version consistently throughout the guide.

© Getstream.io, Inc. All Rights Reserved.