flutter_polyline_points 3.0.1  flutter_polyline_points: ^3.0.1 copied to clipboard
flutter_polyline_points: ^3.0.1 copied to clipboard
A flutter package to get polyline points by either passing the coordinates or google encoded polyline string
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 PolylinePointsclass 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.1
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)),
);
Custom Headers #
You can pass custom HTTP headers with your Routes API requests. This is particularly useful for Android-restricted API keys:
RoutesApiRequest request = RoutesApiRequest(
  origin: PointLatLng(37.7749, -122.4194),
  destination: PointLatLng(37.3382, -121.8863),
  travelMode: TravelMode.driving,
  headers: {
    'X-Android-Package': 'com.example.myapp',
    'X-Android-Cert': 'YOUR_SHA1_FINGERPRINT',
    // Add any other custom headers
  },
);
Using with google_api_headers Package
For easier Android header management, you can use the google_api_headers package:
dependencies:
  flutter_polyline_points: ^3.0.0
  google_api_headers: ^4.0.0
import 'package:google_api_headers/google_api_headers.dart';
// Get Android-specific headers
Map<String, String> headers = await const GoogleApiHeaders().getHeaders();
RoutesApiRequest request = RoutesApiRequest(
  origin: PointLatLng(37.7749, -122.4194),
  destination: PointLatLng(37.3382, -121.8863),
  travelMode: TravelMode.driving,
  headers: headers, // Use the generated headers
);
RoutesApiResponse response = await polylinePoints.getRouteBetweenCoordinatesV2(
  request: request,
);
Note: Custom headers are only supported with the Routes API (getRouteBetweenCoordinatesV2). The legacy Directions API uses GET requests and doesn't support custom headers.
π 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 apiKeyparameter
- 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.flutter-io.cn
- GitHub Repository
π Changelog #
Version 3.0.0 #
- π BREAKING: Simplified API with unified PolylinePointsclass
- π BREAKING: Constructor now requires apiKeyparameter
- β¨ 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.