Aggiunta di Google Maps a un'app Flutter

1. Introduzione

Flutter è l'SDK per app mobile di Google per creare esperienze native di alta qualità su iOS e Android in tempi record.

Con il plug-in Flutter di Google Maps, puoi aggiungere alla tua applicazione mappe basate sui dati di Google Maps. Il plug-in gestisce automaticamente l'accesso ai server di Google Maps, la visualizzazione della mappa e la risposta ai gesti dell'utente, come clic e trascina. Puoi anche aggiungere indicatori alla mappa. Questi oggetti forniscono informazioni aggiuntive per le posizioni sulla mappa e consentono all'utente di interagire con la mappa.

Cosa creerai

In questo codelab, creerai un'app mobile con una mappa Google utilizzando l'SDK Flutter. La tua app sarà in grado di:

  • Visualizza una mappa Google
  • Recuperare i dati della mappa da un servizio web
  • Visualizza questi dati come indicatori sulla mappa

Uno screenshot di un'app Flutter con una mappa di Google in esecuzione in un simulatore per iPhone in cui è evidenziata l'area Mountain View

Cos'è Flutter?

Flutter ha tre capacità principali.

  • Veloce da sviluppare: crea le tue applicazioni Android e iOS in pochi millisecondi con Stateful Hot Reload.
  • Espressivi e flessibili: distribuisci rapidamente le funzionalità con particolare attenzione alle esperienze native dell'utente finale.
  • Prestazioni native su iOS e Android: i widget di Flutter incorporano tutte le differenze fondamentali della piattaforma, come scorrimento, navigazione, icone e caratteri, per fornire prestazioni native complete.

Google Maps offre:

  • 99% di copertura nel mondo: crea dati affidabili e completi per oltre 200 paesi e territori.
  • 25 milioni di aggiornamenti al giorno: puoi contare su informazioni sulla posizione precise e in tempo reale.
  • 1 miliardo di utenti attivi al mese: scala in modo sicuro, con il supporto delle funzionalità di Google Maps dell'infrastruttura.

Questo codelab ti guida nella creazione di un'esperienza su Google Maps in un'app Flutter sia per iOS che per Android.

Cosa imparerai a fare

  • Come creare una nuova applicazione Flutter.
  • Come configurare un plug-in Flutter per Google Maps.
  • Come aggiungere indicatori a una mappa utilizzando i dati sulla posizione provenienti da un servizio web.

Questo codelab è incentrato sull'aggiunta di una mappa Google a un'app Flutter. Concetti e blocchi di codice non pertinenti sono trattati solo superficialmente e sono forniti solo per operazioni di copia e incolla.

Cosa ti piacerebbe imparare da questo codelab?

Non ho mai affrontato questo argomento e vorrei una panoramica completa. So qualcosa su questo argomento, ma vorrei rinfrescarti un po'. Sto cercando un codice di esempio da utilizzare nel mio progetto. Vorrei avere una spiegazione su qualcosa di specifico.

2. Configurare l'ambiente Flutter

Per completare questo lab sono necessari due software: l'SDK Flutter e un editor. Questo codelab presuppone l'utilizzo di Android Studio, ma puoi utilizzare il tuo editor preferito.

Puoi eseguire questo codelab utilizzando uno dei seguenti dispositivi:

  • Un dispositivo fisico (Android o iOS) collegato al computer e impostato sulla modalità sviluppatore.
  • Il simulatore iOS. (è richiesta l'installazione di strumenti Xcode).
  • L'emulatore Android. (la configurazione è richiesta in Android Studio).

3. Per iniziare

Guida introduttiva a Flutter

Il modo più semplice per iniziare a utilizzare Flutter è utilizzare lo strumento a riga di comando flutter per creare tutto il codice richiesto per un'esperienza introduttiva semplice.

$ flutter create google_maps_in_flutter --platforms android,ios,web
Creating project google_maps_in_flutter...
Resolving dependencies in `google_maps_in_flutter`... 
Downloading packages... 
Got dependencies in `google_maps_in_flutter`.
Wrote 81 files.

All done!
You can find general documentation for Flutter at: https://docs.flutter.dev/
Detailed API documentation is available at: https://api.flutter.dev/
If you prefer video documentation, consider: https://www.youtube.com/c/flutterdev

In order to run your application, type:

  $ cd google_maps_in_flutter
  $ flutter run

Your application code is in google_maps_in_flutter/lib/main.dart.

Aggiunta del plug-in Flutter di Google Maps come dipendenza

È facile aggiungere ulteriori funzionalità a un'app Flutter utilizzando i pacchetti Pub. In questo codelab introduci il plug-in Flutter di Google Maps eseguendo il seguente comando dalla directory del progetto.

$ cd google_maps_in_flutter
$ flutter pub add google_maps_flutter
Resolving dependencies... 
Downloading packages... 
+ csslib 1.0.0
+ flutter_plugin_android_lifecycle 2.0.19
+ flutter_web_plugins 0.0.0 from sdk flutter
+ google_maps 7.1.0
+ google_maps_flutter 2.6.1
+ google_maps_flutter_android 2.8.0
+ google_maps_flutter_ios 2.6.0
+ google_maps_flutter_platform_interface 2.6.0
+ google_maps_flutter_web 0.5.7
+ html 0.15.4
+ js 0.6.7 (0.7.1 available)
+ js_wrapping 0.7.4
  leak_tracker 10.0.4 (10.0.5 available)
  leak_tracker_flutter_testing 3.0.3 (3.0.5 available)
  material_color_utilities 0.8.0 (0.11.1 available)
  meta 1.12.0 (1.14.0 available)
+ plugin_platform_interface 2.1.8
+ sanitize_html 2.1.0
+ stream_transform 2.1.0
  test_api 0.7.0 (0.7.1 available)
+ web 0.5.1
Changed 16 dependencies!
6 packages have newer versions incompatible with dependency constraints.
Try `flutter pub outdated` for more information.

Configurazione di iOS platform

Per ottenere la versione più recente dell'SDK di Google Maps su iOS è richiesta una versione minima della piattaforma di iOS 14. Modifica la parte superiore del file di configurazione ios/Podfile come segue.

ios/Podfile

# Google Maps SDK requires platform version 14
# https://developers.google.com/maps/flutter-package/config#ios
platform :ios, '14.0'


# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

Configurazione di Android minSDK

Per utilizzare l'SDK Google Maps su Android, è necessario impostare minSdk su 21. Modifica il file di configurazione android/app/build.gradle come segue.

android/app/build.gradle

android {
    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId = "com.example.google_maps_in_flutter"
        // Minimum Android version for Google Maps SDK
        // https://developers.google.com/maps/flutter-package/config#android
        minSdk = 21
        targetSdk = flutter.targetSdkVersion
        versionCode = flutterVersionCode.toInteger()
        versionName = flutterVersionName
    }

}

4. Aggiunta di Google Maps all'app

Si tratta di chiavi API

Per utilizzare Google Maps nell'app Flutter, devi configurare un progetto API con Google Maps Platform, seguendo le istruzioni della chiave API di Maps SDK for Android e dell'SDK Maps per iOS Utilizzo della chiave API e Utilizzo della chiave API dell'API Maps JavaScript. Tenendo le chiavi API a portata di mano, svolgi i passaggi che seguono per configurare le applicazioni per Android e iOS.

Aggiungere una chiave API per un'app Android

Per aggiungere una chiave API all'app per Android, modifica il file AndroidManifest.xml in android/app/src/main. Aggiungi una singola voce meta-data all'interno del nodo application contenente la chiave API creata nel passaggio precedente.

android/app/src/main/AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        android:label="google_maps_in_flutter"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">

        <!-- TODO: Add your Google Maps API key here -->
        <meta-data android:name="com.google.android.geo.API_KEY"
               android:value="YOUR-KEY-HERE"/>

        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:taskAffinity=""
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <!-- Specifies an Android theme to apply to this Activity as soon as
                 the Android process has started. This theme is visible to the user
                 while the Flutter UI initializes. After that, this theme continues
                 to determine the Window background behind the Flutter UI. -->
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <!-- Don't delete the meta-data below.
             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
    </application>
    <!-- Required to query activities that can process text, see:
         https://developer.android.com/training/package-visibility and
         https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.

         In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
    <queries>
        <intent>
            <action android:name="android.intent.action.PROCESS_TEXT"/>
            <data android:mimeType="text/plain"/>
        </intent>
    </queries>
</manifest>

Aggiunta di una chiave API per un'app per iOS

Per aggiungere una chiave API all'app per iOS, modifica il file AppDelegate.swift in ios/Runner. A differenza di Android, l'aggiunta di una chiave API su iOS richiede modifiche al codice sorgente dell'app Runner. AppDelega è il singleton principale che fa parte del processo di inizializzazione dell'app.

Apporta due modifiche a questo file. In primo luogo, aggiungi un'istruzione #import per estrarre le intestazioni di Google Maps, quindi chiama il metodo provideAPIKey() del singleton GMSServices. Questa chiave API consente a Google Maps di mostrare correttamente i riquadri delle mappe.

