When the user grants the permission, the AppState changes
ovsiannykov opened this issue · comments
Platforms
- iOS
- Android
Versions
Please add the used versions/branches
- Android:
- iOS:
- react-native-geolocation-service:
- react-native:
- react:
Description
When the user grants permission to use geolocation he AppState changes. Everything would be fine, but I have a hook that monitors the exit of the application from sleep, and makes a request to update the token, user, and so on. Because of this, the reload effect is obtained and the user is thrown to the main screen
Code
My useLocation Hook:
import { useContext, useEffect, useState } from 'react';
import Geolocation, { GeoCoordinates } from 'react-native-geolocation-service';
import { localesContext } from '../../../shared/locale/locale.provider';
import { errorContext } from './../../../core/error/error.provider';
import { locationPermission } from '../../helpers/location-permissions';
const useLocation = (): Geolocation.GeoCoordinates | null => {
const [location, setLocation] = useState<GeoCoordinates | null>(null);
const { i18n } = useContext(localesContext);
const { bug } = useContext(errorContext);
const getLocation = async (): Promise<void> => {
const hasPermission = await locationPermission(i18n, bug);
if (!hasPermission) {
return;
}
Geolocation.getCurrentPosition(
position => {
setLocation(position.coords);
},
error => {
bug(t(i18n)`Code ` + error.code + t(i18n)`, please try again`);
setLocation(null);
},
{
accuracy: {
android: 'high',
ios: 'best',
},
enableHighAccuracy: true,
timeout: 15000,
maximumAge: 10000,
distanceFilter: 0,
forceRequestLocation: true,
forceLocationManager: false,
showLocationDialog: true,
},
);
};
useEffect(() => {
getLocation();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return location;
};
export default useLocation;
My location permissions helper:
import { t } from '@lingui/macro';
import { Alert, Linking, PermissionsAndroid, Platform } from 'react-native';
import Geolocation from 'react-native-geolocation-service';
import { IS_ANDROID, IS_IOS } from '../constants/theme';
export const locationPermission = async (i18n: I18n, bug: (rawError: unknown) => void) => {
const hasPermissionIOS = async () => {
const openSetting = () => {
Linking.openSettings().catch(() => {
bug(t(i18n)`Unable to open settings, please try again`);
});
};
try {
const status = await Geolocation.requestAuthorization('whenInUse');
if (status === 'granted') {
return true;
}
if (status === 'denied') {
bug(t(i18n)`Location permission denied, please try again`);
}
if (status === 'disabled') {
Alert.alert(
t(i18n)`Allow “Workfly” To Access your Location?`,
'Workfly helps you to check you current location',
[{ text: t(i18n)`Go to Settings`, onPress: openSetting }],
);
}
return false;
} catch (error) {
bug(error);
return false;
}
};
if (IS_IOS) {
const hasPermission = await hasPermissionIOS();
return hasPermission;
}
if (IS_ANDROID && Platform.Version < 23) {
return true;
}
const hasPermission = await PermissionsAndroid.check(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
);
if (hasPermission) {
return true;
}
const status = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
);
if (status === PermissionsAndroid.RESULTS.GRANTED) {
return true;
}
if (status === PermissionsAndroid.RESULTS.DENIED) {
bug(t(i18n)`Opps... Location permission denied, please enable permissions`);
} else if (status === PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN) {
bug(t(i18n)`Ooops... Location permission revoked, please enable permissions`);
}
return false;
};
My useWakeUp Hook:
import { AppState } from 'react-native';
const useWakeUp = (myFunc: () => ReactNode | Promise<void> | void) => {
useEffect(() => {
const subscription = AppState.addEventListener('change', nextAppState => {
if (nextAppState === 'active') {
myFunc();
}
});
return () => subscription.remove();
}, [myFunc]);
};
export default useWakeUp;
My App.tsx
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { en, he } from 'make-plural/plurals';
import React, { useCallback, useContext, useEffect, useState } from 'react';
import { Linking, LogBox, StatusBar } from 'react-native';
import RNBootSplash from 'react-native-bootsplash';
import 'react-native-gesture-handler';
import AppProvider, { appContext } from '../core/app/app.provider';
import { ErrorProvider, errorContext } from '../core/error/error.provider';
import { SessionProvider } from '../core/session/session.provider';
import CompanyProvider from '../shared/entities/company/company.provider';
import EntryProvider from '../shared/entities/entry/entry.provider';
import UserProvider from '../shared/entities/user/user.provider';
import { LocalesProvider } from '../shared/locale/locale.provider';
import { messages as transEn } from '../locales/en/messages';
import { messages as transHe } from '../locales/he/messages';
import FolderProvider from '../shared/entities/folder/folder-provider';
import TaskProvider from '../shared/entities/task/task-provider';
import DepartmentsProvider from '../shared/selects/departments/departments-provider';
import FoldersProvider from '../shared/selects/folders/folders-provider';
import UsersProvider from '../shared/selects/users/users-provider';
import LoadingIndicator from './components/loading-indicator/loading-indicator';
import Toaster from './components/toaster/toaster';
import { COLORS } from './constants/theme';
import { LINKING_CONFIG } from './helpers/linking-config';
import AuthNavigation from './navigation/auth-navigation/auth-navigation';
import RootNavigator from './navigation/root-navigator/root-navigator';
import LoadingScreen from './screens/other/loading-screen/loading-screen';
import useWakeUp from './hooks/use-wake-up/use-wake-up';
const translationsMessages = { en: transEn, he: transHe };
// ignore yellow warning debug messages
LogBox.ignoreAllLogs();
function App() {
const [loading, setLoading] = useState(false);
const { setStore, store } = useContext(appContext);
const { bug } = useContext(errorContext);
const navigation = useNavigation();
useEffect(() => {
const init = async () => {
// …do multiple sync or async tasks
};
init().finally(async () => {
await RNBootSplash.hide({ fade: true });
});
}, []);
const getSession = useCallback(async () => {
setLoading(true);
try {
const storageToken = await SessionProvider.getSessionCookie();
if (storageToken) {
const [session] = await SessionProvider.getSession(storageToken);
setStore('user', session.user);
}
} catch (e) {
console.log(`APP getSession error: ${e}`);
bug(e);
} finally {
setLoading(false);
}
}, [bug, setStore]);
useWakeUp(getSession);
const linkingListener = useCallback(async () => {
try {
const url = await Linking.getInitialURL();
if (url) {
console.log(url);
if (!store.user) {
//@ts-ignore
navigation.navigate('ViaLink');
}
}
} catch (error) {
console.log(`Link Problem: ${error}`);
bug(error);
}
}, [bug, navigation, store.user]);
useEffect(() => {
getSession();
}, [getSession]);
useEffect(() => {
linkingListener();
}, [linkingListener]);
if (loading) {
return <LoadingScreen color={COLORS.primary} />;
}
return (
<>
<CompanyProvider>
<EntryProvider>
<FolderProvider>
<FoldersProvider>
<TaskProvider>
<DepartmentsProvider>
<UsersProvider>
<UserProvider>
{store.user ? <RootNavigator /> : <AuthNavigation />}
</UserProvider>
</UsersProvider>
</DepartmentsProvider>
</TaskProvider>
</FoldersProvider>
</FolderProvider>
</EntryProvider>
</CompanyProvider>
<Toaster />
</>
);
}
function Index() {
const i18n = setupI18n({
messages: translationsMessages,
locale: 'en',
localeData: {
en: { plurals: en },
he: { plurals: he },
},
});
return (
<>
<StatusBar barStyle="dark-content" />
<LocalesProvider i18n={i18n}>
<AppProvider store={{}} techStore={{ session: null }}>
<ErrorProvider error={null}>
<NavigationContainer
// @ts-ignore
linking={LINKING_CONFIG}
fallback={<LoadingIndicator color={COLORS.primary} size="large" />}
>
<App />
</NavigationContainer>
</ErrorProvider>
</AppProvider>
</LocalesProvider>
</>
);
}
export default Index;
Geolocation.requestAuthorization is IOS ONLY !