smart_location 0.0.4
smart_location: ^0.0.4 copied to clipboard
Smart Location is a Flutter location plugin for GPS tracking, real-time location updates, geofencing, distance calculation.
Smart Location #
A developer-friendly, DX-first Flutter package for handling location. It internally wraps geolocator with a clean, top-down designed API that minimizes boilerplate and intuitively manages permissions.
Features #
- One-line Location Fetching: Get the current location safely.
- Continuous Tracking: Listen to location stream with simple configurations.
- Smart Permission Handling: Checks GPS and prompts permissions automatically.
- Pure Dart Models: Safe mapping from raw platform data to clean Dart classes.
Getting Started #
Add the dependency to your pubspec.yaml:
dependencies:
smart_location: ^0.0.4
Platform Setup #
Android #
In android/app/src/main/AndroidManifest.xml, add inside <manifest>:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
Background Location (optional):
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
iOS #
In ios/Runner/Info.plist, add:
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location access to provide better services.</string>
Background Location (optional):
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs location access for background tracking.</string>
API Overview #
| API | Purpose |
|---|---|
SmartLocation.ensureReady() |
Request permission + verify GPS is on |
SmartLocation.current() |
One-time location fetch |
SmartLocation.lastKnown() |
Last cached location (no GPS needed) |
SmartLocation.stream |
Continuous live updates |
SmartLocation.streamWithSettings(...) |
Live updates with custom accuracy/filter |
SmartLocation.distanceBetween(...) |
Distance in meters between two points |
SmartLocation.bearingBetween(...) |
Direction/heading between two points |
Usage #
1. Initialize & Ensure Permissions #
import 'package:smart_location/smart_location.dart';
// Checks GPS status and requests location permission from the user
await SmartLocation.ensureReady();
2. Get Current Location #
try {
final loc = await SmartLocation.current();
print('Location: ${loc.latitude}, ${loc.longitude}');
} on LocationDisabledException {
print('Please turn on GPS');
} on PermissionDeniedException {
print('Permission was denied');
}
3. Listen to Location Stream #
SmartLocation.stream.listen((loc) {
print('Moving to: ${loc.latitude}, ${loc.longitude}');
});
4. Distance Calculation #
double distance = SmartLocation.distanceBetween(
52.2165157, 21.0369204, // Point A
52.2296756, 21.0122287, // Point B
);
Usage Scenarios #
1️⃣ One-Time Location #
Use case: Delivery address, profile setup
await SmartLocation.ensureReady();
final loc = await SmartLocation.current();
print('Lat: ${loc.latitude}, Lng: ${loc.longitude}');
// For faster response with less accuracy:
final loc = await SmartLocation.current(accuracy: LocationAccuracy.low);
2️⃣ Live Tracking #
Use case: Ride-sharing, food delivery apps
await SmartLocation.ensureReady();
final subscription = SmartLocation.stream.listen((loc) {
mapController.moveCamera(loc.latitude, loc.longitude);
});
// Stop tracking when done
subscription.cancel();
3️⃣ Geofencing / Proximity Alert #
Use case: "You are near a store"
const double shopLat = 37.7749;
const double shopLng = -122.4194;
SmartLocation.stream.listen((loc) {
final distance = SmartLocation.distanceBetween(
loc.latitude, loc.longitude,
shopLat, shopLng,
);
if (distance < 200) { // within 200 metres
showNotification('You are near the store!');
}
});
4️⃣ Distance-Based Tracking #
Use case: Fitness / running apps (battery efficient)
final stream = SmartLocation.streamWithSettings(
accuracy: LocationAccuracy.bestForNavigation,
distanceFilter: 10, // only emit every 10 metres
);
stream.listen((loc) {
totalDistance += SmartLocation.distanceBetween(
prevLat, prevLng,
loc.latitude, loc.longitude,
);
prevLat = loc.latitude;
prevLng = loc.longitude;
});
5️⃣ Fast Startup with Cached Location #
Use case: Show map instantly on open
final cached = await SmartLocation.lastKnown();
if (cached != null) showOnMap(cached);
// Then load a fresh location in the background
await SmartLocation.ensureReady();
final fresh = await SmartLocation.current();
showOnMap(fresh);
6️⃣ Heading / Navigation #
Use case: Compass, turn-by-turn navigation
final bearing = SmartLocation.bearingBetween(
userLat, userLng,
destinationLat, destinationLng,
);
// Rotate UI based on direction (0–360° from North)
compassWidget.rotateTo(bearing);
7️⃣ Permission Check Only #
Use case: Enable/disable location-based features
final hasPermission = await SmartLocation.hasPermission();
final isGpsOn = await SmartLocation.isEnabled();
if (!hasPermission || !isGpsOn) {
showLocationUnavailableBanner();
}
Error Handling #
Always wrap calls in a try-catch:
try {
await SmartLocation.ensureReady();
final loc = await SmartLocation.current();
} on LocationDisabledException {
// GPS is OFF → prompt user to enable
} on PermissionDeniedException {
// Permission denied (can ask again)
} on PermissionPermanentlyDeniedException {
// Denied forever → open app settings
} catch (e) {
// Unknown error
}
Exception types exported by this package:
LocationDisabledExceptionPermissionDeniedExceptionPermissionPermanentlyDeniedException
Best Practices #
- Always call
ensureReady()before accessing location data - Use
distanceFilterinstreamWithSettingsto save battery - Use
lastKnown()to populate the UI instantly on startup - Always handle all three permission exception types
- Cancel stream subscriptions when they are no longer needed