ios/Runner/AppDelegate.swift

import Flutter
import UIKit
import GoogleMaps                                          // Add this import

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)

    // TODO: Add your Google Maps API key
    GMSServices.provideAPIKey("YOUR-API-KEY")               // Add this line

    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

Aggiunta di una chiave API per un'app web

Per aggiungere una chiave API all'app web, modifica il file index.html in web. Aggiungi un riferimento allo script JavaScript di Maps nella sezione head con la tua chiave API.

web/index.html

<!DOCTYPE html>
<html>
<head>
  <!--
    If you are serving your web app in a path other than the root, change the
    href value below to reflect the base path you are serving from.

    The path provided below has to start and end with a slash "/" in order for
    it to work correctly.

    For more details:
    * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base

    This is a placeholder for base href that will be replaced by the value of
    the `--base-href` argument provided to `flutter build`.
  -->
  <base href="$FLUTTER_BASE_HREF">

  <meta charset="UTF-8">
  <meta content="IE=Edge" http-equiv="X-UA-Compatible">
  <meta name="description" content="A new Flutter project.">

  <!-- iOS meta tags & icons -->
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="apple-mobile-web-app-title" content="google_maps_in_flutter">
  <link rel="apple-touch-icon" href="icons/Icon-192.png">

  <!-- Favicon -->
  <link rel="icon" type="image/png" href="favicon.png"/>

  <!-- Add your Google Maps API key here -->
  <script src="https://maps.googleapis.com/maps/api/js?key=YOUR-KEY-HERE"></script>

  <title>google_maps_in_flutter</title>
  <link rel="manifest" href="manifest.json">
</head>
<body>
  <script src="flutter_bootstrap.js" async></script>
</body>
</html>

Inserire una mappa sullo schermo

È il momento di mostrare una mappa sullo schermo. Sostituisci i contenuti di lib/main.dart con quanto segue.

lib/main.dart

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late GoogleMapController mapController;

  final LatLng _center = const LatLng(45.521563, -122.677433);

  void _onMapCreated(GoogleMapController controller) {
    mapController = controller;
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: Colors.green[700],
      ),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Maps Sample App'),
          elevation: 2,
        ),
        body: GoogleMap(
          onMapCreated: _onMapCreated,
          initialCameraPosition: CameraPosition(
            target: _center,
            zoom: 11.0,
          ),
        ),
      ),
    );
  }
}

Esecuzione dell'app

Esegui l'app Flutter su iOS o Android per avere un'unica visualizzazione mappa, centrata su Milano. In alternativa, esegui un emulatore Android o un simulatore iOS. Puoi modificare il centro della mappa per rappresentare la tua città natale o un luogo che è importante per te.

$ flutter run

Uno screenshot di un&#39;app Flutter con una mappa di Google in esecuzione in un simulatore per iPhone

Uno screenshot di un&#39;app Flutter con una mappa Google in esecuzione in un emulatore Android

5. Metti Google sulla mappa

Google ha molti uffici in tutto il mondo, da Nord America, America Latina, Europa, Asia Pacifico, Africa e Medio Oriente. L'aspetto positivo di queste mappe, se le esamini, è che hanno un endpoint API facilmente utilizzabile per fornire le informazioni sulla sede dell'ufficio in formato JSON. In questo passaggio, inserisci le sedi degli uffici sulla mappa. In questo passaggio, utilizzerai la generazione del codice per analizzare JSON.

Aggiungi tre nuove dipendenze Flutter al progetto come segue. Aggiungi il pacchetto http per effettuare facilmente richieste HTTP, json_serializable e json_annotation per dichiarare la struttura degli oggetti per la rappresentazione di documenti JSON. Aggiungi build_runner per il supporto della generazione di codice.

$ flutter pub add http json_annotation json_serializable dev:build_runner
Resolving dependencies... 
Downloading packages... 
+ _fe_analyzer_shared 67.0.0 (68.0.0 available)
+ analyzer 6.4.1 (6.5.0 available)
+ args 2.5.0
+ build 2.4.1
+ build_config 1.1.1
+ build_daemon 4.0.1
+ build_resolvers 2.4.2
+ build_runner 2.4.9
+ build_runner_core 7.3.0
+ built_collection 5.1.1
+ built_value 8.9.2
+ checked_yaml 2.0.3
+ code_builder 4.10.0
+ convert 3.1.1
+ crypto 3.0.3
+ dart_style 2.3.6
+ file 7.0.0
+ fixnum 1.1.0
+ frontend_server_client 4.0.0
+ glob 2.1.2
+ graphs 2.3.1
+ http 1.2.1
+ http_multi_server 3.2.1
+ http_parser 4.0.2
+ io 1.0.4
  js 0.6.7 (0.7.1 available)
