Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

auth().onAuthStateChanged does not always trigger after sign-in on Android in React Native 0.77 #8374

Open
KAMRONBEK opened this issue Feb 26, 2025 · 12 comments
Labels
Needs Attention platform: android plugin: authentication Firebase Authentication type: bug New bug report Workflow: Needs Review Pending feedback or review from a maintainer.

Comments

@KAMRONBEK
Copy link

KAMRONBEK commented Feb 26, 2025

Hi Everybody, Any help would be greatly appreciated! auth().onAuthStateChanged is not working properly. On Android, after signing in, sometimes auth().onAuthStateChanged does not trigger. For example, after building the APK, signing in doesn't work at all. However, everything works fine on iOS.
Additionally, after uninstalling and rebuilding the app, this issue sometimes occurs. But when I completely close the app and reopen it, I find that the user is already signed in.
Thank you in advance for any assistance!

Expected Behavior:
auth().onAuthStateChanged should always trigger when a user signs in.

Current Behavior:
Sometimes, auth().onAuthStateChanged does not execute on Android, and the authenticated user state is not detected.

import React, { useContext, useEffect, useRef, useState } from 'react'
import analytics from '@react-native-firebase/analytics'
import Toast from 'react-native-toast-message'
import { OverflowMenuProvider } from 'react-navigation-header-buttons'
import RNBootSplash from 'react-native-bootsplash'
import auth, { FirebaseAuthTypes } from '@react-native-firebase/auth'
import { NavigationContainer } from '@react-navigation/native'
import { AuthContext, UserFoundStates } from '../config/auth_context'
import { getUsersCountById } from '../api/firestore/get-users-by-id'
import PortalHost from '../components/portal/portal-host'
import AuthNavigator from './auth_navigator'
import RootNavigator from './root'
import { navRef } from './root_navigation_ref'
import { handleAppUpdates } from '../utils/app-update-handler'
import { UserContextProvider } from '../config/user_context'

