-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Description
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:
Activity
[-]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[/+]mikehardy commentedon Feb 26, 2025
Hi there
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
KAMRONBEK commentedon 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)
}
}, [])
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
)
}
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 commentedon Feb 28, 2025
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 commentedon Mar 1, 2025
@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
)
}
export default Navigator
mikehardy commentedon Mar 1, 2025
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 commentedon Mar 1, 2025
12 remaining items