Real-time location tracking is a popular feature in many mobile applications, from navigation and ride-sharing to delivery services and social networking. Combining Flutter, a cross-platform UI toolkit, with Mapbox, a powerful mapping platform, allows developers to create sophisticated real-time location tracking apps with ease.
What is Real-Time Location Tracking?
Real-time location tracking involves continuously monitoring the geographic location of a device and displaying it on a map in real-time. This feature relies on GPS or other location services to provide accurate and up-to-date positional information.
Why Use Flutter and Mapbox?
- Flutter: Enables cross-platform development with a single codebase, ensuring faster development and consistent UI/UX across Android and iOS.
- Mapbox: Offers highly customizable maps, real-time data visualization, and geocoding services, making it perfect for location-based applications.
Setting Up Your Development Environment
Before you start building your real-time location tracking app, ensure you have Flutter and the necessary plugins configured.
Step 1: Install Flutter
Follow the official Flutter documentation to install Flutter on your development machine. You can find the instructions here: Flutter Installation Guide
Step 2: Create a New Flutter Project
Open your terminal and run the following command to create a new Flutter project:
flutter create real_time_location_app
cd real_time_location_app
Step 3: Add Required Dependencies
Add the following dependencies to your pubspec.yaml
file:
dependencies:
flutter:
sdk: flutter
mapbox_gl: ^0.16.0 # Or the latest version
geolocator: ^10.1.2 # Or the latest version
permission_handler: ^11.1.0 # Or the latest version
http: ^1.1.0 # Or the latest version
dev_dependencies:
flutter_test:
sdk: flutter
Then, run flutter pub get
to install the dependencies.
Integrating Mapbox with Flutter
Step 1: Set Up Your Mapbox Account
If you don’t have one already, create a Mapbox account at Mapbox. Once you have an account, obtain your Access Token from your Mapbox dashboard. You will need this token to use Mapbox services in your Flutter app.
Step 2: Configure the Mapbox Plugin
In your android/app/src/main/AndroidManifest.xml
, add the following meta-data tag inside the <application>
tag. Replace YOUR_MAPBOX_ACCESS_TOKEN
with your actual Mapbox Access Token.
<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"
package=\"com.example.real_time_location_app\">
<application
android:name=\"${applicationName}\"
android:icon=\"@mipmap/ic_launcher\"
android:label=\"real_time_location_app\">
<meta-data
android:name=\"com.mapbox.token\"
android:value=\"YOUR_MAPBOX_ACCESS_TOKEN\" />
<activity
android:name=\".MainActivity\"
android:configChanges=\"orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode\"
android:exported=\"true\"
android:hardwareAccelerated=\"true\"
android:launchMode=\"singleTop\"
android:theme=\"@style/LaunchTheme\"
android:windowSoftInputMode=\"adjustResize\">
<meta-data
android:name=\"io.flutter.embedding.android.NormalTheme\"
android:resource=\"@style/NormalTheme\" />
<intent-filter>
<action android:name=\"android.intent.action.MAIN\" />
<category android:name=\"android.intent.category.LAUNCHER\" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name=\"flutterEmbedding\"
android:value=\"2\" />
</application>
</manifest>
For iOS, add the following to your ios/Runner/Info.plist
:
<key>io.flutter.embedded_views_preview</key>
<string>YES</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to your location when open.</string>
Step 3: Request Location Permissions
Before accessing the device’s location, request the necessary permissions using the permission_handler
plugin. Create a function to handle permission requests:
import 'package:permission_handler/permission_handler.dart';
Future<void> requestLocationPermission() async {
final status = await Permission.location.request();
if (status.isGranted) {
print('Location permission granted');
} else if (status.isDenied) {
print('Location permission denied');
} else if (status.isPermanentlyDenied) {
print('Location permission permanently denied');
openAppSettings(); // Opens app settings for manual permission grant
}
}
Building the Real-Time Location Tracking Feature
Step 1: Initialize the Map
Create a stateful widget to hold the map and location-related data.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:mapbox_gl/mapbox_gl.dart';
class MapScreen extends StatefulWidget {
@override
_MapScreenState createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
MapboxMapController? mapController;
LatLng currentLocation = LatLng(0.0, 0.0); // Default location
StreamSubscription<Position>? positionStream;
@override
void initState() {
super.initState();
requestLocationPermission(); // Request location permission on initialization
_getCurrentLocation(); // Get initial location
_startLocationTracking(); // Start real-time location tracking
}
@override
void dispose() {
positionStream?.cancel(); // Cancel the stream when the widget is disposed
mapController?.dispose();
super.dispose();
}
void _onMapCreated(MapboxMapController controller) {
mapController = controller;
}
Future<void> _getCurrentLocation() async {
try {
Position position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high);
setState(() {
currentLocation = LatLng(position.latitude, position.longitude);
});
_updateCameraPosition(currentLocation); // Update the camera position
} catch (e) {
print('Error getting current location: $e');
}
}
void _updateCameraPosition(LatLng location) {
mapController?.animateCamera(
CameraUpdate.newLatLng(location),
);
}
void _startLocationTracking() {
const LocationSettings locationSettings = LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 10, // Update location every 10 meters
);
positionStream = Geolocator.getPositionStream(locationSettings: locationSettings).listen(
(Position? position) {
if (position != null) {
setState(() {
currentLocation = LatLng(position.latitude, position.longitude);
});
_updateCameraPosition(currentLocation); // Update the camera position
_updateUserLocationSymbol(currentLocation); // Update the symbol on the map
}
});
}
Future<void> _updateUserLocationSymbol(LatLng location) async {
final point = location;
// Check if symbol already exists, if so update, otherwise add
if (mapController!.getSymbol("userLocation") != null){
mapController!.updateSymbol(
"userLocation",
SymbolOptions(
geometry: point,
iconImage: "assetImage", // Replace with your asset icon name or other icon options
iconSize: 1.0,
)
);
}else{
mapController!.addSymbol(
SymbolOptions(
geometry: point,
iconImage: "assetImage", // Replace with your asset icon name or other icon options
iconSize: 1.0,
symbolId: "userLocation"
),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Real-Time Location Tracking'),
),
body: MapboxMap(
accessToken: 'YOUR_MAPBOX_ACCESS_TOKEN', // Replace with your Mapbox access token
onMapCreated: _onMapCreated,
initialCameraPosition: CameraPosition(
target: currentLocation,
zoom: 14.0,
),
),
);
}
}
Replace 'YOUR_MAPBOX_ACCESS_TOKEN'
with your actual Mapbox access token.
Step 2: Fetch Current Location
Use the geolocator
plugin to get the device’s current location.
Step 3: Real-Time Location Updates
Implement a stream using Geolocator.getPositionStream
to continuously monitor the device’s location. Update the map’s camera position and add a symbol to represent the user’s location.
Step 4: Add UI Enhancements
Customize the map appearance by adding markers, polylines, or other UI elements. Use Mapbox Studio to design custom map styles that match your app’s branding.
Advanced Features
Consider adding advanced features to enhance your location tracking app:
- Geofencing: Define virtual boundaries and trigger events when a device enters or exits a geofence.
- Directions API: Calculate routes and provide turn-by-turn navigation instructions.
- Clustering: Aggregate nearby markers to improve map readability when displaying many locations.
- Offline Maps: Allow users to download map regions for offline use.
Troubleshooting and Common Issues
- Permission Issues: Always ensure that you handle location permissions gracefully. Handle cases where permissions are denied and guide the user on how to enable them in settings.
- Accuracy Problems: Location accuracy can vary significantly based on GPS signal strength and device hardware. Use LocationAccuracy.high when initializing the location stream for best results.
- Battery Consumption: Real-time location tracking can drain the battery quickly. Implement strategies to optimize battery usage, such as reducing the frequency of location updates or using geofencing instead of continuous tracking where appropriate.
Conclusion
By leveraging the power of Flutter and Mapbox, you can create feature-rich real-time location tracking applications that offer a seamless and engaging user experience. The ability to build cross-platform apps quickly and easily, combined with Mapbox’s customizable mapping capabilities, makes this combination a great choice for developers. Following the guide above allows creation of sophisticated, location-aware mobile apps.