const Navigator = () => {
const [initializing, setInitializing] = useState(true)
const { authUser, setAuthUser, userFound, setUserFound } =
useContext(AuthContext)
const routeNameRef = useRef()

console.log('auth.currentUser', auth().currentUser)

useEffect(() => {
handleAppUpdates()
}, [])

useEffect(() => {
const handleAuthChange = (user: FirebaseAuthTypes.User | null) => {
setUserFound(UserFoundStates.InProgress)
setAuthUser(user ?? undefined)
}

const subscription = auth().onAuthStateChanged(handleAuthChange)
return () => subscription()
// eslint-disable-next-line react-hooks/exhaustive-deps

}, [])

useEffect(() => {
if (authUser) {
getUsersCountById(authUser.uid).then((count) => {
if (initializing) setInitializing(false)
if (count !== 0) {
setUserFound(UserFoundStates.Found)
} else {
setUserFound(UserFoundStates.NotFound)
}
})
} else {
setUserFound(UserFoundStates.NotFound)
if (initializing) setInitializing(false)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [authUser])

if (initializing) {
return null
}

return (

<NavigationContainer
ref={navRef}
onReady={() => {
routeNameRef.current = navRef.current?.getCurrentRoute().name
RNBootSplash.hide({ fade: true })
}}
onStateChange={async () => {
const previousRouteName = routeNameRef.current
const currentRouteName = navRef.current.getCurrentRoute().name

      if (previousRouteName !== currentRouteName) {
        await analytics().logScreenView({
          screen_name: currentRouteName,
          screen_class: currentRouteName,
        })
      }

      // Save the current route name for later comparison
      routeNameRef.current = currentRouteName
    }}>
    <OverflowMenuProvider>
      {userFound === UserFoundStates.Found ? (
        <UserContextProvider userId={authUser?.uid}>
          <RootNavigator />
        </UserContextProvider>
      ) : (
        <AuthNavigator />
      )}
    </OverflowMenuProvider>
    <Toast ref={(ref) => Toast.setRef(ref)} />
  </NavigationContainer>
</PortalHost>

)
}

export default Navigator

package.json:
"scripts": {
"android": "react-native run-android --mode=prodDebug",
"android:staging": "react-native run-android --mode=stagingDebug --appIdSuffix=staging",
"ios": "react-native run-ios",
"ios:staging": "react-native run-ios --scheme SwishStaging Debug",
"start": "react-native start",
"test": "jest",
"pods": "cd ios && RCT_NEW_ARCH_ENABLED=1 bundle exec pod install",
"lint": "eslint . --ext .ts,.tsx,.js,.jsx",
"lint:fix": "eslint . --ext .ts,.tsx,.js,.jsx --fix --quiet",
"format": "prettier --check .",
"format:fix": "prettier --write ."
},
"dependencies": {
"@expo/react-native-action-sheet": "^3.9.0",
"@invertase/react-native-apple-authentication": "^2.3.0",
"@react-native-async-storage/async-storage": "^1.18.2",
"@react-native-camera-roll/camera-roll": "^7.9.0",
"@react-native-clipboard/clipboard": "^1.14.1",
"@react-native-community/datetimepicker": "^8.2.0",
"@react-native-community/push-notification-ios": "^1.10.1",
"@react-native-community/slider": "^4.3.1",
"@react-native-firebase/analytics": "^21.7.1",
"@react-native-firebase/app": "^21.7.1",
"@react-native-firebase/auth": "^21.7.1",
"@react-native-firebase/crashlytics": "^21.7.1",
"@react-native-firebase/dynamic-links": "^21.7.1",
"@react-native-firebase/firestore": "^21.7.1",
"@react-native-firebase/functions": "^21.7.1",
"@react-native-firebase/messaging": "^21.7.1",
"@react-native-firebase/storage": "^21.7.1",
"@react-native-google-signin/google-signin": "^13.1.0",
"@react-native-picker/picker": "^2.9.0",
"@react-navigation/bottom-tabs": "~6.6.1",
"@react-navigation/core": "~6.4.17",
"@react-navigation/native": "~6.1.18",
"@react-navigation/native-stack": "~6.10.1",
"@react-navigation/stack": "~6.4.1",
"country-state-city": "^3.2.1",
"fbjs": "^3.0.5",
"geofirestore": "5.2.0",
"geokit": "1.1.0",
"lodash": "4.17.20",
"moment": "2.29.1",
"promise.allsettled": "^1.0.4",
"react": "18.3.1",
"react-native": "0.77.0",
"react-native-bootsplash": "~6.3.2",
"react-native-calendar-events": "^2.2.0",
"react-native-config": "^1.5.0",
"react-native-device-info": "^8.7.1",
"react-native-draggable-flatlist": "^4.0.1",
"react-native-geocoding": "^0.5.0",
"react-native-geolocation-service": "^5.3.1",
"react-native-gesture-handler": "~2.22.0",
"react-native-get-random-values": "^1.11.0",
"react-native-global-props": "^1.1.5",
"react-native-google-places-autocomplete": "^2.5.7",
"react-native-image-crop-picker": "^0.41.2",
"react-native-international-phone-number": "^0.7.6",
"react-native-keyboard-aware-scroll-view": "^0.9.5",
"react-native-lightbox-v2": "^0.9.0",
"react-native-linear-gradient": "^2.5.6",
"react-native-localize": "^2.0.3",
"react-native-maps": "^1.20.1",
"react-native-permissions": "^4.1.5",
"react-native-picker-select": "^9.3.1",
"react-native-push-notification": "^8.1.1",
"react-native-qrcode-svg": "^6.1.2",
"react-native-reanimated": "^3.16.7",
"react-native-safe-area-context": "^5.2.0",
"react-native-screens": "^4.6.0",
"react-native-svg": "^15.8.0",
"react-native-toast-message": "^1.6.0",
"react-native-url-polyfill": "^1.3.0",
"react-native-webview": "^13.13.2",
"react-navigation-header-buttons": "^10.0.0",
"rn-fetch-blob": "^0.12.0",
"use-memo-one": "^1.1.1",
"uuid": "^11.0.4"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.3",
"@babel/runtime": "^7.25.0",
"@faker-js/faker": "8.3.1",
"@react-native-community/cli": "15.0.1",
"@react-native-community/cli-platform-android": "15.0.1",
"@react-native-community/cli-platform-ios": "15.0.1",
"@react-native/babel-preset": "0.77.0",
"@react-native/eslint-config": "0.77.0",
"@react-native/metro-config": "0.77.0",
"@react-native/typescript-config": "0.77.0",
"@testing-library/react-native": "^13.0.1",
"@types/jest": "^29.5.13",
"@types/lodash": "4.14.167",
"@types/promise.allsettled": "^1.0.3",
"@types/react": "^18.2.6",
"@types/react-native-global-props": "^1.1.1",
"@types/react-native-push-notification": "^7.3.3",
"@types/react-test-renderer": "^18.0.0",
"@types/uuid": "^10.0.0",
"babel-plugin-module-resolver": "^5.0.2",
"deprecated-react-native-prop-types": "^4.2.1",
"detox": "^20.20.3",
"eslint": "^8.49.0",
"eslint-config-airbnb-typescript": "12.0.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-detox": "^1.0.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-jest": "^27.9.0",
"eslint-plugin-jsx-a11y": "6.3.1",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-unused-imports": "^4.1.4",
"husky": "^9.1.7",
"jest": "^29.6.3",
"lint-staged": "^15.2.10",
"prettier": "3.3.3",
"react-test-renderer": "18.3.1",
"ts-jest": "^28.0.4",
"typescript": "5.0.4"
},
"engines": {
"node": ">=18"
}
}

firebase.json:
{
"react-native": {
"crashlytics_debug_enabled": false,
"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": false
}
}

android/build.gradle:
buildscript {
ext {
buildToolsVersion = "35.0.0"
minSdkVersion = 24
compileSdkVersion = 35
targetSdkVersion = 34
ndkVersion = "27.1.12297006"
kotlinVersion = "2.0.21"

    // https://stackoverflow.com/questions/74085319/class-was-expected-declaration-of-com-google-android-gms-location-fusedlocatio
    googlePlayServicesVersion = "21.0.1"
    googlePlayServicesAuthVersion = "20.7.0"

    // https://github.com/react-native-device-info/react-native-device-info/issues/1640#issuecomment-2243533852
    googlePlayServicesIidVersion = "17.0.0"
}
repositories {
    google()
    mavenCentral()
}
dependencies {
    classpath("com.android.tools.build:gradle")
    classpath("com.facebook.react:react-native-gradle-plugin")
    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
    classpath 'com.google.gms:google-services:4.4.2'
    classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.9'
}

}

apply plugin: "com.facebook.react.rootproject"

android/app/build.gradle:

@KAMRONBEK KAMRONBEK changed the title auth().onAuthStateChanged does not always trigger after sign-in on Android auth().onAuthStateChanged does not always trigger after sign-in on Android in React Native 0.77 Feb 26, 2025
@mikehardy
Copy link
Collaborator

Hi there

  • could you use triple-backticks and language markers in the markdown so that's readable? I can't make much sense of the code
  • you are on an old version of react-native-firebase, make certain it reproduces in the current version
  • your posted code is not a minimum + complete example. Please post an App.tsx that is standalone and reproduces the problem

I've been testing this specific feature recently in response to an issue with the event firing after hot reloads and I saw no problem, so for me at least this doesn't reproduce when I inspect it myself - that means the App.tsx with a minimal + complete reproduction is critical to move forward on this issue. Please include exact steps (as if directing a kindergartner...) to reproduce any issue you see

https://github.com/mikehardy/rnfbdemo/blob/90889b436f602f280a733949991fbb5beb648079/App.tsx#L90-L94
https://github.com/mikehardy/rnfbdemo/blob/90889b436f602f280a733949991fbb5beb648079/App.tsx#L242-L255

@mikehardy mikehardy added platform: android Workflow: Waiting for User Response Blocked waiting for user response. plugin: authentication Firebase Authentication resolution: needs-repro This issue could not be reproduced or needs a repro provided. and removed Needs Attention labels Feb 26, 2025
@KAMRONBEK
Copy link
Author

KAMRONBEK commented Feb 27, 2025

@mikehardy Hey bro, As you can see in the video, when I sign in, the app doesn’t automatically reload. That is, if I exit the app and come back, it shows that I’m already signed in. But during the sign-in process itself, this doesn’t happen. This issue occurs after building the APK — it also happens sometimes in the emulator or in debug mode. On iOS, though, it doesn’t happen, I did everything almost, but I have still this problem

recording.mp4

Navigator file
import React, { useContext, useEffect, useRef, useState } from 'react'
import analytics from '@react-native-firebase/analytics'
import Toast from 'react-native-toast-message'
import { OverflowMenuProvider } from 'react-navigation-header-buttons'
import RNBootSplash from 'react-native-bootsplash'
import auth, { FirebaseAuthTypes } from '@react-native-firebase/auth'
import { NavigationContainer } from '@react-navigation/native'
import { AuthContext, UserFoundStates } from '../config/auth_context'
import { getUsersCountById } from '../api/firestore/get-users-by-id'
import PortalHost from '../components/portal/portal-host'
import AuthNavigator from './auth_navigator'
import RootNavigator from './root'
import { navRef } from './root_navigation_ref'
import { handleAppUpdates } from '../utils/app-update-handler'
import { UserContextProvider } from '../config/user_context'

const Navigator = () => {
const [initializing, setInitializing] = useState(true)
const { authUser, setAuthUser, userFound, setUserFound } =
useContext(AuthContext)
const routeNameRef = useRef()

useEffect(() => {
handleAppUpdates()
}, [])

useEffect(() => {
const handleAuthChange = (user: FirebaseAuthTypes.User | null) => {
setUserFound(UserFoundStates.InProgress)
setAuthUser(user ?? undefined)
}

return auth().onAuthStateChanged(handleAuthChange)
// eslint-disable-next-line react-hooks/exhaustive-deps

}, [])

useEffect(() => {
if (authUser) {
getUsersCountById(authUser.uid).then((count) => {
if (initializing) setInitializing(false)
if (count !== 0) {
setUserFound(UserFoundStates.Found)
} else {
setUserFound(UserFoundStates.NotFound)
}
})
} else {
setUserFound(UserFoundStates.NotFound)
if (initializing) setInitializing(false)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [authUser])

if (initializing) {
return null
}

return (

<NavigationContainer
ref={navRef}
onReady={() => {
routeNameRef.current = navRef.current?.getCurrentRoute().name
RNBootSplash.hide({ fade: true })
}}
onStateChange={async () => {
const previousRouteName = routeNameRef.current
const currentRouteName = navRef.current.getCurrentRoute().name

      if (previousRouteName !== currentRouteName) {
        await analytics().logScreenView({
          screen_name: currentRouteName,
          screen_class: currentRouteName,
        })
      }

      // Save the current route name for later comparison
      routeNameRef.current = currentRouteName
    }}>
    <OverflowMenuProvider>
      {userFound === UserFoundStates.Found ? (
        <UserContextProvider userId={authUser?.uid}>
          <RootNavigator />
        </UserContextProvider>
      ) : (
        <AuthNavigator />
      )}
    </OverflowMenuProvider>
    <Toast ref={(ref) => Toast.setRef(ref)} />
  </NavigationContainer>
</PortalHost>

)
}

export default Navigator

application file
import { ActionSheetProvider } from '@expo/react-native-action-sheet'
import analytics from '@react-native-firebase/analytics'
import '@react-native-firebase/storage'
import React from 'react'
import {
ActivityIndicator,
Platform,
StatusBar,
Text,
TextInput,
UIManager,
useColorScheme,
} from 'react-native'
// import codePush from 'react-native-code-push'
// import { Settings } from 'react-native-fbsdk-next'
import Geocoder from 'react-native-geocoding'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import { enableScreens } from 'react-native-screens'
import { AuthContextProvider } from './src/config/auth_context'
import { FIREBASE_API_KEY } from './src/constants'
import Navigator from './src/navigation'

// Ask for consent first if necessary
// Possibly only do this for iOS if no need to handle a GDPR-type flow
// Settings.initializeSDK()

if (FIREBASE_API_KEY) {
Geocoder.init(FIREBASE_API_KEY)
}

if (DEV) {
// TODO: fix this ts error
// @ts-expect-error
import('./src/config/local-firebase')
}

if (DEV) {
const ga = analytics()
ga.setAnalyticsCollectionEnabled(false)
}

const defaultProps = {
maxFontSizeMultiplier: 1,
}

// fix facebook/react-native#30056
if (Platform.OS === 'android') {
// @ts-ignore TS2339: Property 'defaultProps' does not exist on type 'typeof ActivityIndicator'
if (!ActivityIndicator.defaultProps) ActivityIndicator.defaultProps = {}
// @ts-ignore TS2339: Property 'defaultProps' does not exist on type 'typeof ActivityIndicator'
ActivityIndicator.defaultProps.color = 'gray'
}

// @ts-ignore TS2339: Property 'defaultProps' does not exist on type 'typeof Text'
Text.defaultProps = defaultProps

// @ts-ignore TS2339: Property 'defaultProps' does not exist on type 'typeof TextInput'
TextInput.defaultProps = defaultProps
enableScreens()

// firebase.firestore().clearPersistence()
// firebase.firestore().settings({ persistence: false })
// firebase.firestore().disableNetwork()

if (
Platform.OS === 'android' &&
UIManager.setLayoutAnimationEnabledExperimental
) {
UIManager.setLayoutAnimationEnabledExperimental(true)
}

const App = () => {
const isDarkMode = useColorScheme() === 'dark'
return (
<GestureHandlerRootView style={{ flex: 1 }}>



<>
{Platform.select({ android: <StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} /> })}

</>




)
}

// export default codePush({ checkFrequency: codePush.CheckFrequency.MANUAL })(App)
export default App

@mikehardy
Copy link
Collaborator

Not a self contained, minimal reproduction

Post the simplest possible App.tsx that references zero other imports except react, react and react-native-firebase where you can demonstrate the problem

@KAMRONBEK
Copy link
Author

@mikehardy this is App file.
Let me try to explain my issue clearly.

After building the APK and signing in, auth().onAuthStateChanged(onAuthStateChanged) does not trigger for some reason. Because of this, I had to manually log in by getting the currentUser from auth() and proceeding with authentication.

However, after logging in manually, any onSnapshot() listeners I use do not receive data. The real-time updates are not working. But if I close the app and reopen it, everything starts working fine, including onSnapshot().

This is the issue I’m facing, and I’m not sure what needs to be done to fix it. Any help would be appreciated!

import { ActionSheetProvider } from '@expo/react-native-action-sheet'
import analytics from '@react-native-firebase/analytics'
import '@react-native-firebase/storage'
import React from 'react'
import {
ActivityIndicator,
Platform,
StatusBar,
Text,
TextInput,
UIManager,
useColorScheme,
} from 'react-native'
// import codePush from 'react-native-code-push'
// import { Settings } from 'react-native-fbsdk-next'
import Geocoder from 'react-native-geocoding'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import { enableScreens } from 'react-native-screens'
import { AuthContextProvider } from './src/config/auth_context'
import { FIREBASE_API_KEY } from './src/constants'
import Navigator from './src/navigation'

// Ask for consent first if necessary
// Possibly only do this for iOS if no need to handle a GDPR-type flow
// Settings.initializeSDK()

if (FIREBASE_API_KEY) {
Geocoder.init(FIREBASE_API_KEY)
}

if (DEV) {
// TODO: fix this ts error
// @ts-expect-error
import('./src/config/local-firebase')
}

if (DEV) {
const ga = analytics()
ga.setAnalyticsCollectionEnabled(false)
}

const defaultProps = {
maxFontSizeMultiplier: 1,
}

// fix facebook/react-native#30056
if (Platform.OS === 'android') {
// @ts-ignore TS2339: Property 'defaultProps' does not exist on type 'typeof ActivityIndicator'
if (!ActivityIndicator.defaultProps) ActivityIndicator.defaultProps = {}
// @ts-ignore TS2339: Property 'defaultProps' does not exist on type 'typeof ActivityIndicator'
ActivityIndicator.defaultProps.color = 'gray'
}

// @ts-ignore TS2339: Property 'defaultProps' does not exist on type 'typeof Text'
Text.defaultProps = defaultProps

// @ts-ignore TS2339: Property 'defaultProps' does not exist on type 'typeof TextInput'
TextInput.defaultProps = defaultProps
enableScreens()

// firebase.firestore().clearPersistence()
firebase.firestore().settings({ persistence: false })
// firebase.firestore().disableNetwork()

if (
Platform.OS === 'android' &&
UIManager.setLayoutAnimationEnabledExperimental
) {
UIManager.setLayoutAnimationEnabledExperimental(true)
}

const App = () => {
const isDarkMode = useColorScheme() === 'dark'
return (
<GestureHandlerRootView style={{ flex: 1 }}>



<>
{Platform.select({ android: <StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} /> })}

</>




)
}

// export default codePush({ checkFrequency: codePush.CheckFrequency.MANUAL })(App)
export default App

import analytics from '@react-native-firebase/analytics'
import { NavigationContainer } from '@react-navigation/native'
import React, { useContext, useRef } from 'react'
import RNBootSplash from 'react-native-bootsplash'
import Toast from 'react-native-toast-message'
import { OverflowMenuProvider } from 'react-navigation-header-buttons'
import { View, Text, ActivityIndicator } from 'react-native'
import PortalHost from '../components/portal/portal-host'
import { AuthContext, UserFoundStates } from '../config/auth_context'
import { UserContextProvider } from '../config/user_context'
import AuthNavigator from './auth_navigator'
import RootNavigator from './root'
import { navRef } from './root_navigation_ref'
import COLORS from '../config/colors'

const Navigator = () => {
const { authUser, userFound, initializing } = useContext(AuthContext)
const routeNameRef = useRef()

if (initializing) {
return null
}

return (

<NavigationContainer
ref={navRef}
onReady={() => {
routeNameRef.current = navRef.current?.getCurrentRoute()?.name
RNBootSplash.hide({ fade: true })
}}
onStateChange={async () => {
const previousRouteName = routeNameRef.current
const currentRouteName = navRef.current?.getCurrentRoute()?.name

      if (previousRouteName !== currentRouteName) {
        await analytics().logScreenView({
          screen_name: currentRouteName,
          screen_class: currentRouteName,
        })
      }

      // Save the current route name for later comparison
      routeNameRef.current = currentRouteName
    }}>
    <OverflowMenuProvider>
      <>
        {userFound === UserFoundStates.NotFound && <AuthNavigator />}
        {userFound === UserFoundStates.Found && (
          <UserContextProvider userId={authUser?.uid}>
            <RootNavigator />
          </UserContextProvider>
        )}
        {userFound === UserFoundStates.InProgress && (
          <View
            style={{
              flex: 1,
              justifyContent: 'center',
              alignItems: 'center',
              backgroundColor: COLORS.ERROR,
            }}>
            <Text
              style={{
                color: COLORS.BLACK,
                fontSize: 16,
                fontWeight: 'bold',
              }}>
              Loading...
            </Text>
            <ActivityIndicator size="large" color={COLORS.BLACK} />
          </View>
        )}
      </>
    </OverflowMenuProvider>
    <Toast ref={(ref) => Toast.setRef(ref)} />
  </NavigationContainer>
</PortalHost>

)
}

export default Navigator

@mikehardy
Copy link
Collaborator

No, that's not a minimal complete example. Auth provider? Gesture handler? So much stuff. Pleas search "stackoverflow mcve" for a good guide. Reduce it to it's absolute bearest smallest essentials. A button to log in. Two text fields for username password. A handler fir the button to do the login. A callback for the auth changed event. Literally not one other thing. Please try that and if you still reproduce, post that file. Not a gigantic thing with unrelated items please

@KAMRONBEK
Copy link
Author


import React from 'react';
import { View, Text, TextInput, Button, StyleSheet } from 'react-native';
import auth from '@react-native-firebase/auth';
import firestore from '@react-native-firebase/firestore';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { SafeAreaProvider } from 'react-native-safe-area-context';
const App = () => {
  const [email, setEmail] = React.useState('group_creator@etalon.com');
  const [password, setPassword] = React.useState('password123');
  const [user, setUser] = React.useState(null);
  const [groups, setGroups] = React.useState([]);

  React.useEffect(() => {
    const subscriber = auth().onAuthStateChanged((currentUser) => {
      console.log('onAuthStateChanged triggered, user:', currentUser?.uid);
      setUser(currentUser);
      if (currentUser) {
        // Foydalanuvchi mavjud bo‘lganda guruhlarni olish
        fetchGroups(currentUser.uid);
      }
    });
    return subscriber;
  }, []);

  const fetchGroups = (uid) => {
    firestore()
      .collection('groups')
      .where('users', 'array-contains', uid)
      .onSnapshot(
        (snapshot) => {
          console.log('onSnapshot triggered, groups:', snapshot.docs.length);
          const groupList = snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }));
          setGroups(groupList);
        },
        (error) => {
          console.error('Firestore xatosi:', error);
        },
      );
  };

  const onLoginPress = async () => {
    try {
      await auth().signInWithEmailAndPassword(email, password);
      // Agar onAuthStateChanged ishlamasa, qo‘ldan tekshirish
      const currentUser = auth().currentUser;
      if (currentUser) {
        setUser(currentUser);
        fetchGroups(currentUser.uid);
      }
    } catch (error) {
      alert('Login error:' + error.message);
    }
  };

  return (
    <GestureHandlerRootView style={styles.container}>
      <SafeAreaProvider>
        <View style={styles.container}>
          <Text style={styles.title}>Login</Text>
          <TextInput
            style={styles.input}
            placeholder="Email"
            value={email}
            onChangeText={setEmail}
            autoCapitalize="none"
          />
          <TextInput
            style={styles.input}
            placeholder="Password"
            value={password}
            onChangeText={setPassword}
            secureTextEntry
            autoCapitalize="none"
          />
          <Button title="Login" onPress={onLoginPress} />
          {user ? (
            <Text style={styles.userText}>Logged in as: {user.email}</Text>
          ) : null}
          <Text style={styles.groupsTitle}>Your Groups:</Text>
          {groups.map((group) => (
            <Text key={group.id} style={styles.groupText}>
              {group.groupName || 'No name'}
            </Text>
          ))}
        </View>
      </SafeAreaProvider>
    </GestureHandlerRootView>
  );
};

