LoginSignup
26
20

More than 3 years have passed since last update.

[Flutter]FlutterアプリにGoogleマップを追加する-ドキュメント翻訳

Last updated at Posted at 2019-06-03

はじめに

こちらの翻訳となります。
https://codelabs.developers.google.com/codelabs/google-maps-in-flutter/index.html?index=..%2F..index#0

Flutterは、記録的な速さでiOSとAndroidで高品質のネイティブ体験を作り出すためのGoogleのモバイルアプリSDKです。

Google Maps Flutter pluginは、あなたのアプリケーションに、Googleマップのデータに基づいてマップを追加することができます。
このプラグインは、Googleマップサーバーへのアクセス、地図の表示、クリックやドラッグなどのユーザージェスチャーへの応答を自動的に処理します。
地図にマーカーを追加することもできます。
これらのオブジェクトは、地図の場所に関する追加情報を提供し、ユーザーが地図をインタラクティブに使えるようにします。

構築するもの

このコードラボでは、Flutter SDKを使用してGoogle Mapを搭載したモバイルアプリを作成します。
あなたのアプリは:
- Googleマップを表示する
- Webサービスから地図データを取得する
- データを地図上のマーカーとして表示する

ce32c492a689e181.png (425.9 kB)


フラッターとは

フラッターは:
- 迅速な開発:Stateful Hot Reloadを使用して、ミリ秒でAndroidおよびiOSアプリケーションをbuildできます。
- 表現力と柔軟性:ネイティブのエンドユーザーエクスペリエンスに重点を置いて、機能を迅速にリリースします。
- iOSとAndroidの両方でのネイティブパフォーマンス:Flutterのウィジェットには、スクロール、ナビゲーション、アイコン、フォントなど、重要なプラットフォームの違いがすべて組み込まれており、ネイティブのパフォーマンスを最大限に引き出すことができます。

グーグルマップは:
- 世界の99%のカバレッジ:200以上の国と地域の信頼できるデータで構築します。
- 毎日2500万更新:正確で、リアルタイムな位置情報を。
- 毎月10億人のアクティブユーザー:Googleマップのインフラストラクチャに支えられて、自信を持って拡張できます。

このコードラボでは、iOSとAndroidの両方のFlutterアプリでGoogleマップエクスペリエンスを作成する方法について説明します。

あなたが学ぶもの

  • 新しいFlutterアプリケーションを作成する方法
  • Google Maps Flutterプラグインを設定する方法
  • Webサービスからの位置データを使用して、マーカーを地図に追加する方法

このcodelabは、FlutterアプリにGoogleマップを追加することに焦点を当てています。
関連性のない概念やコードブロックについては、まとめてコピーして貼り付けることができるように提供されています。

Flutter環境をセットアップする

このチュートリアルを行うには、Flutter SDK とエディタの 2つのソフトウェアが必要です。
このコードラボはAndroid Studioを想定していますが、好みのエディタを使用できます。

このコードラボは、以下のデバイスを使用して実行できます。
- コンピュータに接続された物理デバイス(AndroidまたはiOS)。
- iOSのシミュレーター。(Xcodeツールをインストールする必要があります。)
- Androidのエミュレータ。(Android Studioでの設定が必要です。)

はじめに

Flutterを始めよう

Flutterを使い始める最も簡単な方法は、flutterコマンドラインツールを使用して、
開始するために必要なすべてのコードを作成することです。

$ flutter create google_maps_in_flutter
Creating project google_maps_in_flutter...
[Listing of created files elided]
Running "flutter packages get" in google_maps_in_flutter...         6.1s
Wrote 66 files.

