הוספה של מפות Google לאפליקציית Flutter

1. מבוא

Flutter היא ה-SDK של האפליקציה לנייד של Google ליצירת חוויות מותאמות באיכות גבוהה ב-iOS וב-Android בזמן שיא.

באמצעות הפלאגין של Google Maps Flutter, ניתן להוסיף לאפליקציה שלכם מפות המבוססות על נתוני מפות Google. הפלאגין מטפל באופן אוטומטי בגישה לשרתים של מפות Google, הצגת המפה ותגובה לתנועות משתמש כגון קליקים וגרירה. אפשר גם להוסיף סמנים למפה. האובייקטים האלה מספקים מידע נוסף על מיקומים במפה, ומאפשרים למשתמש לבצע אינטראקציה עם המפה.

מה תפַתחו

ב-Codelab הזה תבנה אפליקציה לנייד עם מפת Google באמצעות Flutter SDK. האפליקציה שלך:

  • הצגת מפה של Google
  • אחזור נתוני מפות משירות אינטרנט
  • הצגת הנתונים האלה כסמנים במפה

צילום מסך של אפליקציית Flutter עם מפת Google שפועלת בסימולטור של iPhone, עם הדגשה של Mountain View

מה זה Flutter?

ל-Flutter יש שלוש יכולות ליבה.

  • פיתוח מהיר: בניית אפליקציות ל-Android ול-iOS תוך אלפיות שנייה באמצעות Stateful Hot Reload.
  • תצוגה גמישה וגמישה: שליחת תכונות במהירות תוך התמקדות בחוויות משתמש מותאמות למשתמשים.
  • ביצועים מותאמים גם ב-iOS וגם ב-Android: הווידג'טים של Flutter משלבים את כל ההבדלים הקריטיים בין הפלטפורמות, כגון גלילה, ניווט, סמלים וגופנים — כדי לספק ביצועים מקוריים ומלאים.

במפות Google יש:

  • כיסוי של 99% לעולם: פיתוח באמצעות נתונים מהימנים מקיפים ליותר מ-200 מדינות ואזורים.
  • 25 מיליון עדכונים מדי יום: אפשר להסתמך על מידע מדויק בזמן אמת לגבי מיקום.
  • מיליארד משתמשים פעילים בחודש: התאמה לעומס (scaling) בצורה בטוחה, בעזרת מפות Google .

ה-Codelab הזה ידריך אותך איך ליצור חוויה של מפות Google באפליקציית Flutter ל-iOS וגם ל-Android.

מה תלמדו

  • איך ליצור אפליקציה חדשה של Flutter.
  • איך להגדיר פלאגין של Flutter של מפות Google.
  • איך להוסיף סמנים למפה באמצעות נתוני מיקום משירות אינטרנט.

ה-Codelab הזה מתמקד בהוספת מפת Google לאפליקציית Flutter. מונחים לא רלוונטיים ובלוקים של קוד עם הפרדה מודגשת, כך שאפשר פשוט להעתיק ולהדביק אותם.

מה היית רוצה ללמוד מ-Codelab הזה?

הנושא חדש ורציתי לקבל סקירה כללית טובה. יש לי מושג בנושא הזה, אבל אני רוצה לרענן את הידע שלי. אני רוצה קוד לדוגמה לשימוש בפרויקט שלי. אני רוצה הסבר למשהו ספציפי.

2. הגדרת הסביבה של Flutter

כדי להשלים את שיעור ה-Lab הזה אתם צריכים שני רכיבי תוכנה: Flutter SDK וכלי עריכה. ההנחה של Codelab היא Android Studio, אבל אתם יכולים להשתמש בעורך המועדף.

אפשר להריץ את ה-Codelab הזה באמצעות כל אחד מהמכשירים הבאים:

  • מכשיר פיזי (Android או iOS) שמחובר למחשב ומוגדר למצב פיתוח.
  • הסימולטור של iOS. (יש צורך בהתקנת כלי Xcode).
  • האמולטור של Android. (נדרשת הגדרה ב-Android Studio.)

3. תחילת העבודה

תחילת העבודה עם Flutter

הדרך הקלה ביותר להתחיל להשתמש ב-Flutter היא להשתמש בכלי שורת הפקודה Flutter כדי ליצור את כל הקוד הנדרש לחוויה פשוטה לתחילת העבודה.

$ 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.

הוספת הפלאגין Flutter של מפות Google כתלות

