Skip to content

🔥[🐛] Crashlytics does not report crashes in debug mode when using expo-dev-client #8561

Open
@algoORgoal

Description

@algoORgoal

Issue

  • When using an Expo project with react-native-firebase/crashlytics, calling crashlytics().crash() does not work as expected in debug mode if expo-dev-client is installed.
  • Without having expo-dev-client in dependencies, the app crashes natively and the crash is reported to the Firebase console as expected.
  • With expo-dev-client in dependencies, the app crashes. However, instead of a native crash, I see the error overlay provided by Expo, and the crash is not reported to Firebase.
  • I assume this happens because expo-dev-client provides a custom error overlay that catches and displays errors instead of letting the app crash natively.
  • If this behavior is expected and cannot be resolved, I think it should be documented in the official docs so that others do not waste time trying to make it work.
  • Here is the reproduction repository: https://github.com/algoORgoal/my-app/tree/infra/set-up-crashlytics. Make sure to check out to branch set-up-crashlytics.
  • Below is the error screen provided by expo-dev-client. When this screen pops up, the test crash is not sent to firebase.
    error screen provided by expo-dev-client

Project Files

Javascript

Click To Expand

package.json:

{
  "name": "my-app",
  "main": "expo-router/entry",
  "version": "1.0.0",
  "scripts": {
    "start": "expo start",
    "reset-project": "node ./scripts/reset-project.js",
    "android": "expo run:android",
    "ios": "expo run:ios",
    "web": "expo start --web",
    "lint": "expo lint",
    "keystore:debug": "keytool -list -v -keystore ./android/app/debug.keystore",
    "log:crash": "adb logcat | grep -i crash",
    "install:expo": "npx expo install"
  },
  "dependencies": {
    "@expo/vector-icons": "~14.1.0",
    "@react-native-firebase/app": "~22.2.0",
    "@react-native-firebase/crashlytics": "~22.2.0",
    "@react-navigation/bottom-tabs": "^7.3.10",
    "@react-navigation/elements": "~2.3.8",
    "@react-navigation/native": "^7.1.6",
    "@reduxjs/toolkit": "~2.8.2",
    "expo": "~53.0.10",
    "expo-blur": "~14.1.5",
    "expo-constants": "~17.1.6",
    "expo-dev-client": "~5.2.0",
    "expo-font": "~13.3.1",
    "expo-haptics": "~14.1.4",
    "expo-image": "~2.2.0",
    "expo-linking": "~7.1.5",
    "expo-router": "~5.0.7",
    "expo-splash-screen": "~0.30.9",
    "expo-status-bar": "~2.2.3",
    "expo-symbols": "~0.4.5",
    "expo-system-ui": "~5.0.8",
    "expo-web-browser": "~14.1.6",
    "react": "19.0.0",
    "react-dom": "19.0.0",
    "react-native": "0.79.3",
    "react-native-gesture-handler": "~2.24.0",
    "react-native-reanimated": "~3.17.4",
    "react-native-safe-area-context": "5.4.0",
    "react-native-screens": "~4.11.1",
    "react-native-web": "~0.20.0",
    "react-native-webview": "13.13.5",
    "react-redux": "~9.2.0"
  },
  "devDependencies": {
    "@babel/core": "~7.25.2",
    "@types/react": "~19.0.10",
    "typescript": "~5.8.3",
    "eslint": "~9.25.0",
    "eslint-config-expo": "~9.2.0"
  },
  "private": true,
  "expo": {
    "doctor": {
      "reactNativeDirectoryCheck": {
        "listUnknownPackages": false
      }
    }
  }
}

firebase.json for react-native-firebase v6:

{
  "react-native": {
    "crashlytics_debug_enabled": true,
    "crashlytics_disable_auto_disabler": true,
    "crashlytics_auto_collection_enabled": true,
    "crashlytics_is_error_generation_on_js_crash_enabled": true,
    "crashlytics_javascript_exception_handler_chaining_enabled": true
  }
}

iOS

Click To Expand

ios/Podfile:

  • I'm not using Pods
  • I'm using Pods and my Podfile looks like:
# N/A

AppDelegate.m:

// N/A


Android

Click To Expand

Have you converted to AndroidX?

  • my application is an AndroidX application?
  • I am using android/gradle.settings jetifier=true for Android compatibility?
  • I am using the NPM package jetifier for react-native compatibility?

android/build.gradle:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
  repositories {
    google()
    mavenCentral()
  }
  dependencies {
        classpath 'com.google.firebase:firebase-crashlytics-gradle:3.0.3'
        classpath 'com.google.gms:google-services:4.4.1'
    classpath('com.android.tools.build:gradle')
    classpath('com.facebook.react:react-native-gradle-plugin')
    classpath('org.jetbrains.kotlin:kotlin-gradle-plugin')
  }
}

