firebasereact-nativefirebase-authenticationexpofirebase-tools

firebase.auth().useEmulator() takes a non-empty string URL



THE PROBLEM


When I run the command:
npx expo run:android
or
npx expo start --reset-cache

My Android Cellphone is connected on my USB port.

I get this error: firebase.auth().useEmulator() takes a non-empty string URL

I suspect the Android app running on my Cellphone can't reach the computer IP using USB.

Or the problem is in the types' definition .d.ts, but I don't have any idea how to solve the signatures of the method useEmulator()

Without the command for emulators the app works connecting to firebase.

enter image description here

console error:

› Logs for your project will appear below. Press Ctrl+C to exit.
Android Bundled 754ms node_modules/expo-router/entry.js (1222 modules)
 ERROR  Error: firebase.auth().useEmulator() takes a non-empty string URL

This error is located at:
    in TabTwoScreen
    in Unknown (created by Route(explore))
    in Suspense (created by Route(explore))
    in Route (created by Route(explore))
    in Route(explore) (created by SceneView)
    in StaticContainer
    in EnsureSingleNavigator (created by SceneView)
    in SceneView (created by BottomTabView)
    in RCTView (created by View)
    in View (created by Screen)
    in RCTView (created by View)
    in View (created by Background)
    in Background (created by Screen)
    in Screen (created by BottomTabView)
    in RNSScreen (created by Animated(Anonymous))
    in Animated(Anonymous) (created by InnerScreen)
    in Suspender (created by Freeze)
    in Suspense (created by Freeze)
    in Freeze (created by DelayedFreeze)
    in DelayedFreeze (created by InnerScreen)
    in InnerScreen (created by Screen)
    in Screen (created by MaybeScreen)
    in MaybeScreen (created by BottomTabView)
    in RNSScreenContainer (created by ScreenContainer)
    in ScreenContainer (created by MaybeScreenContainer)
    in MaybeScreenContainer (created by BottomTabView)
    in RCTView (created by View)
    in View (created by SafeAreaProviderCompat)
    in SafeAreaProviderCompat (created by BottomTabView)
    in BottomTabView (created by BottomTabNavigator)
    in PreventRemoveProvider (created by NavigationContent)
    in NavigationContent
    in Unknown (created by BottomTabNavigator)
    in BottomTabNavigator
    in Unknown (created by TabLayout)
    in TabLayout
    in Unknown (created by Route((tabs)))
    in Suspense (created by Route((tabs)))
    in Route (created by Route((tabs)))
    in Route((tabs)) (created by SceneView)
    in StaticContainer
    in EnsureSingleNavigator (created by SceneView)
    in SceneView (created by SceneView)
    in RCTView (created by View)
    in View (created by DebugContainer)
    in DebugContainer (created by MaybeNestedStack)
    in MaybeNestedStack (created by SceneView)
    in RCTView (created by View)
    in View (created by SceneView)
    in RNSScreen (created by Animated(Anonymous))
    in Animated(Anonymous) (created by InnerScreen)
    in Suspender (created by Freeze)
    in Suspense (created by Freeze)
    in Freeze (created by DelayedFreeze)
    in DelayedFreeze (created by InnerScreen)
    in InnerScreen (created by Screen)
    in Screen (created by SceneView)
    in SceneView (created by NativeStackViewInner)
    in Suspender (created by Freeze)
    in Suspense (created by Freeze)
    in Freeze (created by DelayedFreeze)
    in DelayedFreeze (created by ScreenStack)
    in RNSScreenStack (created by ScreenStack)
    in ScreenStack (created by NativeStackViewInner)
    in NativeStackViewInner (created by NativeStackView)
    in RCTView (created by View)
    in View (created by SafeAreaProviderCompat)
    in SafeAreaProviderCompat (created by NativeStackView)
    in NativeStackView (created by NativeStackNavigator)
    in PreventRemoveProvider (created by NavigationContent)
    in NavigationContent
    in Unknown (created by NativeStackNavigator)
    in NativeStackNavigator
    in Unknown (created by RootLayout)
    in ThemeProvider (created by RootLayout)
    in RootLayout
    in Unknown (created by Route())
    in Suspense (created by Route())
    in Route (created by Route())
    in Route() (created by ContextNavigator)
    in RNCSafeAreaProvider (created by SafeAreaProvider)
    in SafeAreaProvider (created by wrapper)
    in wrapper (created by ContextNavigator)
    in EnsureSingleNavigator
    in BaseNavigationContainer
    in ThemeProvider
    in NavigationContainerInner (created by ContextNavigator)
    in ContextNavigator (created by ExpoRoot)
    in ExpoRoot (created by App)
    in App (created by ErrorOverlay)
    in ErrorToastContainer (created by ErrorOverlay)
    in ErrorOverlay (created by withDevTools(ErrorOverlay))
    in withDevTools(ErrorOverlay)
    in RCTView (created by View)
    in View (created by AppContainer)
    in RCTView (created by View)
    in View (created by AppContainer)
    in AppContainer
    in main(RootComponent), js engine: hermes
 ERROR  Error: firebase.auth().useEmulator() takes a non-empty string URL


