react-native-live-tracking
v1.0.7
Published
π A lightweight React Native native module + hook for **foreground + background live location tracking**. Supports distance-based updates (iOS) and interval-based updates (Android). Works while app is minimized or killed by system (platform-dependent b
Maintainers
Readme
react-native-live-tracking
π A lightweight React Native native module + hook for foreground + background live location tracking.
Supports distance-based updates (iOS) and interval-based updates (Android). Works while app is minimized or killed by system (platform-dependent behavior).
β¨ Features
- Foreground tracking using
@react-native-community/geolocationwill track in every 3 minutes. - Background tracking (when app minimized) :
- Android: background
Servicelocation track by distance or interval and headless task will trigger - iOS: distance filter + significant-change updates (via
CLLocationManager) every 500m movement.
- Android: background
- Simple hook API (
useLocationTracking) with configurable interval/distance - Works with React Native autolinking (RN >= 0.60)
- Cannot track the user once app is killed by user (swipe up and completely close)
π¦ Installation
Install the JS dependency and your package:
# Install geolocation helper (foreground)
yarn add @react-native-community/geolocation
# Install the module
yarn add react-native-live-tracking
# or with npm
npm install react-native-live-trackingFor iOS
cd ios && pod install && cd ..π Usage
Simple example that shows how to start/stop tracking and read the last location:
import React from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Platform,
Linking,
Alert,
} from 'react-native';
import { useLocationTracking } from 'react-native-live-tracking';
import { ensureOSPermission } from './usePermission';
const App = () => {
const {
tracking,
routeCoordinates,
lastLocation,
error,
startTracking,
stopTracking,
} = useLocationTracking({
backgroundIntervalMs: 10000,
minimumDistanceMeters: 500,
});
const handleStartTracking = async () => {
const granted = await ensureOSPermission(); // check location permission enabled or not
if (granted) {
startTracking();
} else {
Alert.alert(
'Permission Required',
`For background location access, please allow ${
Platform.OS === 'ios' ? 'Always' : '"Allow all the time"'
} permission in settings.`,
[
{ text: 'Cancel', style: 'cancel' },
{ text: 'Open Settings', onPress: Linking.openSettings },
],
);
return false;
}
};
const handleStopTracking = () => {
stopTracking();
};
return (
<View style={styles.container}>
<View style={styles.contentContainer}>
<Text style={styles.heading}>Live User tracking</Text>
<Text style={styles.subHeading}>Track user location in real-time</Text>
<View style={styles.textContainer}>
<Text style={styles.text}>
Last Location: {lastLocation?.latitude}, {lastLocation?.longitude}
</Text>
<Text style={styles.text}>
Status: {tracking ? 'Tracking' : 'Not Tracking'}
</Text>
<Text style={styles.text}>
Route Coordinates: {routeCoordinates.length} points
</Text>
{error && <Text style={styles.error}>{error}</Text>}
</View>
</View>
<View style={styles.buttonContainer}>
{tracking ? (
<TouchableOpacity
style={styles.buttonStop}
onPress={handleStopTracking}
>
<Text style={styles.buttonText}>Stop Tracking</Text>
</TouchableOpacity>
) : (
<TouchableOpacity style={styles.button} onPress={handleStartTracking}>
<Text style={styles.buttonText}>Start Tracking</Text>
</TouchableOpacity>
)}
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
},
contentContainer: {
paddingTop: 150,
alignItems: 'center',
},
buttonContainer: {
marginTop: 100,
},
text: {
marginTop: 20,
},
error: {
color: 'red',
},
textContainer: {
marginTop: 50,
alignItems: 'center',
},
heading: {
fontSize: 24,
marginBottom: 40,
},
subHeading: {
fontSize: 20,
},
button: {
backgroundColor: 'blue',
},
buttonPermission: {
backgroundColor: 'lightcoral',
marginBottom: 10,
},
buttonStop: {
backgroundColor: 'blue',
marginTop: 20,
},
buttonText: {
color: 'white',
padding: 10,
textAlign: 'center',
fontSize: 18,
},
});
export default App;
Hook signature
type UseLocationTrackingOptions = {
backgroundIntervalMs?: number; // Android: interval in ms for interval mode in background mode
minimumDistanceMeters?: number; // distance filter in meters for background mode (Both iOS and Android)
};
declare function useLocationTracking(
opts?: UseLocationTrackingOptions
): {
routeCoordinates: { latitude: number; longitude: number }[];
lastLocation?: { latitude: number; longitude: number; timestamp?: number };
tracking: boolean;
error?: string | null;
startTracking: () => Promise<void> | void;
stopTracking: () => void;
};
βοΈ Options
| Option | Type | Default | Platform | Description | | --------------------- | ------ | ----------- | ------------- | ------------------------------------------------------------------------ | | backgroundIntervalMs | number | 180000 (3m) | Android | forced location push in background mode (ms) | | minimumDistanceMeters | number | 500 | iOS & Android | forced location push when device moved enough in background mode (meter) |
π Setup Notes (Permissions & Config)
Android
- Add required permissions to your app-level
AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />- Register the background service and headless service inside
<application>:
<service
android:name="com.azranazwer.livetracking.TrackBackgroundService"
android:exported="false"
android:foregroundServiceType="location" />
<service
android:name="com.azranazwer.livetracking.TrackHeadlessService"
android:exported="false" />"Runtime Permissions:" On Android 6+ request location permissions at runtime.
On Android 10+ and 11+ explicitly request "Allow all the time" for background access.
iOS
- Add the following keys to Info.plist:
<key>NSLocationWhenInUseUsageDescription</key>
<string>We use your location to track your trip while the app is in use.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We need your location even when the app is backgrounded to continue tracking your trip.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>We need your location always for background tracking.</string>- In Xcode: Target β Capabilities β Background Modes β enable "Location updates".
- If using significant-change API to relaunch the app, implement application(_:didFinishLaunchingWithOptions:) and check .location launch option.
π§ Headless JS (Android)
Create a headlessTasks.js file in root of the project and register your task:
// headlessTasks.js
import { AppRegistry } from "react-native";
AppRegistry.registerHeadlessTask("LocationTrackingTask", () => async (data) => {
console.log("Headless Task data:", data);
// send location to server or handle logic
});Then import it in index.js:
import "./headlessTasks";π§° Troubleshooting
Android:
- Check adb logcat for service logs.
- Ensure your headless service is in AndroidManifest.xml.
- Disable battery optimizations if events stop.
- User must grant Always location permission.
iOS:
- Verify Info.plist keys and Background Modes.
- User must grant Always location permission.
β Contributing
PRs are welcome π
π License
MIT Β© 2025 Azran Azwer
π This version has properly closed code fences (```) around every code example, so GitHub will render headings, tables, and code snippets correctly.
Do you also want me to generate the .gitignore and LICENSE files so your npm package folder is fully ready?
