Skip to content

FabianVarela/flutter_maps_app

Repository files navigation

Flutter Maps App

Flutter application featuring Google Maps integration with real-time location tracking, place search, and custom map styling. Built with Bloc pattern for state management and supporting Android, iOS, and Web platforms.

Prerequisites

Before getting started, make sure you have the following installed:

  • Flutter SDK: >=3.10.0 <4.0.0
  • Dart SDK: >=3.10.0 <4.0.0
  • IDE: VSCode or Android Studio with Flutter extensions
  • Google Cloud Account: Required for Google Maps API access
  • Platforms:
    • For iOS: Xcode (macOS only)
    • For Android: Android Studio or Android SDK
    • For Web: Google Chrome

Initial Setup

1. Clone the repository

git clone <repository-url>
cd flutter_maps_app

2. Install dependencies

flutter pub get

3. Configure Google Maps API

This project requires Google Maps API keys for Android, iOS, and Web.

Create Google Cloud Project

  1. Go to Google Cloud Console
  2. Create a new project or select an existing one
  3. Enable the following APIs:
    • Maps SDK for Android
    • Maps SDK for iOS
    • Maps JavaScript API
    • Places API
    • Directions API
    • Geocoding API

Generate API Keys

  1. Go to APIs & Services > Credentials
  2. Click Create Credentials > API Key
  3. Create separate API keys for each platform (recommended) or use one key for all
  4. Restrict each API key to specific APIs and platforms for security

