Navigation SDK v2 for Androidを試してみる (インストール編)

## はじめに

いよいよ、待ちに待った[Mapbox Navigation SDK v2](https://www.mapbox.com/navigation/)がリリースされました！そこで、ここでは公式サイトの手順にしたがってまずはAndroidのナビゲーションアプリを動かしてみたいと思います。


### v1との違い

v2はMaps SDK v10をベースにナビゲーション機能を提供します。それに伴い、カメラ周りの実装などが大きく変更されました。特にAndroidはUI周りの変更が顕著です。

例えば、v1では`View`を継承した`NavigationView`が実装されていました。これを使うことで、全部入りのナビゲーションは[このサンプル](https://github.com/mapbox/mapbox-navigation-android/blob/v1.6.2/examples/src/main/java/com/mapbox/navigation/examples/ui/NavigationViewActivity.kt)のように少ない記述量で作成することができました。これに対し、v2では`NavigationView`が提供されません。代わりに、ナビゲーションのための各パーツが提供されており、自身でそれらを組み合わせて使います。v1における[このサンプル](https://github.com/mapbox/mapbox-navigation-android/blob/v1.6.2/examples/src/main/java/com/mapbox/navigation/examples/ui/CustomUIComponentStyleActivity.kt)がイメージとしては近いです。

また、Navigation Core (`MapboxNavigation`等)はv1のコードをベースに開発されたため、v1の面影があります。それに対し、UIの実装は新規に行われてたため、完全な別物となっています。

そのため、公式ドキュメントで紹介されているサンプルも"To simulate your first navigation experience using our UI components"という割にはコード量が多いです。ただ、基本的にはコピペで動くので、今回はまず動かすことに主眼を置きたいと思います。

<2023年7月22日更新>
v2.4.0でDrop-In UIが実装されました。以下の記事で詳細に解説しているので合わせてご参照ください。

https://zenn.dev/mapbox_japan/articles/11d9904255c117

## 注意事項
- この記事では2021/11/25現在で最新の`v2.0.2`を使用します。
- [Pricing](https://docs.mapbox.com/android/navigation/guides/pricing/)にご注意ください。特にMAUは100まで無料ですが、[ここに記載](https://docs.mapbox.com/android/navigation/guides/pricing/#how-are-unique-users-counted)されているようにアプリケーションの削除・インストールでカウントアップします。デバッグ中に何度も削除・インストールを繰り返すと無料枠を超える可能性があります。


## インストール
Mapbox Navigation SDK for Android v2の公式ドキュメントは[こちら](https://docs.mapbox.com/android/navigation/guides/)です。Get started の中の [Installation](https://docs.mapbox.com/android/navigation/guides/get-started/install/) から始めます。

基本的には書いてあるとおりに進めればOKですが、以下の点に注意してください。

### 新規プロジェクト
Minimum SDKはAPI21: Android 5.0 (Lollipop) 以上が必要です。Empty Activityで大丈夫です（使わないので）。

### トークン
MapboxのアクセストークンにはPublic, Secretの二種類が存在します。

- Publicトークン: 地図の取得、ナビゲーション情報の取得等アプリケーションからMapboxのAPIを呼ぶ際に使用。`pk.`で始まる文字列
- Secretトークン: アカウントの設定、SDKバイナリのダウンロードなど、開発時に使用。`sk.`で始まる文字列

そこで、まずNavigation SDKをダウンロードするために[アカウントサイト](https://account.mapbox.com/)で「Downloads:Read」スコープの付与されたSecretトークンを作成します。そして、`«USER_HOME»/.gradle/gradle.properties`の中に以下を記載します。

```shell:~/.gradle/gradle.properties
MAPBOX_DOWNLOADS_TOKEN=PASTE_YOUR_SECRET_TOKEN_HERE
```

これが後ほどビルドの際に使用されます。Androidのプロジェクトの中で直接指定することも可能ですが、間違えてGitHub等にPushしてしまう危険性があるので注意してください。

### Mavenの設定

ドキュメントでは以下の設定を**プロジェクトレベル**の`gradle.properties`に書くように指示されています。

```gradle:gradle.properties
allprojects {
    repositories {
        maven {
            url 'https://api.mapbox.com/downloads/v2/releases/maven'
            authentication {
                basic(BasicAuthentication)
            }
            credentials {
                // Do not change the username below.
                // This should always be `mapbox` (not your username).
                username = "mapbox"
                // Use the secret token you stored in gradle.properties as the password
                password = project.properties['MAPBOX_DOWNLOADS_TOKEN'] ?: ""
            }
        }
    }
}
```

Android Studio Arctic Foxでプロジェクトを作成した場合、`allprojects`が存在しません。そこで、**プロジェクトレベル**の`settings.gradle`を開き、以下のように記載します。`project.properties['MAPBOX_DOWNLOADS_TOKEN']`が`this.properties['MAPBOX_DOWNLOADS_TOKEN']`になっている点にご注意ください。

```gradle:settings.gradle
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        jcenter() // Warning: this repository is going to shut down soon
        maven {
            url 'https://api.mapbox.com/downloads/v2/releases/maven'
            authentication {
                basic(BasicAuthentication)
            }
            credentials {
                // Do not change the username below.
                // This should always be `mapbox` (not your username).
                username = "mapbox"
                // Use the secret token you stored in gradle.properties as the password
                password = this.properties['MAPBOX_DOWNLOADS_TOKEN'] ?: ""
            }
        }
    }
}
```

これで先程指定した`MAPBOX_DOWNLOADS_TOKEN`が読み込まれ、SDKバイナリがダウンロードされます。

### アプリ設定
ドキュメントの通り設定してください。

Publicトークンを`R.strings.xml`に設定します。アプリケーションに同梱されるトークンなので`pk.`で始まるPublicトークンを設定します。本番のアプリケーションではトークンをローテーションさせられるように、自分の管理するサーバから取得するようにしても良いかもしれません。

```xml:src/main/res/values/strings.xml
<resources>
    <string name="app_name">NavigationSDKSample</string>
    <string name="mapbox_access_token">MAPBOX_ACCESS_TOKEN</string>
</resources
```


Dependencyに追加します。

```gradle:build.gradle
dependencies {
  implementation "com.mapbox.navigation:android:2.0.2"
}
```

## サンプルの作成

### サンプルのコピペ

[Display a navigation UI](https://docs.mapbox.com/android/navigation/guides/get-started/install/#display-a-navigation-ui)にある[リンク先](https://docs.mapbox.com/android/navigation/examples/turn-by-turn-experience/)のコードをコピペすれば動く、と言いたいところですが、バージョンが合っていないことがあります。

`v2.0.x`をご利用の場合は以下のリンク先のソースをコピペしてください。

- [mapbox_activity_turn_by_turn_experience.xml](https://github.com/mapbox/mapbox-navigation-android-examples/blob/10e50c56e0a1618497a546560c17cd2947c5ddb5/app/src/main/res/layout/mapbox_activity_turn_by_turn_experience.xml)
- [TurnByTurnExperienceActivity.kt](https://github.com/mapbox/mapbox-navigation-android-examples/blob/10e50c56e0a1618497a546560c17cd2947c5ddb5/app/src/main/java/com/mapbox/navigation/examples/basics/TurnByTurnExperienceActivity.kt)

ディレクトリ構造は以下のようになります。

![dir.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85105/55564e64-ac93-8e6a-4306-7d3741c0a32d.png)


### 手直し

appの`build.gradle`を開き、`android`内部に以下を追加

```gradle:build.gradle
android {
    compileSdk 31
...
    buildFeatures {
        viewBinding true
    }
...
}
```

`src/main/AndroidManifest.xml`を開き、`activity`を修正

```xml:src/main/AndroidManifest.xml
...
        <activity
            android:name=".TurnByTurnExperienceActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
...
```

`TurnByTurnExperienceActivity.kt`に対して以下の修正を実施

- [`package`名](https://github.com/mapbox/mapbox-navigation-android-examples/blob/10e50c56e0a1618497a546560c17cd2947c5ddb5/app/src/main/java/com/mapbox/navigation/examples/basics/TurnByTurnExperienceActivity.kt#L1)を`MainActivity`の一行目からコピペ
- [`import`](https://github.com/mapbox/mapbox-navigation-android-examples/blob/10e50c56e0a1618497a546560c17cd2947c5ddb5/app/src/main/java/com/mapbox/navigation/examples/basics/TurnByTurnExperienceActivity.kt#L44-L45)で`package`名由来の部分を同様に修正


## 実行

1. マップ長押しで行き先を選択
2. 経路が設定され、ナビゲーション開始！
3. Recenterボタンを押すとカメラがFollowingモードに遷移

![qiita_s.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85105/7f2a6ba7-04ca-66b1-2d55-ae5447990a86.gif)

## 成果物

今回作成したものは[こちら](https://github.com/OttyLab/MapboxSamples/commit/076944c4bea9a2f886110d00a74261f162a4f23b)にあります。

## 次回

まるっとコピペしたコードの内部を調査し、何が何をやっているのかを見ていきたいと思います。