🗺️

【Flutter】Google Maps URLs ケース毎の挙動確認

2024/06/23に公開

概要

アプリ内で特定のボタンなどをタップしたら、外部のGoogle Maps アプリや、アプリが未インストールの場合ブラウザが開くようにする際に呼び出すURLの挙動を細かく確認していきたいと思います。

検証した環境

※ この記事では以下の環境でのみ確認しています。なのでもしかしたら他の環境だと動作が異なる可能性もあります。

  • iOS
    • iOS 17.4 iPhone 15 Pro Simulator
    • iOS 17.5.1 iPhone 13 Pro 実機
  • Android
    • Android 14.0 arm64-v8a Simulator (Pixel 6 Pro)
    • Android 15.0 arm64-v8a (Pixel 8 Pro)

どんなURLを呼び出せば良いか?

https://developers.google.com/maps/documentation/urls/get-started?hl=ja

↑を参考にすると以下のようなURLを呼び出せば良さそうです。試しにまずモバイル端末のブラウザで開いて挙動を比較してみました。

https://www.google.com/maps/search/?api=1&query=35.681333175036556,139.76653638895476

↑の検索するURLの他にナビやストリートビュー パノラマを表示するなどありますが、今回は検索するURLで試してみます。

モバイル端末上のブラウザでURLを開いた場合

  • iOSの場合 (Safari)
    • Google Mapアプリがインストールされている場合 (実機で確認)
      • SafariでGoogle Mapが開く
      • 「アプリで開く」をタップするとGoogle Mapアプリが開く
    • Google Mapアプリがインストールされていない場合
      • SafariでGoogle Mapが開く
      • 「アプリで開く」が表示されるがタップするとエラーになる
        image1.gif
  • Androidの場合 (Chrome)
    • Google Mapアプリがインストールされている場合
      • ChromeでGoogle Mapが開き、アプリで開くを選択した場合Google Mapアプリが開く
        image2.gif
    • Google Mapアプリがインストールされていない場合
      • ChromeでGoogle Mapが開き、アプリで開くを選択した場合Google Playにとばされる
        image3.gif

アプリからURLを開いた場合

次に実際にサンプルアプリを作成してアプリ内からURLを開いてみたいと思います。

サンプルプロジェクト作成

検証用のFlutterアプリを作成します。

$ mkdir google_maps_flutter_sample
$ cd google_maps_flutter_sample
$ fvm use 3.22.2 --force
$ fvm flutter create . --org com.xxxx.google_map_flutter_sample -e

次に、以下パッケージを導入して、ボタン押したら上記のURLを開くようにしてみたいと思います。

https://pub.dev/packages/url_launcher

  • url_launcherパッケージ追加
flutter pub add url_launcher
  • 又は pubspec.yaml に以下を追加
dependencies:
  url_launcher: ^6.3.0
  • 次に以下のFlutterアプリの画面を作成し検証していきます
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';

class MapUrlButton extends StatelessWidget {
  const MapUrlButton({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Map URL Button')),
      body: const Center(
        child: Text("Tap the floating action button to open a map URL."),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          final uri = Uri.parse(
              "https://www.google.com/maps/search/?api=1&query=35.681333175036556,139.76653638895476");
          if (await canLaunchUrl(uri)) {
            await launchUrl(uri);
          }
        },
        child: const Icon(Icons.map),
      ),
    );
  }
}
  • iOSの場合
    • Google Mapがインストールされている場合 (実機で確認)
      • アプリ内ブラウザでGoogle Mapが開く
      • 「アプリで開く」をタップするとGoogle Mapアプリが開く
    • Google Mapがインストールされていない場合
      • アプリ内ブラウザでGoogle Mapが開く
      • 「アプリで開く」が表示されるがタップするとエラーになる
        image4.gif
  • Androidの場合
    • Google Mapがインストールされている場合
      • Google Mapアプリが開く
        image5.gif
    • Google Mapがインストールされていない場合
      • url_launcherの canLaunchUrl のチェックがある場合、チェックに引っかかっる
        image6.gif
      • url_launcherの canLaunchUrl のチェックがない場合、アプリ内ブラウザが開く
        image7.gif

ここで注目すべき点がiOSでGoogle Maps アプリがインストールされているのにも関わらず、アプリ内ブラウザが開いています。
この場合 launchUrlmode オプションを LaunchMode.externalApplication にする事でGoogle Maps アプリが開くようになります。

ちなみに LaunchMode.externalApplication にすると AndroidでGoogle Maps アプリがインストールされていない場合、アプリ内ブラウザではなくChromeが開きます。

アプリ内にGoogle Mapを使っている場合の挙動

さらにFlutterアプリで google_maps_flutter を使っている場合の挙動を確認してみようと思います。

  • google_maps_flutter パッケージ追加
fvm flutter pub add google_maps_flutter

又は pubspec.yaml に以下を追加

dependencies:
  google_maps_flutter: ^2.7.0
  • APIキー取得

こちらのページへ移動し、プロジェクトを選択又は新規にGCPプロジェクト作成し、選択します。

次に「認証情報を作成」>「APIキー」を選択します。

image8.png

次に作成したAPIキーの名前と、アプリケーションの制限の設定で、「Androidアプリ」を選択します。APIの制限は今回お試し用なのでこのままでいきます。

image9.png

次に同じようにAPIキーを作成し、アプリケーションの制限の設定で「iOSアプリ」を選択しときます。

これで実際に運用する時と同じ構成でAndroidアプリ用のAPIキーとiOSアプリ用のAPIキーが作成されました。

  • プロジェクトへの反映は↓を参照してください。

https://zenn.dev/slowhand/articles/f4e4e092f9b72b

  • 検証用に以下の画面を作成します
import 'dart:async';

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

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

  
  State<MapUrlInside> createState() => BasicMapState();
}

class BasicMapState extends State<MapUrlInside> {
  final Completer<GoogleMapController> _controller =
      Completer<GoogleMapController>();

  static const CameraPosition _initialCameraPosition = CameraPosition(
    target: LatLng(35.68123428932672, 139.76714355230686),
    zoom: 14.4746,
  );

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Map Url Inside')),
      body: GoogleMap(
        mapType: MapType.normal,
        initialCameraPosition: _initialCameraPosition,
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
        },
        markers: {
          Marker(
            markerId: const MarkerId("Tokyo Station"),
            position: const LatLng(35.681333175036556, 139.76653638895476),
            infoWindow: const InfoWindow(title: "Tokyo Station"),
            onTap: () async {
              final uri = Uri.parse(
                  "https://www.google.com/maps/search/?api=1&query=35.681333175036556,139.76653638895476");
              if (await canLaunchUrl(uri)) {
                await launchUrl(uri);
              }
            },
          ),
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          final uri = Uri.parse(
              "https://www.google.com/maps/search/?api=1&query=35.681333175036556,139.76653638895476");
          if (await canLaunchUrl(uri)) {
            await launchUrl(uri);
          }
        },
        child: const Icon(Icons.map),
      ),
    );
  }
}
  • iOSの場合
    • Google Mapがインストールされている場合 (実機で確認)
      • FABでもMarkerでも挙動は同じ
      • アプリ内ブラウザでGoogle Mapが開く
      • 「アプリで開く」をタップするとGoogle Mapアプリが開く
    • Google Mapがインストールされていない場合
      • FABでもMarkerでも挙動は同じ
      • アプリ内ブラウザでGoogle Mapが開く
      • 「アプリで開く」が表示されるがタップするとエラーになる
        image11.gif
  • Androidの場合
    • Google Mapがインストールされている場合
      • FABでもMarkerでも挙動は同じ
      • Google Mapアプリが開く
        image13.gif
    • Google Mapがインストールされていない場合
      • Makerの場合
        • mapToolbarEnabledtrue にして検証
        • アプリ内のMap上にToolbarが表示される (↓)
          image14.png
        • Toolbarタップでエラーが表示される
          image15.gif
      • FABの場合
        • url_launcherの canLaunchUrl のチェックがある場合、チェックに引っかかっる
          image16.gif
        • url_launcherの canLaunchUrl のチェックがない場合、アプリ内ブラウザが開く
          image17.gif

参考URL

https://naipaka.hatenablog.com/entry/2021/08/05/091411

Discussion