Configure Android

  1. Restrict the Android API key to:
    • Maps SDK for Android
    • Places API
    • Android apps (add your app's SHA-1 fingerprint)

Configure iOS

  1. Restrict the iOS API key to:
    • Maps SDK for iOS
    • Places API
    • iOS apps (add your bundle identifier)

Configure Web

  1. Restrict the Web API key to:

    • Maps JavaScript API
    • Places API
    • Directions API
    • Geocoding API
    • HTTP referrers (add your website URLs)
  2. The Web platform uses --dart-define to pass the API key securely:

    • The key is loaded dynamically at runtime via Dart code
    • Never hardcode the API key in web/index.html
    • See the Final Recommendations section for detailed security practices

4. Configure Location Permissions

Android

The necessary permissions are already configured in android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

iOS

Add location permissions to ios/Runner/Info.plist:

<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to your location to show your position on the map</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to your location to track your position</string>

5. Generate assets

The project uses flutter_gen to generate type-safe access to assets:

flutter pub run build_runner build --delete-conflicting-outputs

Assets are located at:

  • assets/map_styles/ - Custom map style JSON files
  • assets/images/ - Image assets

6. Generate localization files

flutter gen-l10n

Development

Run the application

Important: Always pass the Google Maps API key using --dart-define:

flutter run --dart-define-from-file=config-keys.json

Run on specific platform

# Android
flutter run -d android --dart-define-from-file=config-keys.json

# iOS
flutter run -d iPhone --dart-define-from-file=config-keys.json

# Web (development)
flutter run -d chrome --dart-define-from-file=config-keys.json

Build for production

# Android (App Bundle)
flutter build appbundle --dart-define-from-file=config-keys.json

# Android (APK)
flutter build apk --dart-define-from-file=config-keys.json

# iOS
flutter build ios --dart-define-from-file=config-keys.json

# Web (production - use production key with domain restrictions)
flutter build web --dart-define-from-file=config-keys.json

Project Structure

lib/
├── core/                   # Core application infrastructure
│   ├── gen/               # Generated assets (flutter_gen)
│   ├── theme/             # App theming
│   └── utils/             # Utilities and helpers
├── Bloc/                   # Bloc state management
│   ├── location_Bloc/     # User location tracking
│   ├── map_Bloc/          # Map state management
│   └── places_Bloc/       # Places search
├── data/                   # Data layer
│   ├── models/            # Data models
│   ├── repositories/      # Data repositories
│   └── services/          # External services (Google Maps API)
├── ui/                     # UI layer
│   ├── pages/             # Application pages
│   └── widgets/           # Reusable widgets
└── main.dart              # Application entry point
assets/
├── map_styles/            # Custom map styles (JSON)
└── images/                # Image assets

Features

Google Maps Integration

  • Interactive Map: Full-featured Google Maps with gestures support
  • Map Controls: Zoom, compass, and map type controls
  • Custom Markers: Add custom markers with info windows
  • Polylines & Polygons: Draw routes and areas on the map
  • Map Styling: Apply custom map styles (light, dark, retro, etc.)
  • Map Types: Switch between normal, satellite, hybrid, and terrain views

Location Services

  • Real-time Location: Track user's current location
  • Location Updates: Continuous location tracking
  • Location Permissions: Handle location permission requests
  • GPS Accuracy: Display location accuracy radius
  • My Location Button: Quick navigation to current position
  • Background Tracking: Continue tracking in background (optional)

Places Search

  • Place Search: Search for places using Google Places API
  • Autocomplete: Real-time search suggestions
  • Place Details: View detailed information about places
  • Nearby Places: Find nearby points of interest
  • Place Categories: Filter by category (restaurants, gas stations, etc.)
  • Custom Markers: Display search results on map

Map Customization

  • Custom Styles: Multiple pre-defined map styles
  • Style Switcher: Easy switching between map styles
  • Custom Markers: Icon customization for different marker types
  • Info Windows: Custom info window designs

User Experience

  • Smooth Animations: Animated camera movements
  • Loading States: Skeleton loaders and progress indicators
  • Error Handling: User-friendly error messages
  • Offline Support: Basic functionality without internet
  • State Persistence: Remember last map position and settings
  • Responsive Design: Works on phones and tablets

Bloc Architecture

Location Bloc

Manages user location tracking:

  • LocationRequested: Request current location
  • LocationUpdated: Continuous location updates
  • LocationPermissionChanged: Handle permission changes
  • LocationServiceStatusChanged: Track GPS service status

Map Bloc

Manages map state and interactions:

  • MapInitialized: Initialize map with settings
  • MapStyleChanged: Apply custom map style
  • MapTypeChanged: Switch map type (normal, satellite, etc.)
  • CameraPositionChanged: Update camera position
  • MarkerAdded: Add marker to map
  • PolylineAdded: Add route/path to map

Places Bloc

Handles place search functionality:

  • PlacesSearchRequested: Search for places
  • PlaceSelected: Show details for selected place
  • NearbyPlacesRequested: Find nearby places
  • AutocompleteQueryChanged: Update search suggestions

Google Maps API

Maps SDK

  • Android: Uses Google Maps SDK for Android
  • iOS: Uses Google Maps SDK for iOS
  • Web: Uses Google Maps JavaScript API

Places API

Search and autocomplete functionality:

GET https://maps.googleapis.com/maps/api/place/autocomplete/json?input={query}&key={API_KEY}&types={types}&location={lat,lng}&radius={radius}

Geocoding API

Convert addresses to coordinates:

GET https://maps.googleapis.com/maps/api/geocode/json?address={address}&key={API_KEY}

Map Styles

Custom map styles are defined in JSON format in assets/map_styles/. Each style file follows the Snazzy Maps format.

Available Styles

  1. night_blue_mode.json - Grayscale monochrome style
  2. night_mode.json - Vintage map appearance
  3. personal_mode.json - Dark theme for low-light environments
  4. uber_mode.json - High contrast night mode

Testing

Run all tests

flutter test

Run tests with coverage

flutter test --coverage

View coverage report

# Generate coverage report
genhtml coverage/lcov.info -o coverage/

# Open coverage report in browser
open coverage/index.html

Run specific test file

flutter test test/path/to/test_file.dart

Code Quality

Run code analysis

The project uses very_good_analysis to maintain code quality:

flutter analyze

Format code

flutter format .

Generate code

For assets and localization:

# Generate assets
flutter pub run build_runner build --delete-conflicting-outputs

# Watch for changes and auto-generate
flutter pub run build_runner watch --delete-conflicting-outputs

# Generate localization
flutter gen-l10n

Main Dependencies

Maps & Location

  • google_maps_flutter: Google Maps SDK integration
  • geolocator: Location services and permissions
  • google_maps_webservice: Google Maps Web Services API

State Management & Architecture

  • flutter_Bloc: Bloc pattern implementation
  • Bloc: Core Bloc library
  • equatable: Value equality for Bloc states
  • Bloc_concurrency: Advanced Bloc concurrency control

Data Persistence

  • shared_preferences: Local key-value storage

Utilities

  • stream_transform: Stream transformation utilities

Dev Dependencies

  • build_runner: Code generation
  • flutter_gen_runner: Type-safe asset generation
  • very_good_analysis: Strict lint rules

Location Permissions

Android Permission Levels

The app requests the following location permissions:

  • ACCESS_FINE_LOCATION: Precise location from GPS
  • ACCESS_COARSE_LOCATION: Approximate location from network

iOS Permission Levels

  • When In Use: Location access while app is in foreground
  • Always: Location access even when app is in background (if needed)

Web Geolocation

Web uses browser's Geolocation API, which prompts user for permission automatically.

Troubleshooting

Google Maps not displaying

  1. Check API Key: Verify API key is correctly configured
  2. Enable APIs: Ensure required APIs are enabled in Google Cloud Console
  3. Billing: Verify billing is enabled for your Google Cloud project
  4. Restrictions: Check API key restrictions aren't blocking requests
  5. Platform: Confirm API key is configured for the correct platform

Location not working

Android

  • Verify location permissions in AndroidManifest.xml
  • Check device GPS is enabled
  • Grant location permission in app settings
  • Test on physical device (emulator GPS may be unreliable)

iOS

  • Check Info.plist has location usage descriptions
  • Verify location permissions granted in iOS Settings
  • Test on physical device for best results

Web

  • Use HTTPS (required for geolocation on web)
  • Allow location permission in browser
  • Check browser console for geolocation errors

Map shows gray screen

  • Verify API key is valid
  • Check internet connection
  • Ensure Maps SDK is enabled for your platform
  • Check for JavaScript errors (Web)
  • Verify billing is enabled

Places search not working

  • Enable Places API in Google Cloud Console
  • Check API key has Places API access
  • Verify internet connection
  • Check API quota and billing

"API key not valid" error

  • Copy API key exactly (no extra spaces)
  • Check API key restrictions match your app
  • Verify correct API is enabled
  • Try creating a new unrestricted key for testing

iOS build fails

flutter clean
cd ios
pod install
pod update
cd ..
flutter build ios

Android build fails

flutter clean
cd android
./gradlew clean
cd ..
flutter build apk

Asset generation fails

flutter clean
flutter pub get
flutter pub run build_runner build --delete-conflicting-outputs

Location permission denied

Handle permission denial gracefully:

  • Show explanation dialog
  • Direct user to app settings
  • Provide fallback functionality
  • Test permission flows thoroughly

Performance Optimization

This app implements several performance optimizations:

Map Performance

  • Marker Clustering: Group nearby markers to reduce clutter
  • Visible Region: Only render markers in visible area
  • Lite Mode: Use lite mode for static maps
  • Zoom-based Markers: Show/hide markers based on zoom level

Architecture

Bloc Pattern

The app follows the Bloc (Business Logic Component) pattern:

  • UI: Widgets that display data and emit events
  • Bloc: Business logic that processes events and emits states
  • Repository: Data layer that communicates with APIs and services
  • Services: External service integrations (Google Maps, Location)

Data Flow

  1. User interacts with map (pan, zoom, search)
  2. UI emits event to appropriate Bloc
  3. Bloc processes event and calls repository/service
  4. Service interacts with Google Maps API or device GPS
  5. Repository returns data to Bloc
  6. Bloc emits new state
  7. UI rebuilds to reflect changes

Service Layer

  • GoogleMapsService: Wrapper for Google Maps Web Services
  • LocationService: Handles device location tracking
  • PlacesService: Place search and autocomplete
  • GeocodeService: Address to coordinate conversion

Security Best Practices

API Key Security

  • Restrict Keys: Always restrict API keys to specific APIs and platforms
  • Separate Keys: Use different keys for dev/staging/production
  • Don't Commit: Never commit API keys to version control
  • Environment Variables: Use environment variables or secret management
  • Rotation: Regularly rotate API keys
  • Monitoring: Monitor API usage for anomalies

Final Recommendations

Important: For client-side applications (web), the Google Maps API key will be visible in the compiled JavaScript. This is normal and expected for frontend apps. Google provides proper security mechanisms to protect your key:

1. Configure API Key Restrictions in Google Cloud Console

Application Restrictions (Critical):

1. Go to Google Cloud Console → APIs & Services → Credentials
2. Select your Web API key
3. Under "Application restrictions", choose "HTTP referrers (websites)"
4. Add your authorized domains:
   - https://yourdomain.com/*
   - https://*.yourdomain.com/*
   - http://localhost:* (for development only)

API Restrictions (Required):

Enable ONLY the APIs you use:
- Maps JavaScript API
- Places API
- Directions API
- Geocoding API

2. Use Separate Keys for Development and Production

Development:

{
  "GOOGLE_MAPS_API_KEY": "dev_key_with_localhost"
}
# Run with development key (restricted to localhost)
flutter run -d chrome --dart-define-from-file=config-keys.json

Production:

{
  "GOOGLE_MAPS_API_KEY": "prod_key_with_domain_restrictions"
}
# Build with production key (restricted to your domain)
flutter build web --dart-define-from-file=config-keys.json

3. Set Up Usage Quotas and Alerts

  1. In Google Cloud Console, go to "APIs & Services" → "Quotas"
  2. Set daily request limits for each API
  3. Configure billing alerts to notify you of unusual usage
  4. Review usage reports regularly in the Dashboard

4. Monitor API Usage

  • Enable detailed logging in Google Cloud Console
  • Set up alerts for unexpected usage spikes
  • Review the "APIs & Services → Dashboard" weekly
  • Check for unauthorized domains in the logs

Why This Approach is Secure

  • The API key being visible in JavaScript is by design for client-side APIs
  • Security comes from domain restrictions and API restrictions, not from hiding the key
  • Even if someone copies your key, they cannot use it from unauthorized domains
  • Usage quotas prevent abuse and unexpected charges
  • This is the official Google-recommended approach for web applications

License

[Include license information here]

About

Create an application in Flutter using Google Maps and Flutter Bloc

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published