@gabriel-sisjr/react-native-background-location
Version:
React Native library for background location tracking using TurboModules. Track user location even when the app is minimized or in the background.
185 lines (162 loc) • 5.68 kB
text/typescript
import { useState, useCallback } from 'react';
import { Platform, PermissionsAndroid } from 'react-native';
import { LocationPermissionStatus } from '../types';
import type { UseLocationPermissionsResult, PermissionState } from '../types';
/**
* Hook to manage location permissions for background tracking
*
* Handles requesting and checking location permissions on Android.
* Includes foreground (FINE, COARSE) and background permissions.
*
* @example
* ```tsx
* function App() {
* const { permissionStatus, requestPermissions, isRequesting } = useLocationPermissions();
*
* if (!permissionStatus.hasPermission) {
* return <Button onPress={requestPermissions}>Grant Permissions</Button>;
* }
*
* return <TrackingScreen />;
* }
* ```
*/
export function useLocationPermissions(): UseLocationPermissionsResult {
const [isRequesting, setIsRequesting] = useState(false);
const [permissionStatus, setPermissionStatus] = useState<PermissionState>({
hasPermission: false,
status: LocationPermissionStatus.UNDETERMINED,
canRequestAgain: true,
});
/**
* Check current permission status without requesting
*/
const checkPermissions = useCallback(async (): Promise<boolean> => {
if (Platform.OS !== 'android') {
// iOS to be implemented
setPermissionStatus({
hasPermission: false,
status: LocationPermissionStatus.UNDETERMINED,
canRequestAgain: true,
});
return false;
}
try {
const fineLocation = await PermissionsAndroid.check(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION
);
const coarseLocation = await PermissionsAndroid.check(
PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION
);
// Check background location for Android 10+
let backgroundLocation = true;
if (Platform.Version >= 29) {
backgroundLocation = await PermissionsAndroid.check(
PermissionsAndroid.PERMISSIONS.ACCESS_BACKGROUND_LOCATION
);
}
const allGranted = fineLocation && coarseLocation && backgroundLocation;
setPermissionStatus({
hasPermission: allGranted,
status: allGranted
? LocationPermissionStatus.GRANTED
: LocationPermissionStatus.DENIED,
canRequestAgain: true,
});
return allGranted;
} catch (error) {
console.error('Error checking permissions:', error);
return false;
}
}, []);
/**
* Request all required location permissions
*/
const requestPermissions = useCallback(async (): Promise<boolean> => {
if (Platform.OS !== 'android') {
// iOS to be implemented
console.warn('iOS permissions not yet implemented');
return false;
}
setIsRequesting(true);
try {
// Step 1: Request foreground permissions first
const foregroundPermissions = await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION,
]);
const foregroundGranted =
foregroundPermissions['android.permission.ACCESS_FINE_LOCATION'] ===
PermissionsAndroid.RESULTS.GRANTED &&
foregroundPermissions['android.permission.ACCESS_COARSE_LOCATION'] ===
PermissionsAndroid.RESULTS.GRANTED;
if (!foregroundGranted) {
const canRequestAgain =
foregroundPermissions['android.permission.ACCESS_FINE_LOCATION'] !==
PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN &&
foregroundPermissions['android.permission.ACCESS_COARSE_LOCATION'] !==
PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN;
setPermissionStatus({
hasPermission: false,
status: canRequestAgain
? LocationPermissionStatus.DENIED
: LocationPermissionStatus.BLOCKED,
canRequestAgain,
});
return false;
}
// Step 2: Request background permission for Android 10+
let backgroundGranted = true;
if (Platform.Version >= 29) {
const backgroundResult = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_BACKGROUND_LOCATION,
{
title: 'Background Location Permission',
message:
'This app needs access to your location in the background to track your trips.',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
}
);
backgroundGranted =
backgroundResult === PermissionsAndroid.RESULTS.GRANTED;
if (!backgroundGranted) {
const canRequestAgain =
backgroundResult !== PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN;
setPermissionStatus({
hasPermission: false,
status: canRequestAgain
? LocationPermissionStatus.DENIED
: LocationPermissionStatus.BLOCKED,
canRequestAgain,
});
return false;
}
}
// All permissions granted
setPermissionStatus({
hasPermission: true,
status: LocationPermissionStatus.GRANTED,
canRequestAgain: true,
});
return true;
} catch (error) {
console.error('Error requesting permissions:', error);
setPermissionStatus({
hasPermission: false,
status: LocationPermissionStatus.DENIED,
canRequestAgain: true,
});
return false;
} finally {
setIsRequesting(false);
}
}, []);
return {
permissionStatus,
requestPermissions,
checkPermissions,
isRequesting,
};
}