באמצעות חבילות Pub אפשר להוסיף יכולות נוספות לאפליקציית Flutter. ב-Codelab הזה כדי להציג את הפלאגין של Google Maps Flutter, מריצים את הפקודה הבאה מספריית הפרויקט.

$ 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.

הגדרה של iOS platform

כדי לקבל את הגרסה העדכנית ביותר של ה-SDK של מפות Google ב-iOS, נדרשת גרסת פלטפורמה מינימלית של iOS 14. משנים את החלק העליון של קובץ התצורה ios/Podfile באופן הבא.

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'

הגדרה של Android minSDK

כדי להשתמש ב-SDK של מפות Google ב-Android, צריך להגדיר את הערך של minSdk ל-21. משנים את קובץ התצורה android/app/build.gradle באופן הבא.

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. הוספה של מפות Google לאפליקציה

הכול תלוי במפתחות API

כדי להשתמש במפות Google באפליקציית Flutter, עליך להגדיר פרויקט API באמצעות הפלטפורמה של מפות Google, בהתאם ל-SDK של מפות Google לשימוש במפתח API של Android, SDK של מפות ל-iOS' שימוש במפתח API ובשימוש במפתח API של מפות Google JavaScript. אם משתמשים במפתחות API, מבצעים את השלבים הבאים כדי להגדיר גם אפליקציות ל-Android וגם ל-iOS.

הוספת מפתח API לאפליקציה ל-Android

כדי להוסיף מפתח API לאפליקציה ל-Android, צריך לערוך את הקובץ AndroidManifest.xml ב-android/app/src/main. מוסיפים כניסה אחת מסוג meta-data שמכילה את מפתח ה-API שנוצר בשלב הקודם בתוך הצומת application.

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>

הוספת מפתח API לאפליקציה ל-iOS

כדי להוסיף מפתח API לאפליקציה ל-iOS, צריך לערוך את הקובץ AppDelegate.swift ב-ios/Runner. שלא כמו ב-Android, כדי להוסיף מפתח API ב-iOS צריך לבצע שינויים בקוד המקור של האפליקציה Runner. App לקישור הוא הסינגלון העיקרי שנכלל בתהליך האתחול של האפליקציה.

יש לבצע שני שינויים בקובץ הזה. קודם כל צריך להוסיף הצהרת #import כדי למשוך את הכותרות של מפות Google, ואז להפעיל את השיטה provideAPIKey() של הסינגלטון GMSServices. מפתח ה-API הזה מאפשר למפות Google להציג קטעי מפה בצורה נכונה.

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)
  }
}

הוספה של מפתח API לאפליקציית אינטרנט

כדי להוסיף מפתח API לאפליקציית האינטרנט, צריך לערוך את הקובץ index.html ב-web. צריך להוסיף הפניה לסקריפט ה-JavaScript של מפות Google בקטע head, באמצעות מפתח ה-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>

הצגת מפה למסך

עכשיו הגיע הזמן להציג מפה במסך. מחליפים את התוכן של lib/main.dart בערך הבא.

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,
          ),
        ),
      ),
    );
  }
}

הפעלת האפליקציה

הפעילו את אפליקציית Flutter ב-iOS או ב-Android כדי לראות תצוגת מפה אחת, שמתמקדת בפורטלנד. לחלופין, מריצים אמולטור של Android או סימולטור של iOS. אתם יכולים לשנות את מרכז המפה כך שמייצג את עיר המגורים שלכם או מקום שחשוב לכם.

$ flutter run

צילום מסך של אפליקציית Flutter עם מפת Google שפועלת בסימולטור ב-iPhone

צילום מסך של אפליקציית Flutter עם מפת Google שפועלת באמולטור Android

5. המיקום של Google במפה

ל-Google יש משרדים רבים ברחבי העולם, מצפון אמריקה, אמריקה הלטינית, אירופה, אסיה-פסיפיק ועד אפריקה המזרח התיכון. היתרון של המפות האלה הוא העובדה שהם כוללים נקודת קצה (endpoint) של API, שקל להשתמש בה, כדי לספק את פרטי המיקום של המשרד בפורמט JSON. בשלב הזה תציגו את מיקומי המשרדים האלה במפה. בשלב הזה תשתמשו ביצירת קוד כדי לנתח JSON.