export default App;

@KAMRONBEK
Copy link
Author

@mikehardy I’ve created a minimal example (as requested) using React Native with Firebase. After building and signing into the APK, auth().onAuthStateChanged doesn’t trigger initially, so I manually check auth().currentUser to proceed with login. However, onSnapshot listeners for Firestore (fetching groups) don’t receive data or work in real-time until I close and reopen the app. In debug mode, everything works fine, but in release mode, this issue persists. I’m using React Native 0.77 with new architecture (Fabric) enabled. Any suggestions on fixing this would be greatly appreciated!

@mikehardy
Copy link
Collaborator

@KAMRONBEK thank you for reducing the reproduction to its essentials that helps a great deal, now it is something I can just drop in an app and run

This:

In debug mode, everything works fine, but in release mode, this issue persists

...seems like it might be the critical information. I haven't quite reproduced this yet, but we test in debug mode ... exclusively. So if this is something you only see in release mode it could be something that is very real (and based on your report it seems to be) that we just never see.

I'm working on configuring our android e2e test app for release mode testing and I'm nearly there. I suspect I'll be able to reproduce it as soon as I have it ready, then we can figure out what is going on.

For you - as a temporary test - I imagine in release mode you have minification ("proguard", though it isn't really proguard anymore at a low level) configured? Can you try altering that setting in android/app/build.gradle so that minification / proguard is off in release mode, then re-try?

I have a hunch that will fix things because I have a hunch react-native-firebase may not be handling release mode + minification correctly

@mikehardy mikehardy added Workflow: Needs Review Pending feedback or review from a maintainer. and removed Workflow: Waiting for User Response Blocked waiting for user response. resolution: needs-repro This issue could not be reproduced or needs a repro provided. labels Mar 1, 2025
@KAMRONBEK
Copy link
Author

Hi, @mikehardy thank you for your response and suggestion. I tried disabling minification (minifyEnabled false) in android/app/build.gradle and then tested the app in release mode. However, the issue still persists.

@mikehardy
Copy link
Collaborator

@KAMRONBEK that's really unexpected. As far as I'm aware, there should be very little difference between debug mode and "release but with minification disabled" on android. That is a really really surprising result that debug works and release mode still does not. I won't have time to investigate for a couple days but this does bear investigation

@KAMRONBEK
Copy link
Author

KAMRONBEK commented Mar 4, 2025

@mikehardy I noticed that if I disable the New Architecture, the app works fine in release mode as well. However, I need the New Architecture to be enabled for my use case.
Is there anything specific you’d suggest checking while you’re unavailable? I’d be happy to run additional tests or provide more details if needed. Thanks again for your time!

@mikehardy
Copy link
Collaborator

Hey @KAMRONBEK I'm still pretty focused on why release mode would be failing while debug is working even if you disable minification. That really makes no sense to me and - with respect! - I doubt the test methodology and need to reproduce the result. So that's the first step - either getting our e2e app working in release mode (95% there, but not totally) or using https://github.com/mikehardy/rnfbdemo/blob/main/make-demo.sh (which does build an android release mode app) and dropping in a minimal example to reproduce - but with the script modified just a touch to disable minimification

That second style - using my build demo to make a test release mode android app from scratch with minimal repro - is something you could do as well to build confidence in the testing methodology to see if this really is a minimification thing or not.

After that, if the problem reproduces for me, experiments to run are to add console.log statements in all of the relevant javascript pathways for an event that is not firing, and also System.err.println(); java logging statements in the relevant java native code parts to see why the event isn't firing. That is also something you could do, via direct edits in node_modules with build/test cycles while watching adb logcat

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Attention platform: android plugin: authentication Firebase Authentication type: bug New bug report Workflow: Needs Review Pending feedback or review from a maintainer.
Projects
None yet
Development

No branches or pull requests

2 participants