def reactNativeAndroidDir = new File(
  providers.exec {
    workingDir(rootDir)
    commandLine("node", "--print", "require.resolve('react-native/package.json')")
  }.standardOutput.asText.get().trim(),
  "../android"
)

allprojects {
  repositories {
    maven {
      // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
      url(reactNativeAndroidDir)
    }

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

apply plugin: "expo-root-project"
apply plugin: "com.facebook.react.rootproject"

android/settings.gradle:

pluginManagement {
  def reactNativeGradlePlugin = new File(
    providers.exec {
      workingDir(rootDir)
      commandLine("node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })")
    }.standardOutput.asText.get().trim()
  ).getParentFile().absolutePath
  includeBuild(reactNativeGradlePlugin)
  
  def expoPluginsPath = new File(
    providers.exec {
      workingDir(rootDir)
      commandLine("node", "--print", "require.resolve('expo-modules-autolinking/package.json', { paths: [require.resolve('expo/package.json')] })")
    }.standardOutput.asText.get().trim(),
    "../android/expo-gradle-plugin"
  ).absolutePath
  includeBuild(expoPluginsPath)
}

plugins {
  id("com.facebook.react.settings")
  id("expo-autolinking-settings")
}

extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
  if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') {
    ex.autolinkLibrariesFromCommand()
  } else {
    ex.autolinkLibrariesFromCommand(expoAutolinking.rnConfigCommand)
  }
}
expoAutolinking.useExpoModules()

rootProject.name = 'my-app'

expoAutolinking.useExpoVersionCatalog()

include ':app'
includeBuild(expoAutolinking.reactNativeGradlePlugin)

MainApplication.kt:

package com.ryan46.myapp

import android.app.Application
import android.content.res.Configuration

import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.ReactHost
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.soloader.SoLoader

import expo.modules.ApplicationLifecycleDispatcher
import expo.modules.ReactNativeHostWrapper

class MainApplication : Application(), ReactApplication {

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

          override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry"

          override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG

          override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
          override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
      }
  )

  override val reactHost: ReactHost
    get() = ReactNativeHostWrapper.createReactHost(applicationContext, reactNativeHost)

  override fun onCreate() {
    super.onCreate()
    SoLoader.init(this, OpenSourceMergedSoMapping)
    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
      // If you opted-in for the New Architecture, we load the native entry point for this app.
      load()
    }
    ApplicationLifecycleDispatcher.onApplicationCreate(this)
  }

  override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)
    ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig)
  }
}

AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  <uses-permission android:name="android.permission.INTERNET"/>
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
  <uses-permission android:name="android.permission.VIBRATE"/>
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  <queries>
    <intent>
      <action android:name="android.intent.action.VIEW"/>
      <category android:name="android.intent.category.BROWSABLE"/>
      <data android:scheme="https"/>
    </intent>
  </queries>
  <application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true">
    <meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>
    <meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
    <meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
    <activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
      <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="myapp"/>
        <data android:scheme="exp+my-app"/>
      </intent-filter>
    </activity>
  </application>
</manifest>


Environment

Click To Expand

npx expo-env-info output:

  expo-env-info 1.3.3 environment info:
    System:
      OS: macOS 15.5
      Shell: 5.9 - /bin/zsh
    Binaries:
      Node: 22.15.0 - ~/.nvm/versions/node/v22.15.0/bin/node
      npm: 10.9.2 - ~/.nvm/versions/node/v22.15.0/bin/npm
      Watchman: 2025.04.14.00 - /opt/homebrew/bin/watchman
    Managers:
      CocoaPods: 1.16.2 - /opt/homebrew/bin/pod
    SDKs:
      iOS SDK:
        Platforms: DriverKit 24.5, iOS 18.5, macOS 15.5, tvOS 18.5, visionOS 2.5, watchOS 11.5
    IDEs:
      Android Studio: 2024.2 AI-242.23726.103.2422.12816248
      Xcode: 16.4/16F6 - /usr/bin/xcodebuild
    npmPackages:
      expo: ~53.0.10 => 53.0.11 
      expo-router: ~5.0.7 => 5.0.7 
      react: 19.0.0 => 19.0.0 
      react-dom: 19.0.0 => 19.0.0 
      react-native: 0.79.3 => 0.79.3 
      react-native-web: ~0.20.0 => 0.20.0 
    npmGlobalPackages:
      eas-cli: 16.6.2
    Expo Workflow: bare
 OUTPUT GOES HERE
  • Platform that you're experiencing the issue on:
    • iOS
    • Android
    • iOS but have not tested behavior on Android
    • Android but have not tested behavior on iOS
    • Both
  • react-native-firebase version you're using that has this issue:
    • v22.2.0
  • Firebase module(s) you're using that has the issue:
    • e.g. Instance ID
  • Are you using TypeScript?
    • Y, v5.8.3


Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions