Android StudioでGoogle Map APIを使う

# 概要
Android Studioを使ってAndroidプログラミングの勉強を進めている。
ふとGoogle Mapで遊びたいなと思ったのだけど，[公式ガイド](https://developers.google.com/maps/documentation/android-api/intro)を読んでも「プロジェクトのセットアップ」の理解に苦労して時間を浪費してしまった。
いろんなページを行ったり来たりしたらようやくセットアップができたので，備忘録としてメモを残しておく。

Windows環境。

## やったこと

- 勉強用のプロジェクトへのGoogle Mapの追加

## 参考にしたサイト

[公式ガイド](https://developers.google.com/maps/documentation/android-api/intro)
[（プロジェクトの設定）](https://developers.google.com/maps/documentation/android-api/config)
[（サインアップと API キー）](https://developers.google.com/maps/documentation/android-api/signup)
[Androidアプリ開発でGoogleMapを利用する](http://qiita.com/konnobu/items/8bec3d5a45235fc88a08)
[Google Play Services SDK のセットアップ(Android Studio)](http://qiita.com/ryo0301/items/e2722f0a8d5528d0f257)
[【Android】Google Maps Android API についての備忘録](http://qiita.com/POCOio_oi/items/e0f30ad5fcfc82fe0f52)
[keytoolを使う](http://androyer.blogspot.jp/2014/01/keytool.html)
[64K を超えるメソッドを使用するアプリの設定](https://developer.android.com/studio/build/multidex.html)

# 前準備
## Android Studioのインストール
はもう済んでいる。

## Google Play servicesのインストール
SDKマネージャーを開いて「Google Play services」がインストールされていなかったらしておく。
僕はされていなかったのでインストールした。

## Google Play servicesとプロジェクトを関連付ける
Gradle Scripts内の「build.gradle (Module:app)」に1行追加した。

```:build.gradle
dependencies {
    ...
    compile 'com.google.android.gms:play-services:+'
}
```

その後，プロジェクトを同期させた（Sync Project with Gradle Files）。

### 追記：必要なサービスのみを取り込む

上記のような関連付けだと膨大なデータと紐付いてしまって必要以上に肥大化するらしいので、[ここを参考にして](https://developers.google.com/android/guides/setup#split)関連付けたいサービス分だけ記述するようにしたほうがいいようだ。

```:build.gradle
dependencies {
    ...
    compile 'com.google.android.gms:play-services-maps:11.0.2'
}
```

## Google Play servicesを使えるようにする

マニフェストファイルの`<application>`要素以下に次の行を追加した。

```xml:AndroidManifest.xml
<meta-data
    android:name="com.google.android.gms.version"
    android:value="@integer/google_play_services_version" />
```

マニフェストファイルはまだまだ使うので開いた状態にしておく。

# Google Map APIのセットアップ

## SHA1フィンガープリントを取得する

`debug.keystore`のある場所（`c:\Users\<user>\.android`あたり）に移動してプロンプトを開く。
SHIFTを押しながら右クリックすると「ここでプロンプトを開く」みたいなメニューが出現する。
そして以下のコマンドを叩く。

```:プロンプト
keytool -list -v -keystore debug.keystore
```

パスワードを聞かれても空欄のままエンターすると証明書のフィンガープリントが何種類か得られる。
そのうち，SHA1のものを使うので適当にメモっておく。

なお，「keytoolコマンドなんて知らん」と怒られたらJava JDKのbinへパスを通してからやり直す。

## APIキーを取得する

[Google API Console](https://console.developers.google.com/)に移動して適当な名前のプロジェクトを作成する。
「ライブラリ」のページを開いて「Google Maps Android API」を選択して「有効」にする
「認証情報」のページを開いて「認証情報を作成」->「APIキー」と進む。
するとAPIキーが生成されるので，「キーを制限する」へと進んで「Androidアプリ」を選択する。
「パッケージ名とフィンガープリントを追加」から，マニフェストファイル記載のパッケージ名と，先ほどメモっておいたフィンガープリントをコピペして保存する。

すると，指定したプロジェクトでGoogle Map APIが使えるようになる。

## APIキーを読み込む
マニフェストファイルの`<application>`要素以下に次の行を追加した。

```xml:AndroidManifest.xml
<meta-data
    android:name="com.google.android.geo.API_KEY"
    android:value="<your API key>"/>
```

## パーミッションの設定

マニフェストファイルに以下のパーミッションを追加する。
パーミッションの追加に関してはバージョンごとに異なるらしいが詳しいことはわからない。

```xml:AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
```

その後，描画用にOpenGL ESを使えるよう`<manifest>`の子要素に以下を追加する。

```xml:AndroidManifest.xml
<uses-feature
    android:glEsVersion="0x00020000"
    android:required="true"/>
```

## ~~Multidexへの対応~~

追記：すべてのサービスと関連付けていなければ下記の対応は不要でした。

次章に載せているサンプルプログラムを実行させようとしたら以下のようなエラーが出て怒られた。

```:MessagesGradleBuild
Error:The number of method references in a .dex file cannot exceed 64K.
Learn how to resolve this issue at https://developer.android.com/tools/building/multidex.html
```

何やらよく分からないのだが，公式ガイドに載っていた以下の追記で対応した。

- SDK Managerを使って Android SDK Build Tools と Android Support Repository をアップデートする
- Gradle Scripts内の「build.gradle (Module:app)」に2ヶ所追加した

```:build.gradle
android {
    ...
    defaultConfig {
        ...
        multiDexEnabled true
    }
    ....
    dependencies {
        ...
        compile 'com.android.support:multidex:1.0.0'
    }
}
```

- マニフェストファイルの`<application>`属性に1つ追加した

```xml:AndroidManifest.xml
<appication
    ...
    android:name="android.support.multidex.MultiDexApplication" >
...
</application>
```


# サンプルプログラムの実装

ここからは公式ガイドの「マップを作成する」以降となんら変わらないのだが，一応メモ。

## レイアウト側

``` xml:activity_main.xml
<fragment
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:name="com.google.android.gms.maps.MapFragment"
    android:id="@+id/map" />
```

## アクティビティ側

``` java:MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    MapFragment mapFragment = (MapFragment)getFragmentManager().findFragmentById(R.id.map);
    mapFragment.getMapAsync(new OnMapReadyCallback() {
        @Override
        public void onMapReady(GoogleMap map) {
            map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
            map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(35.681382, 139.766084), 15));
        }
    });
    ...
}
```