Adds complete Google Navigation support with: - LocationPermissionService for runtime location permissions - NavigationSessionService for session and route management - NavigationPage for full-screen turn-by-turn navigation UI - NavigationTermsAndConditionsDialog for service acceptance - Comprehensive i18n support (English/French) - Android minSdk=23 with Java NIO desugaring - iOS location permissions in Info.plist - Error handling with user-friendly dialogs - Location update and arrival notifications Includes detailed setup guide and implementation documentation with API key configuration instructions, integration examples, and testing checklist. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
347 lines
9.8 KiB
Markdown
347 lines
9.8 KiB
Markdown
# Google Navigation Flutter Setup Guide
|
|
|
|
This document provides detailed instructions for completing the Google Navigation Flutter implementation.
|
|
|
|
## Overview
|
|
|
|
The implementation includes:
|
|
- Location permissions handling with user dialogs
|
|
- Google Navigation session management
|
|
- Turn-by-turn navigation for delivery destinations
|
|
- Terms and Conditions acceptance for navigation services
|
|
- i18n support (English/French)
|
|
- Proper error handling and logging
|
|
|
|
## Prerequisites
|
|
|
|
Before implementing, you need:
|
|
|
|
1. **Google Cloud Project** with Navigation SDK enabled
|
|
2. **API Keys** for both Android and iOS platforms
|
|
3. **Configuration** in Android and iOS native files
|
|
|
|
## Part 1: API Key Configuration
|
|
|
|
### Android Setup
|
|
|
|
1. Open `android/app/build.gradle.kts`
|
|
2. Add your Android API key to the metadata section in `AndroidManifest.xml`:
|
|
|
|
```xml
|
|
<application>
|
|
<meta-data
|
|
android:name="com.google.android.geo.API_KEY"
|
|
android:value="YOUR_ANDROID_API_KEY" />
|
|
</application>
|
|
```
|
|
|
|
Alternatively, use Secrets Gradle Plugin for better security:
|
|
|
|
```gradle
|
|
// In android/app/build.gradle.kts
|
|
android {
|
|
buildTypes {
|
|
debug {
|
|
manifestPlaceholders = [googleMapsApiKey: "YOUR_ANDROID_API_KEY"]
|
|
}
|
|
release {
|
|
manifestPlaceholders = [googleMapsApiKey: "YOUR_ANDROID_API_KEY_RELEASE"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Then in `AndroidManifest.xml`:
|
|
```xml
|
|
<meta-data
|
|
android:name="com.google.android.geo.API_KEY"
|
|
android:value="${googleMapsApiKey}" />
|
|
```
|
|
|
|
### iOS Setup
|
|
|
|
1. Open `ios/Runner/AppDelegate.swift`
|
|
2. The API key is already configured in the `provideAPIKey()` method:
|
|
|
|
```swift
|
|
import GoogleMaps
|
|
|
|
@main
|
|
@objc class AppDelegate: FlutterAppDelegate {
|
|
override func application(
|
|
_ application: UIApplication,
|
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
|
) -> Bool {
|
|
GMSServices.provideAPIKey("YOUR_IOS_API_KEY")
|
|
GeneratedPluginRegistrant.register(with: self)
|
|
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
|
}
|
|
}
|
|
```
|
|
|
|
Replace `YOUR_IOS_API_KEY` with your actual Google Cloud Navigation API key.
|
|
|
|
## Part 2: Integration with Deliveries Page
|
|
|
|
To add navigation button to deliveries, update `lib/pages/deliveries_page.dart`:
|
|
|
|
```dart
|
|
import '../pages/navigation_page.dart';
|
|
|
|
// In your delivery item or action menu:
|
|
ElevatedButton(
|
|
onPressed: () {
|
|
Navigator.of(context).push(
|
|
MaterialPageRoute(
|
|
builder: (context) => NavigationPage(
|
|
delivery: delivery,
|
|
destinationLatitude: delivery.latitude,
|
|
destinationLongitude: delivery.longitude,
|
|
onNavigationComplete: () {
|
|
// Handle navigation completion
|
|
// Update delivery status
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text(
|
|
AppLocalizations.of(context)?.navigationArrived ??
|
|
'Navigation completed',
|
|
),
|
|
),
|
|
);
|
|
},
|
|
onNavigationCancelled: () {
|
|
// Handle cancellation
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text(
|
|
AppLocalizations.of(context)?.cancel ?? 'Navigation cancelled',
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
);
|
|
},
|
|
child: Text(AppLocalizations.of(context)?.navigateToAddress ?? 'Navigate'),
|
|
)
|
|
```
|
|
|
|
## Part 3: Location Permissions
|
|
|
|
The app uses the `permission_handler` package for location permissions. Permissions are already configured in:
|
|
|
|
- **Android**: `android/app/src/main/AndroidManifest.xml`
|
|
- Required: `INTERNET`, `ACCESS_FINE_LOCATION`, `ACCESS_COARSE_LOCATION`
|
|
- Optional background modes for continuous navigation
|
|
|
|
- **iOS**: `ios/Runner/Info.plist`
|
|
- `NSLocationWhenInUseUsageDescription`: When app is active
|
|
- `NSLocationAlwaysAndWhenInUseUsageDescription`: Always
|
|
- `NSLocationAlwaysUsageDescription`: Background location
|
|
- Background mode: "location" enabled
|
|
|
|
## Part 4: Available Classes and Services
|
|
|
|
### NavigationPage
|
|
Main UI widget for turn-by-turn navigation.
|
|
|
|
```dart
|
|
NavigationPage(
|
|
delivery: deliveryObject,
|
|
destinationLatitude: 33.5731,
|
|
destinationLongitude: -7.5898,
|
|
onNavigationComplete: () { /* Handle arrival */ },
|
|
onNavigationCancelled: () { /* Handle cancellation */ },
|
|
)
|
|
```
|
|
|
|
### LocationPermissionService
|
|
Handles location permission requests and checks.
|
|
|
|
```dart
|
|
final permissionService = LocationPermissionService();
|
|
|
|
// Check current permission status
|
|
final hasPermission = await permissionService.hasLocationPermission();
|
|
|
|
// Request permission
|
|
final result = await permissionService.requestLocationPermission();
|
|
result.when(
|
|
granted: () { /* Permission granted */ },
|
|
denied: () { /* Permission denied */ },
|
|
permanentlyDenied: () { /* Need to open settings */ },
|
|
error: (message) { /* Handle error */ },
|
|
);
|
|
```
|
|
|
|
### NavigationSessionService
|
|
Manages the Google Navigation session lifecycle.
|
|
|
|
```dart
|
|
final sessionService = NavigationSessionService();
|
|
|
|
// Initialize session
|
|
await sessionService.initializeSession();
|
|
|
|
// Set controller from the navigation view
|
|
await sessionService.setController(navigationViewController);
|
|
|
|
// Calculate and set route
|
|
final route = await sessionService.calculateRoute(
|
|
startLatitude: 33.5731,
|
|
startLongitude: -7.5898,
|
|
destinationLatitude: 33.5745,
|
|
destinationLongitude: -7.5850,
|
|
);
|
|
|
|
// Listen to events
|
|
sessionService.addArrivalListener((info) {
|
|
print('Arrived at destination');
|
|
});
|
|
|
|
sessionService.addLocationListener((location) {
|
|
print('Location: ${location.latitude}, ${location.longitude}');
|
|
});
|
|
|
|
// Start/stop navigation
|
|
await sessionService.startNavigation();
|
|
await sessionService.stopNavigation();
|
|
|
|
// Cleanup when done
|
|
await sessionService.cleanup();
|
|
```
|
|
|
|
### NavigationTermsAndConditionsDialog
|
|
Dialog component to show T&C for navigation services.
|
|
|
|
```dart
|
|
showDialog(
|
|
context: context,
|
|
builder: (context) => NavigationTermsAndConditionsDialog(
|
|
onAccept: () {
|
|
// Save acceptance and proceed with navigation
|
|
},
|
|
onDecline: () {
|
|
// User declined, don't start navigation
|
|
},
|
|
),
|
|
);
|
|
```
|
|
|
|
## Part 5: Error Handling
|
|
|
|
The implementation includes comprehensive error handling for:
|
|
|
|
1. **Location Permission Errors**
|
|
- Permission denied
|
|
- Permission permanently denied
|
|
- System errors
|
|
|
|
2. **Navigation Initialization Errors**
|
|
- Session initialization failure
|
|
- Controller not available
|
|
- Route calculation failure
|
|
|
|
3. **Runtime Errors**
|
|
- Network issues
|
|
- Location acquisition timeout
|
|
- Navigation start/stop failures
|
|
|
|
All errors are displayed through user-friendly dialogs with action buttons.
|
|
|
|
## Part 6: Internationalization
|
|
|
|
Navigation strings are available in English and French:
|
|
- `navigationTcTitle`, `navigationTcDescription`
|
|
- `locationPermissionRequired`, `locationPermissionMessage`
|
|
- `navigationArrived`, `navigatingTo`
|
|
|
|
Add custom translations to `lib/l10n/app_*.arb` files as needed.
|
|
|
|
## Part 7: Testing Checklist
|
|
|
|
### Android Testing
|
|
- [ ] Test on API level 23+ device
|
|
- [ ] Verify minSdk=23 is set
|
|
- [ ] Check desugaring is enabled
|
|
- [ ] Test location permissions request
|
|
- [ ] Verify navigation starts correctly
|
|
- [ ] Test with GPS disabled/enabled
|
|
- [ ] Verify Terms & Conditions dialog shows
|
|
|
|
### iOS Testing
|
|
- [ ] Test on iOS 16.0+ device
|
|
- [ ] Verify Info.plist has all location keys
|
|
- [ ] Test location permissions request
|
|
- [ ] Verify background location mode is enabled
|
|
- [ ] Test navigation with map open
|
|
- [ ] Verify arrival notification
|
|
- [ ] Check attribution text is visible
|
|
|
|
### Common Issues and Solutions
|
|
|
|
**Issue**: "Navigation SDK not available"
|
|
- Solution: Verify API key is correctly added and Navigation SDK is enabled in Google Cloud Console
|
|
|
|
**Issue**: "Location permission always denied"
|
|
- Solution: Clear app data and reinstall, or open app settings and manually enable location
|
|
|
|
**Issue**: "Navigation session fails to initialize"
|
|
- Solution: Check that controller is properly created before calling methods
|
|
|
|
**Issue**: "Routes not calculating"
|
|
- Solution: Ensure start and destination coordinates are valid and within service areas
|
|
|
|
## Part 8: Production Considerations
|
|
|
|
Before releasing to production:
|
|
|
|
1. **API Key Security**
|
|
- Use separate API keys for Android and iOS
|
|
- Restrict API keys by platform and package name
|
|
- Rotate keys periodically
|
|
|
|
2. **Analytics**
|
|
- Track navigation start/completion rates
|
|
- Monitor location permission denial rates
|
|
- Log any navigation errors
|
|
|
|
3. **User Experience**
|
|
- Provide clear instructions for permission requests
|
|
- Show progress during initialization
|
|
- Handle network failures gracefully
|
|
|
|
4. **Compliance**
|
|
- Ensure proper attribution to Google
|
|
- Display Terms & Conditions for navigation
|
|
- Comply with EEA data regulations if applicable
|
|
|
|
## Files Created/Modified
|
|
|
|
### Created Files
|
|
- `lib/services/location_permission_service.dart` - Permission handling
|
|
- `lib/services/navigation_session_service.dart` - Session management
|
|
- `lib/pages/navigation_page.dart` - Navigation UI
|
|
- `lib/components/navigation_tc_dialog.dart` - T&C dialog
|
|
|
|
### Modified Files
|
|
- `android/app/build.gradle.kts` - Added minSdk=23, desugaring
|
|
- `ios/Podfile` - iOS configuration (already set)
|
|
- `ios/Runner/Info.plist` - Location permissions (updated)
|
|
- `lib/l10n/app_en.arb` - English translations
|
|
- `lib/l10n/app_fr.arb` - French translations
|
|
|
|
## Next Steps
|
|
|
|
1. Add your API keys to Android and iOS configurations
|
|
2. Test location permissions flow
|
|
3. Integrate navigation button into delivery items
|
|
4. Test navigation on real devices
|
|
5. Monitor and handle edge cases in production
|
|
|
|
For more information, refer to:
|
|
- [Google Navigation Flutter Documentation](https://developers.google.com/maps/documentation/navigation/mobile-sdk)
|
|
- [Flutter Location Permissions](https://pub.dev/packages/permission_handler)
|
|
- [Google Cloud Console](https://console.cloud.google.com)
|