CONFIGURATIONS



npm modules started:
npx expo install firebase
npx expo install @react-native-firebase/app
npx expo install @react-native-firebase/auth

FIREBASE SETUP:
firebase init

EMULATOR SETUP:
firebase init emulators

I started my emulators:
firebase emulators:start

PROJECT SETUP:

android/build.gradle

    dependencies {
        classpath('com.google.gms:google-services:4.4.2')
    }

android/app/build.gradle

apply plugin: 'com.google.gms.google-services'

firebaseConfig.js

import { initializeApp } from 'firebase/app';

// Optionally import the services that you want to use
// import {...} from "firebase/auth";
// import {...} from "firebase/database";
// import {...} from "firebase/firestore";
// import {...} from "firebase/functions";
// import {...} from "firebase/storage";

// Initialize Firebase
const firebaseConfig = {
  apiKey: '....',
  authDomain: '.....firebaseapp.com',
  projectId: '.....',
  storageBucket: "......firebasestorage.app",
  messagingSenderId: "......",
  appId: "1:......:web:......"
};

const app = initializeApp(firebaseConfig);

The root folder has the firebase.json configured

enter image description here

enter image description here

enter image description here

EMULATOR LOG:
enter image description here

my android folder has:
google-services.json
debug.keystore

my project settings in firebase console and my debug.keystore have the same SHA1.

app.json

{
  "expo": {
    "plugins": [
      "@react-native-firebase/app",
      "@react-native-firebase/auth",
      "expo-router"
    ],
  }
}

explore.tsx

import auth from '@react-native-firebase/auth';
export default function TabTwoScreen() {
  const fire = auth()
  fire.useEmulator("192.168.1.26:9099")
}

I tried using:

fire.useEmulator("localhost:9099")

And tried using:

fire.useEmulator("10.0.2.2:9099")

Solution

  • As shown in your screenshot, you are hitting the exception thrown by this validation check:

    useEmulator(url) {
      if (!url || !isString(url) || !isValidUrl(url)) {
        throw new Error('firebase.auth().useEmulator() takes a non-empty string URL');
      }
    
      // ...
    }
    

    Feeding this function the value 192.168.1.26:9099 passes the !url and !isString(url) checks.

    But if we take a closer look at the implementation of isValidUrl, we can see where things go awry:

    /**
     * URL test
     * @param url
     * @returns {boolean}
     */
    const IS_VALID_URL_REGEX = /^(http|https):\/\/[^ "]+$/;
    export function isValidUrl(url) {
      return IS_VALID_URL_REGEX.test(url);
    }
    

    Based on this regular expression, we can see that the provided URL must start with http:// or https:// followed by some additional characters that are not spaces or double-quote characters.

    This means you should be using the string http://192.168.1.26:9099 as the URL, assuming that 192.168.1.26 is the IP address of your computer hosting the emulators.