使用ツール
Android Studio Giraffe | 2022.3.1 Patch 2
Android Studio Giraffe では、プロジェクトを新規作成するときに「Google Map テンプレート」を選択することができなくなりました。
(もしも同等のプロジェクトを作成したいなら app > File - New - Fragment - Gallery... から Google Maps Fragment を選択します)
「Google Map テンプレート」は Fragment による実装でしたが、ここでは MapView で実装します。
MapView を使用することにより、ほかの View との重ね合わせを直感的に配置できます。
0. 事前準備 (Web ページ Google Maps Platform で作業)
Google Map を表示するには「Google Maps API」を使用しますが、
それには API キー (長い文字列) の発行を受け、そのキーをプログラムに埋め込まなければなりません。
API キーはアカウント毎ではなく、プロジェクト毎の発行です。
API キーは有料 (発行前にクレジットカードの登録が必要) ですが無料期間が 90 日あり、これを過ぎると 30 日間の猶予の後に API キーが無効になります。
キーが無効になるとサービスが受けられなくなるだけで、料金の発生はありません。
「Google Cloud の無料プログラム」によると、条件は以下なので、無料トライアルは 1 回だけ受けられる、ということになります。
以下抜粋
このとき、さらに Google Maps API を使うには、以下の方法があります。
- 90 日間 $300 分の無料トライアル期間は、登録が完了すると自動的に開始されます。
- 以前に Google Cloud、Google Maps Platform、Firebase を有料で利用したことがない。
- 以前に無料トライアルに登録したことがない。
- お使いの Cloud 請求先アカウントは 30 日間の猶予期間に入ります。その間に、トライアル期間中に Google Cloud サービスに保存したリソースとデータを復元できます。
「料金」は「お客様のニーズに合わせた柔軟な料金設定」によると、「1 か月あたり 28,500 回まで無料の地図読み込み」とあるので、開発目的なら無料という算段になります。
- 料金を支払って API キーの有効期間を延長する。
- 料金を支払って新規に API キーを発行する。(プロジェクトを作成し直す)
(負荷テストとかは、やっちゃだめですよ)
API キーの取得
0-1. Gmail アカウント (= Google アカウント) の作成
Google アカウントは Gmail アカウントを作成すると、それに付随して作成される。0-2. Google Cloud へログイン
すでに Gmail アカウントがあるなら、作成の必要はない。
Google Maps Platform をブラウザでアクセスし、「使ってみる」から Gmail アカウントでログインすると、Google Cloud が使えるようになる。0-3. プロジェクトを作成
Google Cloud の「≡」(ナビゲーションメニュー) にある「Google Maps Platform」からプロジェクトを一つ作成する。0-4. API キーの表示
プロジェクトを作成すると、自動的に API キーが発行される。
(API キーを発行するような操作は特に必要ない)
作成したプロジェクトを選択し「≡」の「Google Maps Platform」から「鍵と認証情報」を選択する。
中央ペインの「API キー」の下にある「鍵を表示します」をクリックして API キーを表示する。
ここで表示した API キーの文字列をコピーし、後述の MAPS_API_KEY= として設置する。(下記 3-1)
1. Android Studio で通常のプロジェクトを作成する。
ここでは MapView を利用して Google Map を表示するので、画面の存在するプロジェクトを作成する。
「Empty Activity」「Empty Views Activity」等のプロジェクトが対象。
「No Activity」でも構わないが、Default Activity の追加が必要になるので、ここでは割愛する。(選択しない)
2. アクティビティに MapView を配置する。
MapView を設置すると「No speakable text present」の警告が表示される。無視の設定をするか、contentDescription を設定すると警告が消える。
要素名 内容 備考 アクティビティ Android > app > res > layout > activity_main.xml - 部品 種類 MapView - id mapView プログラムから R.id.mapView として参照される。
3. API キーの設置
3-1. local.properties を開き、API キー (上記 0-4 で取得) を設置する。
Android > Gradle Scripts > local.properties を編集する。
MAPS_API_KEY= の右辺に記述する。(行そのものがないので、1 行追加)
MAPS_API_KEY は下記 AndroidManifest.xml から value="${MAPS_API_KEY}" として参照する。
## This file is automatically generated by Android Studio. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! # # This file should *NOT* be checked into Version Control Systems, # as it contains information specific to your local configuration. # # Location of the SDK. This is only used by Gradle. # For customization when using a Version Control System, please read the # header note. sdk.dir=/home/who/Android/Sdk MAPS_API_KEY=AbCdEfGhIjKlMnOpQrStUvWxYz-0123456789aZ
ここではサンプルのため、でたらめな文字列にしている。
4. 設定ファイルの調整
4-1. Manifest の追加
Android > app > manifests > AndroidManifest.xml を編集する。4-2. プラグインの追加 (1)
<application></application> の中に <meta-data> を挿入する。
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <application ~省略~ tools:targetApi="31">
<meta-data android:name="com.google.android.geo.API_KEY" android:value="${MAPS_API_KEY}" />
<activity ~省略~ </activity> </application> </manifest>
Android > Gradle Scripts > build.gradle.kts (Project) を編集する。4-3. プラグインの追加 (2)
// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { id("com.android.application") version "8.1.2" apply false
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") version "2.0.1" apply false
}
Android > Gradle Scripts > build.gradle.kts (Module :app) を編集する。4-4. ビルド情報の反映。
plugins { id("com.android.application")
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
} ~省略~
メニュー File の Sync Project with Gradle Files Ctrl+Shift+O を選択する。
5. 地図の表示
5-1. MainActivity.java にコードを記述する。
フラグメント xxx_Fragment.java に記述する場合は onCreate(···) ではなく onCreateView(···) に記述する。
参考はここ。
public class MainActivity extends AppCompatActivity {
private MapView mMapView;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
// MapView に GoogleMap を表示する mMapView = findViewById(R.id.mapView); mMapView.onCreate(savedInstanceState); // GoogleMap のコールバックメソッドを用意する OnMapReadyCallback onMapReadyCallback = new OnMapReadyCallback() { @Override public void onMapReady(@NonNull GoogleMap googleMap) { // ジェスチャーによる地図の回転を許可する UiSettings uiSettings = googleMap.getUiSettings(); uiSettings.setRotateGesturesEnabled(true); // 東京タワーの緯度・経度 LatLng tokyoTower = new LatLng(35.65867633445335, 139.74545436106237); // 東京タワーのマーカーを設置する MarkerOptions markerOptions = new MarkerOptions(); markerOptions.position(tokyoTower); markerOptions.title("東京タワー"); googleMap.addMarker(markerOptions); // 東京タワーを中心にして地図を表示する googleMap.moveCamera(CameraUpdateFactory.newLatLng(tokyoTower)); googleMap.moveCamera(CameraUpdateFactory.zoomTo(8.0f)); // ジェスチャーによる地図の移動開始リスナを用意する googleMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() { @Override public void onCameraMoveStarted(int i) { // カメラ移動の開始要因を求める String reason = ""; switch(i) { case GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE: reason = "GESTURE"; break; case GoogleMap.OnCameraMoveStartedListener.REASON_API_ANIMATION: reason = "API_ANIMATION"; break; case GoogleMap.OnCameraMoveStartedListener.REASON_DEVELOPER_ANIMATION: reason = "DEVELOPER_ANIMATION"; break; } Toast.makeText(MainActivity.this, "CameraMove Started: " + reason, Toast.LENGTH_SHORT).show(); } }); // ジェスチャーによる地図の移動中リスナを用意する googleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() { @Override public void onCameraMove() { // カメラ位置を求める CameraPosition cameraPosition = googleMap.getCameraPosition(); LatLng latLng = cameraPosition.target; float zoom = cameraPosition.zoom; float bearing = cameraPosition.bearing; String state = String.format("%7.3f %7.3f %7.3f %7.3f°", latLng.latitude, latLng.longitude, zoom, bearing); Log.d("CameraMove", state); //トーストだとイベント発生が多すぎて追従できない } }); // ジェスチャーによる地図の移動終了リスナを用意する googleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() { @Override public void onCameraIdle() { // カメラ位置を求める CameraPosition cameraPosition = googleMap.getCameraPosition(); LatLng latLng = cameraPosition.target; float zoom = cameraPosition.zoom; float bearing = cameraPosition.bearing; String state = String.format("%7.3f %7.3f %7.3f %7.3f°", latLng.latitude, latLng.longitude, zoom, bearing); Toast.makeText(MainActivity.this, "CameraMove in Idle:\n"+state, Toast.LENGTH_SHORT).show();
// ここはお好みで追加する LatLngBounds bounds = googleMap.getProjection().getVisibleRegion().latLngBounds; Log.d("LatLngBounds", String.format("%7.3f,%7.3f - %7.3f,%7.3f", bounds.northeast.latitude, bounds.northeast.longitude, bounds.southwest.latitude, bounds.southwest.longitude));
} }); } }; // GoogleMap のコールバックメソッドを登録する mMapView.getMapAsync(onMapReadyCallback);
}
@Override protected void onResume() { super.onResume(); mMapView.onResume(); } @Override protected void onStart() { super.onStart(); mMapView.onStart(); } @Override protected void onStop() { super.onStop(); mMapView.onStop(); } @Override protected void onPause() { mMapView.onPause(); super.onPause(); } @Override protected void onDestroy() { mMapView.onDestroy(); super.onDestroy(); } @Override public void onLowMemory() { super.onLowMemory(); mMapView.onLowMemory(); }
}