React Native Geolocation

A high-performance React Native geolocation library with advanced location tracking capabilities using Google's FusedLocationProviderClient for Android and CoreLocation for iOS. Built following the @amrshbib/react-native-background-tasks convention for consistency and reliability.
✨ Features
- 🚀 Cross-Platform: Full support for both Android and iOS
- 📍 High Accuracy Location: Uses Google's FusedLocationProviderClient on Android
- 🔄 Background Location: Continuous location tracking in background
- 🛡️ Smart Permissions: Automatic permission request dialogs with user guidance
- 🎯 Multiple Providers: GPS, Network, Passive, and Bluetooth-based location
- ⚡ Real-time Watching: Continuous location updates with configurable intervals
- 📝 TypeScript: Complete TypeScript support with type definitions
- 🔗 Auto-linking: Zero configuration setup for React Native 0.60+
- 📱 Easy API: Simple getCurrentLocation/watchLocation methods
- 🔧 Permission Management: Check and request permissions programmatically
📦 Installation
npm install @amrshbib/react-native-geolocation
yarn add @amrshbib/react-native-geolocation
Note: This package is currently in version 0.0.1 and ready for use. The package supports both Android and iOS platforms with comprehensive geolocation capabilities.
React Native 0.60+
This package supports auto-linking. No additional configuration is required.
React Native < 0.60
For older React Native versions, you'll need to manually link the package:
react-native link @amrshbib/react-native-geolocation
🚀 Quick Start
import Geolocation from "@amrshbib/react-native-geolocation";
const getCurrentLocation = async () => {
try {
const location = await Geolocation.getCurrentLocation({
enableHighAccuracy: true,
timeout: 15000,
priority: "high_accuracy",
});
console.log("Location:", location);
} catch (error) {
console.error("Error getting location:", error);
}
};
const watchLocation = async () => {
try {
const watchId = await Geolocation.watchLocation(
(location, error) => {
if (error) {
console.error("Location error:", error);
} else {
console.log("Location update:", location);
}
},
{
enableHighAccuracy: true,
interval: 1000,
priority: "high_accuracy",
}
);
setTimeout(() => {
Geolocation.stopWatching(watchId);
}, 30000);
} catch (error) {
console.error("Error watching location:", error);
}
};
const checkPermissions = async () => {
const permissions = await Geolocation.checkPermissions();
console.log("Fine location:", permissions.fine);
console.log("Background location:", permissions.background);
};
const requestPermissions = async () => {
const permissions = await Geolocation.requestPermissions();
if (permissions.fine) {
console.log("Location permission granted!");
}
};
📖 API Reference
Geolocation.getCurrentLocation(options)
Get the current location once.
Parameters:
options (Object, optional):
enableHighAccuracy (boolean): Use high accuracy mode (default: true)
timeout (number): Timeout in milliseconds (default: 15000)
maximumAge (number): Maximum age of cached location in milliseconds (default: 10000)
priority (string): Location priority - 'high_accuracy', 'balanced_power_accuracy', 'low_power', 'no_power' (default: 'high_accuracy')
interval (number): Update interval in milliseconds (default: 1000)
fastestInterval (number): Fastest update interval in milliseconds (default: 1000)
smallestDisplacement (number): Minimum displacement for updates in meters (default: 0)
Returns: Promise<LocationData> - Resolves with location data
Example:
const location = await Geolocation.getCurrentLocation({
enableHighAccuracy: true,
timeout: 10000,
priority: "high_accuracy",
});
Geolocation.watchLocation(callback, options)
Watch for location changes continuously.
Parameters:
callback (Function): Function called with (location, error)
location: LocationData object or null
error: Error string or null
options (Object, optional): Same as getCurrentLocation
Returns: Promise<number> - Resolves with watchId
Example:
const watchId = await Geolocation.watchLocation(
(location, error) => {
if (error) {
console.error("Location error:", error);
} else {
console.log("New location:", location);
}
},
{
enableHighAccuracy: true,
interval: 2000,
smallestDisplacement: 5,
}
);
Geolocation.stopWatching(watchId)
Stop watching location changes.
Parameters:
watchId (number): The watch ID returned by watchLocation
Returns: Promise<void> - Resolves when watching stops
Example:
await Geolocation.stopWatching(watchId);
Geolocation.checkPermissions()
Check current permission status.
Returns: Promise<{fine: boolean, background: boolean}> - Permission status
Example:
const permissions = await Geolocation.checkPermissions();
console.log("Fine location:", permissions.fine);
console.log("Background location:", permissions.background);
Geolocation.requestPermissions()
Request location permissions from the user.
Returns: Promise<{fine: boolean, background: boolean}> - Permission status after request
Example:
const permissions = await Geolocation.requestPermissions();
if (permissions.fine) {
console.log("Location permission granted!");
}
Geolocation.isLocationEnabled()
Check if location services are enabled on the device.
Returns: Promise<boolean> - True if location services are enabled
Example:
const enabled = await Geolocation.isLocationEnabled();
if (!enabled) {
Alert.alert("Location Services", "Please enable location services in settings");
}
🔧 Platform-Specific Setup
Android Setup
The package automatically handles Android configuration, but you need to add location permissions to your android/app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<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.BLUETOOTH_SCAN" />
</manifest>
iOS Setup
For iOS, you need to add location usage descriptions to your ios/YourApp/Info.plist:
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location when open.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs access to location when open and in the background.</string>
Optional: For background location tracking, add background modes:
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
🎯 Use Cases
- Location Tracking: Track user location for fitness apps
- Navigation: Real-time navigation and routing
- Geofencing: Location-based notifications and actions
- Asset Tracking: Track vehicles, equipment, or packages
- Social Features: Location-based social networking
- Emergency Services: Emergency location sharing
- Delivery Apps: Real-time delivery tracking
- Weather Apps: Location-based weather information
📱 Example Implementation
import React, { useEffect, useState } from "react";
import { View, Text, TouchableOpacity, Alert } from "react-native";
import Geolocation from "@amrshbib/react-native-geolocation";
const App = () => {
const [location, setLocation] = useState(null);
const [permissions, setPermissions] = useState({ fine: false, background: false });
const [watchId, setWatchId] = useState(null);
const [isWatching, setIsWatching] = useState(false);
useEffect(() => {
checkPermissions();
return () => {
if (watchId) {
Geolocation.stopWatching(watchId);
}
};
}, []);
const checkPermissions = async () => {
try {
const perms = await Geolocation.checkPermissions();
setPermissions(perms);
} catch (error) {
console.error("Error checking permissions:", error);
}
};
const requestPermissions = async () => {
try {
const perms = await Geolocation.requestPermissions();
setPermissions(perms);
if (perms.fine) {
Alert.alert("Success", "Location permissions granted!");
} else {
Alert.alert("Permission Required", "Please grant location permission to use this feature.");
}
} catch (error) {
Alert.alert("Error", "Failed to request permissions");
}
};
const getCurrentLocation = async () => {
try {
if (!permissions.fine) {
Alert.alert("Permission Required", "Please grant location permission first.");
return;
}
const loc = await Geolocation.getCurrentLocation({
enableHighAccuracy: true,
timeout: 15000,
priority: "high_accuracy",
});
setLocation(loc);
Alert.alert("Success", `Location: ${loc.latitude}, ${loc.longitude}`);
} catch (error) {
if (error.message && error.message.includes("permissions not granted")) {
Alert.alert("Permission Required", "Location permission is required.");
} else {
Alert.alert("Error", error.message || "Failed to get location");
}
}
};
const startWatching = async () => {
try {
if (!permissions.fine) {
Alert.alert("Permission Required", "Please grant location permission first.");
return;
}
const id = await Geolocation.watchLocation(
(loc, error) => {
if (error) {
console.error("Location watch error:", error);
Alert.alert("Location Error", error);
} else {
setLocation(loc);
}
},
{
enableHighAccuracy: true,
interval: 1000,
priority: "high_accuracy",
}
);
setWatchId(id);
setIsWatching(true);
} catch (error) {
Alert.alert("Error", error.message || "Failed to start location watching");
}
};
const stopWatching = () => {
if (watchId) {
Geolocation.stopWatching(watchId);
setWatchId(null);
setIsWatching(false);
}
};
return (
<View style={{ flex: 1, padding: 20 }}>
<Text style={{ fontSize: 24, marginBottom: 20 }}>Geolocation Demo</Text>
<View style={{ marginBottom: 20 }}>
<Text>Fine Location: {permissions.fine ? "✅ Granted" : "❌ Denied"}</Text>
<Text>Background Location: {permissions.background ? "✅ Granted" : "❌ Denied"}</Text>
</View>
{!permissions.fine && (
<TouchableOpacity
onPress={requestPermissions}
style={{
backgroundColor: "#007AFF",
padding: 15,
borderRadius: 8,
marginBottom: 20,
}}
>
<Text style={{ color: "white", textAlign: "center", fontSize: 18 }}>Request Permissions</Text>
</TouchableOpacity>
)}
<TouchableOpacity
onPress={getCurrentLocation}
style={{
backgroundColor: "#34C759",
padding: 15,
borderRadius: 8,
marginBottom: 10,
}}
>
<Text style={{ color: "white", textAlign: "center", fontSize: 18 }}>Get Current Location</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={isWatching ? stopWatching : startWatching}
style={{
backgroundColor: isWatching ? "#FF3B30" : "#FF9500",
padding: 15,
borderRadius: 8,
marginBottom: 20,
}}
>
<Text style={{ color: "white", textAlign: "center", fontSize: 18 }}>{isWatching ? "Stop Watching" : "Start Watching"}</Text>
</TouchableOpacity>
{location && (
<View style={{ backgroundColor: "#f0f0f0", padding: 15, borderRadius: 8 }}>
<Text style={{ fontSize: 18, marginBottom: 10 }}>Current Location:</Text>
<Text>Latitude: {location.latitude}</Text>
<Text>Longitude: {location.longitude}</Text>
<Text>Accuracy: {location.accuracy}m</Text>
<Text>Speed: {location.speed} m/s</Text>
<Text>Heading: {location.heading}°</Text>
<Text>Provider: {location.provider}</Text>
</View>
)}
</View>
);
};
export default App;
⚠️ Important Notes
Android
- Uses Google's FusedLocationProviderClient for optimal battery usage
- Background location requires additional permission on Android 10+
- Location accuracy depends on GPS signal strength and device capabilities
iOS
- Uses CoreLocation framework for location services
- Background location is limited by iOS system policies
- Location services must be enabled by the user
🔧 Troubleshooting
Permission Denied Error
- Check if location permissions are granted
- Request permissions using
Geolocation.requestPermissions()
- Guide user to app settings if permissions are denied
Location Services Disabled
- Check if location services are enabled using
Geolocation.isLocationEnabled()
- Guide user to enable location services in device settings
No Location Updates
- Ensure permissions are granted
- Check if location services are enabled
- Verify GPS signal strength
- Try different priority levels
High Battery Usage
- Use
balanced_power_accuracy or low_power priority
- Increase
interval and fastestInterval values
- Use
smallestDisplacement to reduce unnecessary updates
📋 Requirements
- React Native 0.60+
- Android API 21+ (Android 5.0+)
- iOS 10.0+
- Kotlin support (Android)
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
The MIT License
Copyright (c) 2024 Amr Shbib amr.shbib@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
🔗 Links
Made with ❤️ for the React Native community