מוסיפים לפרויקט שלושה יחסי תלות חדשים של Flutter. מוסיפים את החבילה http לביצוע בקשות HTTP בקלות, את json_serializable ואת json_annotation להצהרה על מבנה אובייקטים לייצוג מסמכי JSON, מוסיפים את build_runner לתמיכה ביצירת קוד.

$ 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.

ניתוח JSON באמצעות יצירת קוד

יכול להיות שהבחנתם שלנתוני JSON שמוחזרים מנקודת הקצה ב-API יש מבנה קבוע. כדאי ליצור את הקוד כדי לארגן את הנתונים האלה לתוך אובייקטים שבהם תוכלו להשתמש בקוד.

בספרייה lib/src, יוצרים קובץ locations.dart ומתארים את המבנה של נתוני ה-JSON שמוחזרים באופן הבא:

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>,
  );
}

אחרי הוספת הקוד הזה, סביבת הפיתוח המשולבת (אם השתמשת בה) אמורה להציג שרבוטים אדומים כי הוא מפנה לקובץ אח שאינו קיים, locations.g.dart. הקובץ שנוצר מבצע המרה בין מבני JSON לא מוטמעים לאובייקטים בעלי שם. כדי ליצור אותו, מריצים את build_runner באופן הבא:

$ 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)

עכשיו הקוד אמור לנתח שוב בצורה חלקה. בשלב הבא צריך להוסיף את הקובץ locations.json החלופי, שמשמש בפונקציה getGoogleOffices. אחת הסיבות להכללה של החלופה הזו היא שהנתונים הסטטיים שנטענים בפונקציה הזו מוצגים ללא כותרות CORS, ולכן הם לא ייטענו בדפדפן אינטרנט. לאפליקציות Flutter ל-Android ול-iOS אין צורך בכותרות CORS, אבל הגישה לחבילת הגלישה עלולה להיות קטנונית בזמנים הטובים ביותר.

עוברים אל https://about.google/static/data/locations.json בדפדפן ושומרים את התוכן בספריית הנכסים הדיגיטליים. לחלופין, אתם יכולים להשתמש בשורת הפקודה הבאה.

$ 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

אחרי שהורדתם את קובץ הנכס, צריך להוסיף אותו לקטע Flutter בקובץ pubspec.yaml.

pubspec.yaml

flutter:
  uses-material-design: true

  assets:
    - assets/locations.json

משנים את הקובץ main.dart כדי לבקש את נתוני המפה, ואז משתמשים במידע שהוחזר כדי להוסיף משרדים למפה:

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(),
        ),
      ),
    );
  }
}

הקוד הזה מבצע מספר פעולות:

  • ב-_onMapCreated, נעשה שימוש בקוד ניתוח ה-JSON מהשלב הקודם, await עד שנטען. אחר כך הוא משתמש בנתונים שמוחזרים כדי ליצור ערכי Marker בתוך קריאה חוזרת של setState(). לאחר שהאפליקציה תקבל סמנים חדשים, צריך להגדיר את דגלי המדינה Flutter כדי לצבוע מחדש את המסך, וכך להציג את מיקומי המשרדים.
  • הסמנים מאוחסנים במסגרת Map שמשויכת לווידג'ט GoogleMap. הפעולה הזו מקשרת את הסמנים למפה הנכונה. אפשר כמובן להשתמש בכמה מפות ולהציג סמנים שונים בכל אחת מהן.

צילום מסך של אפליקציית Flutter עם מפת Google שפועלת בסימולטור של iPhone, עם הדגשה של Mountain View

הנה צילום מסך של מה שהשגת. בשלב הזה ניתן להוסיף הרבה תוספות מעניינות. לדוגמה, תוכלו להוסיף תצוגת רשימה של המשרדים להזיז את המפה או לשנות את מרחק התצוגה שלה כשמשתמש לוחץ על משרד, אבל כמו שהוא אומר, התרגיל הזה נשאר לקורא!

6. השלבים הבאים

מעולה!

סיימתם את ה-Codelab ובנית אפליקציה של Flutter באמצעות מפת Google! הייתה לך אינטראקציה גם עם שירות אינטרנט מסוג JSON.

השלבים הבאים נוספים

ה-Codelab הזה יצר חוויה שממחישה מספר נקודות במפה. יש מספר אפליקציות לנייד שמסתמכות על היכולת הזו כדי לענות על צרכים שונים של משתמשים. יש מקורות מידע נוספים שיעזרו לך לבצע את התהליך הזה: