Flutter Polyline Points
A Flutter package for decoding polyline points from Google Maps Directions API and the new Google Routes API. This package provides a unified interface supporting both legacy Directions API and the enhanced Google Routes API.
๐ Version 3.0 - Simplified Routes API Integration
Version 3.0 introduces a simplified and unified approach to Google's routing services:
- Single
PolylinePoints
class for both APIs - Simplified Routes API integration with essential features
- Enhanced request/response models with better type safety
- Custom body parameters for advanced use cases
- Comprehensive test coverage for reliability
- Backward compatibility maintained for existing code
๐ฆ Installation
Add this to your package's pubspec.yaml
file:
dependencies:
flutter_polyline_points: ^3.0.0
Then run:
flutter pub get
๐ API Key Setup
- Go to the Google Cloud Console
- Enable the Directions API and/or Routes API
- Create an API key
- Configure API key restrictions as needed
Note: The Routes API may have different pricing than the Directions API. Check the Google Routes API documentation for details.
๐ฑ Basic Usage
Legacy Directions API (Backward Compatibility)
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
// Initialize PolylinePoints
PolylinePoints polylinePoints = PolylinePoints(apiKey: "YOUR_API_KEY");
// Get route using legacy Directions API
PolylineResult result = await polylinePoints.getRouteBetweenCoordinates(
request: PolylineRequest(
origin: PointLatLng(37.7749, -122.4194), // San Francisco
destination: PointLatLng(37.3382, -121.8863), // San Jose
mode: TravelMode.driving,
),
);
if (result.points.isNotEmpty) {
// Convert to LatLng for Google Maps
List<LatLng> polylineCoordinates = result.points
.map((point) => LatLng(point.latitude, point.longitude))
.toList();
}
Routes API (Enhanced Features)
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
// Initialize PolylinePoints
PolylinePoints polylinePoints = PolylinePoints(apiKey: "YOUR_API_KEY");
// Create Routes API request
RoutesApiRequest request = RoutesApiRequest(
origin: PointLatLng(37.7749, -122.4194),
destination: PointLatLng(37.3382, -121.8863),
travelMode: TravelMode.driving,
routingPreference: RoutingPreference.trafficAware,
);
// Get route using Routes API
RoutesApiResponse response = await polylinePoints.getRouteBetweenCoordinatesV2(
request: request,
);
if (response.routes.isNotEmpty) {
Route route = response.routes.first;
// Access route information
print('Duration: ${route.durationMinutes} minutes');
print('Distance: ${route.distanceKm} km');
// Get polyline points
List<PointLatLng> points = route.polylinePoints ?? [];
}
๐๏ธ Two-Wheeler Routing
// Get optimized route for motorcycles/scooters
RoutesApiRequest request = RoutesApiRequest(
origin: PointLatLng(37.7749, -122.4194),
destination: PointLatLng(37.3382, -121.8863),
travelMode: TravelMode.twoWheeler,
routeModifiers: RouteModifiers(
avoidHighways: true,
avoidTolls: false,
),
);
RoutesApiResponse response = await polylinePoints.getRouteBetweenCoordinatesV2(
request: request,
);
๐ฃ๏ธ Alternative Routes
// Get multiple route options
RoutesApiRequest request = RoutesApiRequest(
origin: PointLatLng(37.7749, -122.4194),
destination: PointLatLng(37.3382, -121.8863),
computeAlternativeRoutes: true,
intermediates: [
PolylineWayPoint(location: "37.4419,-122.1430"), // Palo Alto coordinates
],
);
RoutesApiResponse response = await polylinePoints.getRouteBetweenCoordinatesV2(
request: request,
);
// Access all alternative routes
for (int i = 0; i < response.routes.length; i++) {
Route route = response.routes[i];
print('Route ${i + 1}: ${route.durationMinutes} min, ${route.distanceKm} km');
}
โ๏ธ Advanced Configuration
Route Modifiers
RoutesApiRequest request = RoutesApiRequest(
origin: PointLatLng(37.7749, -122.4194),
destination: PointLatLng(37.3382, -121.8863),
travelMode: TravelMode.driving,
routeModifiers: RouteModifiers(
avoidTolls: true,
avoidHighways: false,
avoidFerries: true,
avoidIndoor: false,
),
routingPreference: RoutingPreference.trafficAware,
units: Units.metric,
polylineQuality: PolylineQuality.highQuality,
);
RoutesApiResponse response = await polylinePoints.getRouteBetweenCoordinatesV2(
request: request,
);
Custom Body Parameters
// Add custom parameters not covered by the standard API
RoutesApiRequest request = RoutesApiRequest(
origin: PointLatLng(37.7749, -122.4194),
destination: PointLatLng(37.3382, -121.8863),
customBodyParameters: {
'extraComputations': ['TRAFFIC_ON_POLYLINE'],
'requestedReferenceTime': DateTime.now().toIso8601String(),
},
);
Timing Preferences
RoutesApiRequest request = RoutesApiRequest(
origin: PointLatLng(37.7749, -122.4194),
destination: PointLatLng(37.3382, -121.8863),
travelMode: TravelMode.driving,
routingPreference: RoutingPreference.trafficAware,
departureTime: DateTime.now().add(Duration(hours: 1)),
// OR
// arrivalTime: DateTime.now().add(Duration(hours: 2)),
);
๐ Migration Guide
From v2.x to v3.0
Version 3.0 simplifies the API while maintaining backward compatibility:
// OLD (v2.x)
PolylinePoints polylinePoints = PolylinePoints();
PolylineResult result = await polylinePoints.getRouteBetweenCoordinates(
googleApiKey: "YOUR_API_KEY",
request: request,
);
// NEW (v3.0)
PolylinePoints polylinePoints = PolylinePoints(apiKey: "YOUR_API_KEY");
PolylineResult result = await polylinePoints.getRouteBetweenCoordinates(
request: request,
);
Converting Between APIs
// Convert Routes API response to legacy format
RoutesApiResponse routesResponse = await polylinePoints.getRouteBetweenCoordinatesV2(
request: routesRequest,
);
PolylineResult legacyResult = polylinePoints.convertToLegacyResult(routesResponse);
Factory Constructors
// Optimized for legacy API
PolylinePoints legacyPoints = PolylinePoints.legacy("YOUR_API_KEY");
// Optimized for Routes API
PolylinePoints enhancedPoints = PolylinePoints.enhanced("YOUR_API_KEY");
// Custom configuration
PolylinePoints customPoints = PolylinePoints.custom(
apiKey: "YOUR_API_KEY",
timeout: Duration(seconds: 60),
preferRoutesApi: true,
);
๐ Response Data
Legacy API Response
class PolylineResult {
List<PointLatLng> points;
String? errorMessage;
String? status;
}
Routes API Response
class RoutesApiResponse {
List<Route> routes;
String? status;
String? errorMessage;
}
class Route {
int? duration; // Duration in seconds
int? staticDuration; // Static duration in seconds
int? distanceMeters; // Distance in meters
String? polylineEncoded; // Encoded polyline string
List<PointLatLng>? polylinePoints; // Decoded polyline points
// Convenience getters
double? get durationMinutes => duration != null ? duration! / 60.0 : null;
double? get staticDurationMinutes => staticDuration != null ? staticDuration! / 60.0 : null;
double? get distanceKm => distanceMeters != null ? distanceMeters! / 1000.0 : null;
}
๐ฏ Features Comparison
Feature | Legacy Directions API | Routes API |
---|---|---|
Basic routing | โ | โ |
Waypoints | โ | โ |
Travel modes | Driving, Walking, Bicycling, Transit | + Two-Wheeler |
Alternative routes | โ | โ |
Route modifiers | Basic | Enhanced |
Polyline quality | Standard | High-quality, Overview |
Request format | GET with query params | POST with JSON |
Custom parameters | โ | โ |
Timing preferences | โ | โ |
Field mask support | โ | โ |
๐ง Troubleshooting
Common Issues
-
API Key Issues
- Ensure your API key has the correct APIs enabled
- Check API key restrictions and quotas
- Verify billing is enabled for your Google Cloud project
-
Routes API Errors
- The Routes API requires different permissions than Directions API
- Check the Routes API documentation for requirements
-
Migration Issues
- Update constructor calls to include
apiKey
parameter - Use
convertToLegacyResult()
for compatibility - Check method signatures for parameter changes
- Update constructor calls to include
Error Handling
try {
RoutesApiResponse response = await polylinePoints.getRouteBetweenCoordinatesV2(
request: RoutesApiRequest(
origin: PointLatLng(37.7749, -122.4194),
destination: PointLatLng(37.3382, -121.8863),
),
);
if (response.routes.isNotEmpty) {
// Success
Route route = response.routes.first;
} else {
print('Error: ${response.errorMessage ?? "No routes found"}');
}
} catch (e) {
print('Exception: $e');
}
๐ Examples
Check out the /example
folder for comprehensive examples:
- Legacy API Example: Basic routing with backward compatibility
- Routes API Example: Enhanced features and custom parameters
- Two-Wheeler Example: Motorcycle/scooter optimized routing
- Advanced Configuration: Custom body parameters and timing preferences
๐ค Contributing
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Links
- Google Directions API Documentation
- Google Routes API Documentation
- Package on pub.dev
- GitHub Repository
๐ Changelog
Version 3.0.0
- ๐ BREAKING: Simplified API with unified
PolylinePoints
class - ๐ BREAKING: Constructor now requires
apiKey
parameter - โจ Enhanced Routes API integration with
RoutesApiRequest
/RoutesApiResponse
- ๐ ๏ธ Added custom body parameters support
- ๐๏ธ Added two-wheeler routing mode
- โฐ Added timing preferences (departure/arrival time)
- ๐ฏ Added field mask support for response optimization
- ๐งช Comprehensive test coverage added
- ๐ Improved response models with convenience getters
- ๐ง Better error handling and type safety
- ๐ ๏ธ Maintained backward compatibility for legacy API
Previous Versions
See CHANGELOG.md for complete version history.