【Flutter】Google Maps URLs ケース毎の挙動確認
概要
アプリ内で特定のボタンなどをタップしたら、外部の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を呼び出せば良いか?
↑を参考にすると以下のような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が開く
- 「アプリで開く」が表示されるがタップするとエラーになる
- Google Mapアプリがインストールされている場合 (実機で確認)
- Androidの場合 (Chrome)
- Google Mapアプリがインストールされている場合
- ChromeでGoogle Mapが開き、アプリで開くを選択した場合Google Mapアプリが開く
- ChromeでGoogle Mapが開き、アプリで開くを選択した場合Google Mapアプリが開く
- Google Mapアプリがインストールされていない場合
- ChromeでGoogle Mapが開き、アプリで開くを選択した場合Google Playにとばされる
- ChromeでGoogle Mapが開き、アプリで開くを選択した場合Google Playにとばされる
- Google Mapアプリがインストールされている場合
アプリから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を開くようにしてみたいと思います。
- 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が開く
- 「アプリで開く」が表示されるがタップするとエラーになる
- Google Mapがインストールされている場合 (実機で確認)
- Androidの場合
- Google Mapがインストールされている場合
- Google Mapアプリが開く
- Google Mapアプリが開く
- Google Mapがインストールされていない場合
- url_launcherの
canLaunchUrl
のチェックがある場合、チェックに引っかかっる
- url_launcherの
canLaunchUrl
のチェックがない場合、アプリ内ブラウザが開く
- url_launcherの
- Google Mapがインストールされている場合
ここで注目すべき点がiOSでGoogle Maps アプリがインストールされているのにも関わらず、アプリ内ブラウザが開いています。
この場合 launchUrl
の mode
オプションを 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キー」を選択します。
次に作成したAPIキーの名前と、アプリケーションの制限の設定で、「Androidアプリ」を選択します。APIの制限は今回お試し用なのでこのままでいきます。
次に同じようにAPIキーを作成し、アプリケーションの制限の設定で「iOSアプリ」を選択しときます。
これで実際に運用する時と同じ構成でAndroidアプリ用のAPIキーとiOSアプリ用のAPIキーが作成されました。
- プロジェクトへの反映は↓を参照してください。
- 検証用に以下の画面を作成します
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が開く
- 「アプリで開く」が表示されるがタップするとエラーになる
- Google Mapがインストールされている場合 (実機で確認)
- Androidの場合
- Google Mapがインストールされている場合
- FABでもMarkerでも挙動は同じ
- Google Mapアプリが開く
- Google Mapがインストールされていない場合
- Makerの場合
-
mapToolbarEnabled
をtrue
にして検証 - アプリ内のMap上にToolbarが表示される (↓)
- Toolbarタップでエラーが表示される
-
- FABの場合
- url_launcherの
canLaunchUrl
のチェックがある場合、チェックに引っかかっる
- url_launcherの
canLaunchUrl
のチェックがない場合、アプリ内ブラウザが開く
- url_launcherの
- Makerの場合
- Google Mapがインストールされている場合
参考URL
Discussion