All done!
[✓] Flutter (Channel dev, v1.5.0, on Mac OS X 10.14.3 18D109, locale en-AU)
[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
[✓] iOS toolchain - develop for iOS devices (Xcode 10.2)
[✓] Android Studio is fully installed. (version 3.1)
[✓] IntelliJ IDEA Community Edition (version 2018.3.5)
[✓] VS Code (version 1.33.1)
[✓] Connected device is fully installed. (1 available)

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.

依存関係としてGoogle Maps Flutterプラグインを追加する

Flutterアプリに機能を追加するには、Pubパッケージを使うのはが簡単です。
このコードラボでは、pubspec.yamlファイルに1行追加して、Google Maps Flutterプラグインを紹介します。

name: google_maps_in_flutter
description: A new Flutter project.
version: 1.0.0+1

environment:
  sdk: ">=2.2.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  # Add the following line
  google_maps_flutter: ^0.5.11

flutter:
  uses-material-design: true

次のコマンドでパッケージをダウンロードしてください。

$ flutter packages get
Running "flutter packages get" in google_maps_in_flutter...         0.9s 

アプリにGoogleマップを追加する

APIキーについて

FlutterアプリでGoogle Mapsを使用するには、Android用のMaps SDKのGet APIキーと、
Maps SDK for iOSのGet APIのキープロセスに従って、Google Maps PlatformでAPIプロジェクトを設定する必要があります。
APIキーを入手したら、次の手順を実行してAndroidとiOSの両方のアプリケーションを設定します。

AndroidアプリのAPIキーを追加する

AndroidアプリにAPIキーを追加するには、android/app/src/mainにあるAndroidManifest.xmlファイルを編集します。
前の手順で作成したAPIキーを含む単一のメタデータエントリを追加します。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.google_maps_in_flutter">

    <application
        android:name="io.flutter.app.FlutterApplication"
        android:label="google_maps_in_flutter"
        android:icon="@mipmap/ic_launcher">

        <!-- ここにAPIキーを追加 -->
        <meta-data android:name="com.google.android.geo.API_KEY"
               android:value="YOUR-KEY-HERE"/>

        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <meta-data
                android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
                android:value="true" />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

iOSアプリのAPIキーを追加する

iOSアプリにAPIキーを追加するには、ios/RunnerAppDelegate.mファイルを編集します。
Androidとは異なり、iOSにAPIキーを追加するには、Runnerアプリのソースコードを変更する必要があります。
AppDelegateは、アプリの初期化プロセスの一部である重要なシングルトンです。

このファイルに2つの変更を加えます。
まず、#importステートメントを追加してGoogle Mapsヘッダーを取得してから、
GMSServicesシングルトンのprovideAPIKey()メソッドを呼び出します。
このAPIキーにより、マップタイルを正しく表示できます。

#import "AppDelegate.h"
#import "GeneratedPluginRegistrant.h"
// Add the following import.
#import "GoogleMaps/GoogleMaps.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];
  // Add the following line, with your API key
  [GMSServices provideAPIKey: @"YOUR-API-KEY"];
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

@end

また、ios/Runner/Info.plistに設定を追加する必要があります。
これにより、iOS上のFlutterはシングルスレッドモードになります。
これはプラットフォームビューの埋め込みが機能するために必要です。
この技術的な制限は現在処理中であり、Googleマップがデベロッパープレビューから出る前に解除される予定です。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <!-- Add the following entry, from here, -->
        <key>io.flutter.embedded_views_preview</key>
        <true/>
        <!-- to here. -->
        <key>CFBundleDevelopmentRegion</key>
        <string>en</string>
        <key>CFBundleExecutable</key>
        <string>$(EXECUTABLE_NAME)</string>
        <key>CFBundleIdentifier</key>
        <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
        <key>CFBundleInfoDictionaryVersion</key>
        <string>6.0</string>
        <key>CFBundleName</key>
        <string>google_maps_in_flutter</string>
        <key>CFBundlePackageType</key>
        <string>APPL</string>
        <key>CFBundleShortVersionString</key>
        <string>$(FLUTTER_BUILD_NAME)</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
        <string>$(FLUTTER_BUILD_NUMBER)</string>
        <key>LSRequiresIPhoneOS</key>
        <true/>
        <key>UILaunchStoryboardName</key>
        <string>LaunchScreen</string>
        <key>UIMainStoryboardFile</key>
        <string>Main</string>
        <key>UISupportedInterfaceOrientations</key>
        <array>
                <string>UIInterfaceOrientationPortrait</string>
                <string>UIInterfaceOrientationLandscapeLeft</string>
                <string>UIInterfaceOrientationLandscapeRight</string>
        </array>
        <key>UISupportedInterfaceOrientations~ipad</key>
        <array>
                <string>UIInterfaceOrientationPortrait</string>
                <string>UIInterfaceOrientationPortraitUpsideDown</string>
                <string>UIInterfaceOrientationLandscapeLeft</string>
                <string>UIInterfaceOrientationLandscapeRight</string>
        </array>
        <key>UIViewControllerBasedStatusBarAppearance</key>
        <false/>
</dict>
</plist>

画面に地図を表示する

今度は画面に地図を表示します。 次のようにlib/main.dartを更新します。

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

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  GoogleMapController mapController;

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

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

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

アプリを実行する

iOSまたはAndroidのどちらかでFlutterアプリを実行すると、ポートランドを中心としたマップビューが表示されます。
あなたの故郷やあなたにとって重要な場所を表すために地図の中心を自由に変更してください..

android iOS
6b2f9d88226616f6.png (393.4 kB) e9d9d7f8c362b546.png (362.1 kB)

Google Maps SDK for iOS 3.0へのアップグレード

最新バージョンのMaps for iOSを使用する

前の手順でiOSでアプリを実行しているときに、Google Maps SDK for iOSプラグインのバージョンが古いという警告が
コンソールに表示されることがあります。
これは、最小限バージョンがあっていないためです。
Flautterは、iOSバージョン8以上をサポートしていますが、iOS用GoogleマップSDKの最新バージョンは、iOSバージョン9をサポートしています。
CocoaPodsがデフォルトでインストールしたバージョンは、
iOSバージョン8をサポートするiOS用GoogleマップSDKの最後のバージョンでした。
このステップでは、iOS用Google Maps SDKの最新バージョンを使用するようにiOS Runnerプロジェクトを変更します。

この手順はiOSにのみ適用され、Xcodeを使用してiOSターゲットを変更します。
WindowsまたはLinuxを使用している場合、この手順はあなたには適用されません。 次のステップに進んでください。

CocoaPodでプラットフォームを設定する

ios/Podfileを編集して最小のプラットフォームバージョンを宣言します。

# Uncomment the following line
platform :ios, '9.0'

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

project 'Runner', {
  'Debug' => :debug,
  'Profile' => :release,
  'Release' => :release,
}

# And ignore the rest of this file... 

CocoaPod依存関係を更新する

CocoaPodsを実行して、iOS用のGoogle Maps SDKの最新バージョンを取得します。

$ (cd ios && pod update)
Analyzing dependencies
Fetching podspec for `Flutter` from `.symlinks/flutter/ios`
Fetching podspec for `google_maps_flutter` from `.symlinks/plugins/google_maps_flutter/ios`
Downloading dependencies
Using Flutter (1.0.0)
Installing GoogleMaps 3.0.3
Using google_maps_flutter (0.0.1)
Generating Pods project
Integrating client project
Pod installation complete! There are 2 dependencies from the Podfile and 3 total pods installed.

deployのターゲットをXcodeに設定する

iOS Runner Xcodeプロジェクトでdeployment targeを設定して、RunnerとGoogleマップのバイナリバージョンが一致するようにします。 次のようにコマンドラインからRunnerプロジェクトを開きます。

$ open ios/Runner.xcworkspace/

これにより、iOS Runnerプロジェクト用のXcodeワークスペースが開きます。
Generalからdeployment targeを設定します。

dc5ceca8418fe726.png (151.9 kB)

もう一度アプリを実行する

今回はiOS用のGoogleマップSDKの最新バージョンを使用して、iOSでFlutterアプリを実行します。

$ flutter run
Launching lib/main.dart on iPhone XR in debug mode...
Running pod install...                                              1.2s
Running Xcode build...                                                  
 ├─Assembling Flutter resources...                           1.3s
 └─Compiling, linking and signing...                         4.5s
Xcode build done.                                            7.6s
Google Maps SDK for iOS version: 3.0.33124.0                            
Syncing files to device iPhone XR...                             1,267ms

🔥  To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".

Googleのオフィスを地図に載せる

Googleには、北米、ラテンアメリカ、ヨーロッパ、アジア太平洋、アフリカ、中東など、世界中に多数のオフィスがあります。
これらのマップを調べてみると、オフィイスの位置情報をJSON形式で提供するための使いやすいAPIエンドポイントがあります。
このステップでは、これらのオフィスの場所を地図上に配置します。

コードベースを拡大したら、Dartが提供するツールを使用してコードを読みやすく保守しやすくします。
このステップでは、コード生成を使用してJSONを解析し、潜在的なコードの匂いを浮き彫りにするコードリンティングを使用します。

これらの機能を使用するには、pubspec.yamlファイルにいくつかの新しい依存関係を追加してください。
これらの依存関係は、httpリクエストへのアクセス、JSON構文解析を機械化する機能、
Googleで広く使用されている便利なlintルールの設定、およびそれらすべてを結び付けるビルドランナーを提供します。
次のようにpubspec.yamlファイルの依存関係を編集します。

name: google_maps_in_flutter
description: A new Flutter project.
version: 1.0.0+1

environment:
  sdk: ">=2.2.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  google_maps_flutter: ^0.5.11
  # 次の2行を追加してください
  http: ^0.12.0+1
  json_serializable: ^2.0.2

# 次の3行を追加してください
dev_dependencies:
  pedantic: ^1.4.0
  build_runner: ^1.2.7

flutter:
  uses-material-design: true

これらの新しい依存関係を取得し、次の段階に向けてアプリを準備するには、コマンドラインでflutterパッケージを実行します。

$ flutter packages get 
Running "flutter packages get" in google_maps_in_flutter...         0.5s

提供されているツールを使用する

近年プログラミング言語に追加された優れた機能のうちの2つは、コードフォーマットの実用的なデフォルトと、
既知の問題のあるコードパターンのリンティングです。
コードフォーマットの場合は、flutter formatを使用できますが、特定のキーの組み合わせまたはファイルの保存時にこれを実行するようにコードエディタを設定することもできます。

$ flutter format .
Formatting directory .:
Unchanged test/widget_test.dart
Skipping link ios/Pods/Headers/Public/google_maps_flutter/GoogleMapMarkerController.h
Skipping link ios/Pods/Headers/Public/google_maps_flutter/GoogleMapController.h
Skipping link ios/Pods/Headers/Public/google_maps_flutter/GoogleMapsPlugin.h
Skipping link ios/Pods/Headers/Private/google_maps_flutter/GoogleMapMarkerController.h
Skipping link ios/Pods/Headers/Private/google_maps_flutter/GoogleMapController.h
Skipping link ios/Pods/Headers/Private/google_maps_flutter/GoogleMapsPlugin.h
Skipping link ios/.symlinks/plugins/google_maps_flutter
Skipping link ios/.symlinks/flutter
Unchanged lib/main.dart
Unchanged lib/src/locations.g.dart
Unchanged lib/src/locations.dart
Skipping hidden path .dart_tool

リンティングのために、Dartはカスタマイズされたコードリンターを設定する機能を提供します。
このステップでは、アプリにリンターを追加しますが、使用可能なlintsの一覧はLinter for Dartのドキュメントで指定されています。

analysis_options.yamlというファイルをプロジェクトのルートに追加し、以下の内容を記入します。

include: package:pedantic/analysis_options.yaml

analyzer:
  exclude:
    - lib/src/locations.g.dart

linter:
  rules:
    - always_declare_return_types
    - camel_case_types
    - empty_constructor_bodies
    - annotate_overrides
    - avoid_init_to_null
    - constant_identifier_names
    - one_member_abstracts
    - slash_for_doc_comments
    - sort_constructors_first
    - unnecessary_brace_in_string_interps

最初の行には、Googleで広く使用されているデフォルトのルールセットが含まれています。
リンタールールのセクションでは、可能なことについて説明しています。
excludeはまだ生成されていないファイルを参照しています。
lintルールを実行するには、次のようにコードをアナライズしてください。

$ flutter analyze
Analyzing google_maps_in_flutter...                                     
No issues found! (ran in 1.8s)

アナライザが警告を出しても心配しないでください、いまからそれらを修正します。

コード生成によるJSONの構文解析

APIエンドポイントから返されたJSONデータには規則的な構造があることに気付くかもしれません。
そのデータをコードで使用できるオブジェクトにマーシャリングするコードを生成すると便利です。
DartはJSONデータのシリアル化を解除する(build-it-yourselfからデータの署名やbuilt_valueの使用まで)ためのさまざまなオプションを提供しますが、このステップではJSONアノテーションを使用します。

lib/srcディレクトリにlocations.dartファイルを作成し、返されるJSONデータの構造を次のように記述します。

import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:json_annotation/json_annotation.dart';

part 'locations.g.dart';

@JsonSerializable()
class LatLng {
  LatLng({
    this.lat,
    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({
    this.coords,
    this.id,
    this.name,
    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({
    this.address,
    this.id,
    this.image,
    this.lat,
    this.lng,
    this.name,
    this.phone,
    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({
    this.offices,
    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';

  // Googleのオフィスの場所を取得する
  final response = await http.get(googleLocationsURL);
  if (response.statusCode == 200) {
    return Locations.fromJson(json.decode(response.body));
  } else {
    throw HttpException(
        'Unexpected status code ${response.statusCode}:'
        ' ${response.reasonPhrase}',
        uri: Uri.parse(googleLocationsURL));
  }
}

このコードを追加すると、存在しないファイルのlocations.g.dartを参照しているので、
IDE(使用している場合)には赤い波線が表示されます。
この生成されたファイルは、型なしのJSON構造と名前付きオブジェクトの間で変換を行います。
build_runnerを実行してそれを作成します。

$ flutter packages pub run build_runner build
[INFO] Generating build script...
[INFO] Generating build script completed, took 291ms

[INFO] Initializing inputs
[INFO] Reading cached asset graph...
[INFO] Reading cached asset graph completed, took 65ms

[INFO] Checking for updates since last build...
[INFO] Checking for updates since last build completed, took 595ms

[INFO] Running build...
[INFO] 1.2s elapsed, 0/1 actions completed.
[INFO] Running build completed, took 1.2s

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

[INFO] Succeeded after 1.2s with 1 outputs (1 actions)

あなたのコードは再びきれいにアナライズされるはずです。

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(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState 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) => MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: const Text('Google Office Locations'),
            backgroundColor: Colors.green[700],
          ),
          body: GoogleMap(
            onMapCreated: _onMapCreated,
            initialCameraPosition: CameraPosition(
              target: const LatLng(0, 0),
              zoom: 2,
            ),
            markers: _markers.values.toSet(),
          ),
        ),
      );
}

このコードはいくつかの操作を実行します。
- _onMapCreatedでは、前の手順のJSON解析コードを使用し、ロードされるまで待機します。 その後、返されたデータを使用してsetState()コールバック内にマーカーを作成します。 アプリが新しいマーカーを受信すると、setStateは画面を再描画するようにFlutterにフラグを立て、オフィスの場所を表示します。
- マーカーは、GoogleMapウィジェットに関連付けられている地図に保存されます。 これにより、マーカーが正しいマップにリンクされます。 もちろん、複数の地図を持ち、それぞれに異なるマーカーを表示することもできます。

ce32c492a689e181 (1).png (425.9 kB)

これがあなたが達成したことのスクリーンショットです。
ここまでくれば、多くの機能を追加することができます。
たとえば、
ユーザーがオフィスをクリックしたときに地図を移動してズームするオフィスのリストビューを追加できます。
それを実現するのはあなたの力で!

次のステップ

おめでとうございます。

コードラボを完成させ、Googleマップを使ってFlutterアプリを作成しました。
また、インタラクティブなJSON Webサービスを作成しました。

その他の次のステップ

このコードラボは、地図上のいくつかの点を視覚化させる経験をしました。
この機能を基に、さまざまなユーザーのニーズに応えるためのモバイルアプリがいくつもあります。

チュートリアルでlintを入れると余計混乱するかもと思いつつ、コードラボの演習にできるだけ近い形で翻訳しました。
誤字や、分かりにく箇所などありましたらご連絡お願いします。

26
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
20