+ json_annotation 4.9.0
+ json_serializable 6.8.0
  leak_tracker 10.0.4 (10.0.5 available)
  leak_tracker_flutter_testing 3.0.3 (3.0.5 available)
+ logging 1.2.0
  material_color_utilities 0.8.0 (0.11.1 available)
  meta 1.12.0 (1.14.0 available)
+ mime 1.0.5
+ package_config 2.1.0
+ pool 1.5.1
+ pub_semver 2.1.4
+ pubspec_parse 1.2.3
+ shelf 1.4.1
+ shelf_web_socket 1.0.4
+ source_gen 1.5.0
+ source_helper 1.3.4
  test_api 0.7.0 (0.7.1 available)
+ timing 1.0.1
+ typed_data 1.3.2
+ watcher 1.1.0
+ web_socket_channel 2.4.5
+ yaml 3.1.2
Changed 42 dependencies!
8 packages have newer versions incompatible with dependency constraints.
Try `flutter pub outdated` for more information.

Analisi di JSON con generazione del codice

Potresti aver notato che i dati JSON restituiti dall'endpoint API hanno una struttura normale. Potrebbe essere utile generare il codice per eseguire il marshal dei dati in oggetti da utilizzare nel codice.

Nella directory lib/src, crea un file locations.dart e descrivi la struttura dei dati JSON restituiti come segue:

lib/src/locations.dart

import 'dart:convert';

import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:http/http.dart' as http;
import 'package:json_annotation/json_annotation.dart';

part 'locations.g.dart';

@JsonSerializable()
class LatLng {
  LatLng({
    required this.lat,
    required this.lng,
  });

  factory LatLng.fromJson(Map<String, dynamic> json) => _$LatLngFromJson(json);
  Map<String, dynamic> toJson() => _$LatLngToJson(this);

  final double lat;
  final double lng;
}

@JsonSerializable()
class Region {
  Region({
    required this.coords,
    required this.id,
    required this.name,
    required this.zoom,
  });

  factory Region.fromJson(Map<String, dynamic> json) => _$RegionFromJson(json);
  Map<String, dynamic> toJson() => _$RegionToJson(this);

  final LatLng coords;
  final String id;
  final String name;
  final double zoom;
}

@JsonSerializable()
class Office {
  Office({
    required this.address,
    required this.id,
    required this.image,
    required this.lat,
    required this.lng,
    required this.name,
    required this.phone,
    required this.region,
  });

  factory Office.fromJson(Map<String, dynamic> json) => _$OfficeFromJson(json);
  Map<String, dynamic> toJson() => _$OfficeToJson(this);

  final String address;
  final String id;
  final String image;
  final double lat;
  final double lng;
  final String name;
  final String phone;
  final String region;
}

@JsonSerializable()
class Locations {
  Locations({
    required this.offices,
    required this.regions,
  });

  factory Locations.fromJson(Map<String, dynamic> json) =>
      _$LocationsFromJson(json);
  Map<String, dynamic> toJson() => _$LocationsToJson(this);

  final List<Office> offices;
  final List<Region> regions;
}

Future<Locations> getGoogleOffices() async {
  const googleLocationsURL = 'https://about.google/static/data/locations.json';

  // Retrieve the locations of Google offices
  try {
    final response = await http.get(Uri.parse(googleLocationsURL));
    if (response.statusCode == 200) {
      return Locations.fromJson(
          json.decode(response.body) as Map<String, dynamic>);
    }
  } catch (e) {
    if (kDebugMode) {
      print(e);
    }
  }

  // Fallback for when the above HTTP request fails.
  return Locations.fromJson(
    json.decode(
      await rootBundle.loadString('assets/locations.json'),
    ) as Map<String, dynamic>,
  );
}

Dopo aver aggiunto questo codice, il tuo IDE (se ne utilizzi uno) dovrebbe mostrare delle "scarabocchi" rossi, poiché fa riferimento a un file di pari livello inesistente. locations.g.dart. Questo file generato viene convertito tra strutture JSON non digitate e oggetti con nome. Per crearlo, esegui build_runner nel seguente modo:

$ dart run build_runner build --delete-conflicting-outputs
[INFO] Generating build script...
[INFO] Generating build script completed, took 357ms

[INFO] Creating build script snapshot......
[INFO] Creating build script snapshot... completed, took 10.5s

[INFO] There was output on stdout while compiling the build script snapshot, run with `--verbose` to see it (you will need to run a `clean` first to re-snapshot).

[INFO] Initializing inputs
[INFO] Building new asset graph...
[INFO] Building new asset graph completed, took 646ms

[INFO] Checking for unexpected pre-existing outputs....
[INFO] Deleting 1 declared outputs which already existed on disk.
[INFO] Checking for unexpected pre-existing outputs. completed, took 3ms

[INFO] Running build...
[INFO] Generating SDK summary...
[INFO] 3.4s elapsed, 0/3 actions completed.
[INFO] Generating SDK summary completed, took 3.4s

[INFO] 4.7s elapsed, 2/3 actions completed.
[INFO] Running build completed, took 4.7s

[INFO] Caching finalized dependency graph...
[INFO] Caching finalized dependency graph completed, took 36ms

[INFO] Succeeded after 4.8s with 2 outputs (7 actions)

Il codice dovrebbe analizzare di nuovo in modo corretto. Successivamente, dobbiamo aggiungere il file locations.json di fallback utilizzato nella funzione getGoogleOffices. Uno dei motivi per includere questo elemento di riserva è che i dati statici caricati in questa funzione vengono forniti senza intestazioni CORS e pertanto non verranno caricati in un browser web. Le app Flutter per Android e iOS non hanno bisogno di intestazioni CORS, ma l'accesso ai dati mobili può essere spesso limitato.

Vai a https://about.google/static/data/locations.json nel browser e salva i contenuti nella directory degli asset. In alternativa, puoi utilizzare la riga di comando come indicato di seguito.

$ mkdir assets
$ cd assets
$ curl -o locations.json https://about.google/static/data/locations.json
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 30348  100 30348    0     0  75492      0 --:--:-- --:--:-- --:--:-- 75492

Ora che hai scaricato il file degli asset, aggiungilo alla sezione Flutter del file pubspec.yaml.

pubspec.yaml

flutter:
  uses-material-design: true

  assets:
    - assets/locations.json

Modifica il file main.dart per richiedere i dati della mappa, quindi utilizza le informazioni restituite per aggiungere uffici alla mappa:

lib/main.dart

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'src/locations.dart' as locations;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final Map<String, Marker> _markers = {};
  Future<void> _onMapCreated(GoogleMapController controller) async {
    final googleOffices = await locations.getGoogleOffices();
    setState(() {
      _markers.clear();
      for (final office in googleOffices.offices) {
        final marker = Marker(
          markerId: MarkerId(office.name),
          position: LatLng(office.lat, office.lng),
          infoWindow: InfoWindow(
            title: office.name,
            snippet: office.address,
          ),
        );
        _markers[office.name] = marker;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: Colors.green[700],
      ),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Google Office Locations'),
          elevation: 2,
        ),
        body: GoogleMap(
          onMapCreated: _onMapCreated,
          initialCameraPosition: const CameraPosition(
            target: LatLng(0, 0),
            zoom: 2,
          ),
          markers: _markers.values.toSet(),
        ),
      ),
    );
  }
}

Questo codice esegue diverse operazioni:

  • In _onMapCreated, utilizza il codice di analisi JSON del passaggio precedente, awaiting fino al caricamento. Quindi, utilizza i dati restituiti per creare Marker all'interno di un callback setState(). Una volta che l'app riceve nuovi indicatori, setState segnala a Flutter per ridipingere lo schermo, visualizzando le posizioni degli uffici.
  • Gli indicatori sono memorizzati in un elemento Map associato al widget GoogleMap. In questo modo, gli indicatori vengono collegati alla mappa corretta. Potresti, ovviamente, avere più mappe e visualizzare indicatori diversi in ognuna.

Uno screenshot di un&#39;app Flutter con una mappa di Google in esecuzione in un simulatore per iPhone in cui è evidenziata l&#39;area Mountain View

Ecco uno screenshot dei risultati raggiunti. A questo punto si possono aggiungere molte aggiunte interessanti. Ad esempio, potresti aggiungere una visualizzazione elenco degli uffici che si spostano e ingrandisci la mappa quando l'utente fa clic su un ufficio ma, come si suol dire, questo esercizio è lasciato al lettore.

6. Passaggi successivi

Complimenti!

Hai completato il codelab e creato un'app Flutter con una mappa di Google Maps. Hai anche interagito con un servizio web JSON.

Altri passaggi successivi

Questo codelab ha creato un'esperienza per visualizzare una serie di punti su una mappa. Esistono varie app mobile che si basano su questa funzionalità per soddisfare molte esigenze diverse degli utenti. Esistono altre risorse che possono aiutarti a raggiungere questo obiettivo: