Get Started

この章ではSDKを利用したアプリを構築するための基礎知識について説明します。


サンプルアプリを試す

Android Studioでプロジェクトを開き、任意のデバイスでアプリを実行してください。


新しいアプリにSDKを組み込んで地図を表示する

本ガイドの開発環境は Android Studio Giraffe および Gradle7.1 を対象としています。
また、ソースコードは全てJavaで記述しています。

Gradle依存関係構築

*.aarをアプリケーションのapp/libsディレクトリに配置します。

次に、アプリのbuild.gradleに以下の記述を追加して*.aarが依存関係に取り込まれるようにし、 必要なパッケージの依存関係を構築します。

implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
implementation 'com.mapbox.maps:android:10.14.0'
implementation 'com.mapbox.extension:maps-androidauto:0.5.0'
implementation 'com.google.android.gms:play-services-location:21.0.1'
implementation "androidx.car.app:app-projected:1.2.0"
Note:

各パッケージのバージョンはリリースノートに従った値を設定してください。

次に、プロジェクトのbuild.gradleに以下の記述を追加して、MapBoxパッケージのCredentialを設定します。

allprojects {
    repositories {
        google()
        jcenter()

+       maven {
+           url 'https://api.mapbox.com/downloads/v2/releases/maven'
+           authentication {
+               basic(BasicAuthentication)
+           }
+           credentials {
+               username = 'mapbox'
+               password = project.properties['MAPBOX_DOWNLOADS_TOKEN'] ?: ""
+           }
+       }
    }
}
注意:

MAPBOX_DOWNLOADS_TOKENは環境変数で、ビルド作業者のローカルに保存されるものです。
~/.gradle/gradle.propertiesMAPBOX_DOWNLOADS_TOKEN=XXXXのように設定してください。
secret access tokenという機密情報のため、権限のないユーザーが見つける可能性がある、公的にアクセス可能なソース コードに公開しないでください。

MapBox public access tokenの設定

MapBoxの'Configure your public token'の手順に従い、トークンを設定してください。

例えば、app/src/main/res/values/developer-config.xmlを追加して、以下のように設定します。

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
	<string name="mapbox_access_token" translatable="false" tools:ignore="UnusedResources">YOUR_PUBLIC_MAPBOX_ACCESS_TOKEN</string>
</resources>

secret access token 及び public access token について、 具体的な値(文字列)については営業窓口までお問い合わせください。

AndroidManifestによる権限設定

AndroidAutoを使用する場合、AndroidManifest.xmlに以下の記述を追加して権限を設定します。

    <uses-permission android:name="androidx.car.app.NAVIGATION_TEMPLATES" />

    <application
        <!-- snip -->
        >

        <!-- You must add xml/automotive_app_desc -->
        <meta-data
            android:name="com.google.android.gms.car.application"
            android:resource="@xml/automotive_app_desc" />

        <!-- Create a theme for your app -->
        <meta-data
            android:name="androidx.car.app.theme"
            android:resource= "@style/CarAppTheme" />

        <!-- You choose your minCarApiLevel -->
        <meta-data
            android:name="androidx.car.app.minCarApiLevel"
            android:value="3" />

        <!-- Link to your implementation of CarAppService -->
        <service
            android:name=".car.YourCarAppService"
            android:exported="true"
            tools:ignore="ExportedService">

            <intent-filter>
                <action android:name="androidx.car.app.CarAppService" />
                <category android:name="androidx.car.app.category.NAVIGATION" />
            </intent-filter>
        </service>
    </application>
Note:

Google's documentation for building a navigation appもご確認下さい。
SDKには androidx.car.app.ACCESS_SURFACE 権限が含まれているため、この権限をマニフェストに追加する必要はありません。
アプリに必要な他の権限とともに、androidx.car.app.NAVIGATION_TEMPLATES 権限を追加する必要があります。

SDKの初期化

SDKは使用開始前に初期化処理が必要です。 詳細な手順は「Initialize」 を参照してください。
ここでは地図を表示するための最小限の手順を説明します。

まずNavi.initialize()によってSDK全体の初期化を行います。 NaviInitInfoコンストラクタのcontextはApplication Contextを指定してください。

private void initializeNavi(Context context) {
    NaviInitInfo initInfo = new NaviInitInfo(context);
	initInfo.setCloudEnvironment(Common.CloudEnvironment.PRODUCTION);
	initInfo.setTrafficProviderKey(PROVIDER_KEY); // 具体的なキー(文字列)については営業窓口までお問い合わせください。さい。
	initInfo.setTrafficProviderUserID(USER_ID); // 具体的なID(文字列)については営業窓口までお問い合わせください。
	initInfo.setApiKey(API_KEY); // 具体的なキー(文字列)については営業窓口までお問い合わせください。

    Navi.getInstance().initialize(initInfo, new NaviInitListener() {
        @Override
        public void onInitCompleted(ErrorCode errorCode, NaviInitResult naviInitResult) {
            if (errorCode == ErrorCode.NONE) {
                Navi.getInstance().setMobileAppLifecycle(getLifecycle());
            }
        }
    });
}

続いて、地図の初期化を行います。
例えば、端末の全画面に地図を表示したい場合、次のようなFrameLayoutを用意してください。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
    />
</RelativeLayout>

地図の描画領域はSupportFragmentで、これを既存のFragmentと置き換えることでSDKが自動的に地図更新できるようになります。 ここでは上述のFrameLayoutをgetSupportFragmentManager を利用して置き換えてみます。

private Map map = null;
private void initializeMap() {
    getSupportFragmentManager().beginTransaction()
            .replace(R.id.container, SupportMapFragment.newInstance(), "supportMapFragment")
            .commitNow();

    SupportMapFragment supportMapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.container);
    supportMapFragment.initialize(new MapSetting(), new OnMapEventListener() {
        @Override
        public void onInitializationCompleted(ErrorCode errorCode) {
            if (errorCode == ErrorCode.NONE) {
                map = supportMapFragment.getMap();
                Navi.getInstance().attach(map);
            }
        }

        @Override
        public void onMapModeChanged(Map.MapMode mode) { }
    });
}

このinitializeMap()関数をNaviInitListener.onInitializationCompleted()完了に合わせて呼び出すことで、地図を描画できます。

    Navi.getInstance().initialize(initInfo, new NaviInitListener() {
        @Override
        public void onInitCompleted(ErrorCode errorCode, NaviInitResult naviInitResult) {
            if (errorCode == ErrorCode.NONE) {
                Navi.getInstance().setMobileAppLifecycle(getLifecycle());
+               initializeMap();
            }
        }
    });

このように地図が表示されれば成功です。

地図のみ描画

なお、現在位置と違う地図を出している状態ですが、この時点では正常です。

自車位置を特定する

アプリの権限のうち、位置情報を許可してください。

SDK初期化完了後にNavi.startPositioning()を呼び出せば、それ以降自車位置を更新し続けます。

    Navi.getInstance().initialize(initInfo, new NaviInitListener() {
        @Override
        public void onInitCompleted(ErrorCode errorCode, NaviInitResult naviInitResult) {
            if (errorCode == ErrorCode.NONE) {
                Navi.getInstance().setMobileAppLifecycle(getLifecycle());
+               Navi.getInstance().startPositioning(new PositioningSetting());
                initializeMap();
            }
        }
    });

起動後に地図を自車位置中心に移動する

自車位置を中心に地図を描画し続けるには、Map.setMapMode()による描画指定、および自車位置へのカメラ位置移動が必要です。

private void setMapCenterToOwnCarPosition(Map map) {
    CameraOptions cameraOptions = new CameraOptions();
    cameraOptions.setCenter(Navi.getInstance().getRunInfo().getOwnCarInfo().getGeoCoordinate());
    map.moveToPoint(cameraOptions, null);
    map.setMapMode(Map.MapMode.HEADING_UP);
}

setMapCenterToOwnCarPosition()OnMapEventListener.onInitializationCompleted()通知時に呼び出してください。

        @Override
        public void onInitializationCompleted(Error error) {
            if (error == Error.NONE) {
                map = supportMapFragment.getMap();
                Navi.getInstance().attach(map);
+               setMapCenterToOwnCarPosition(map);
            }
       }

これで起動完了とともに自車位置を中心に地図が描画されるようになります。

自車位置中心

地図の制御方法の詳細は「Camera Control」を参照してください。

Note:

自車位置が東京都庁になっている場合、アプリの位置情報権限が付与されていない可能性があります。

ルートを探索して案内を開始する

ルート探索の詳細は「Route」を参照してください。
ここでは地図を長押しした地点へのルートを探索し、案内を開始する最小限の手順を説明します。

まず、地図の長押しを検知するために、Map.addOnMapLongClickListener()でリスナを登録します。

        @Override
        public void onInitializationCompleted(Error error) {
            if (error == Error.NONE) {
                map = supportMapFragment.getMap();
                Navi.getInstance().attach(map);
                setMapCenterToOwnCarPosition(map);
+               map.addOnMapLongClickListener(new OnMapLongClickListener() {
+                   @Override
+                   public boolean onMapLongClick(GeoCoordinate point) {
+                       return false;
+                   }
+               });
            }
        }

次に、その地点へのルートを探索する処理(startNavigation())を追加し、OnMapLongClickListener.onMapLongClick()でそれを呼び出します。

private void startNavigation(GeoCoordinate goal) {
    RoutePlan routePlan = new RoutePlan();
    routePlan.setEndPoint(goal);
    routePlan.setRouteOptions(new RouteOptions());

    Navi.getInstance().calculateRoute(routePlan, new CalcRouteListener() {
        @Override
        public void onCompleted(ErrorCode errorCode, CalcRouteResult calcRouteResult) {
            if (errorCode == CalcRouteListener.ErrorCode.NONE) {
                Navi.getInstance().startGuidance(null);
            }
        }
    });
}
                        @Override
                        public boolean onMapLongClick(GeoCoordinate point) {
+                           startNavigation(point);
                            return false;
                        }

最後に、誘導音声の出力を有効化するため、NaviInitListener.onInitCompleted()Navi.startVoiceEngine()を追加します。

            @Override
            public void onInitCompleted(ErrorCode errorCode, NaviInitResult naviInitResult) {
                if (errorCode == ErrorCode.NONE) {
                    Navi navi = Navi.getInstance();
                    navi.setMobileAppLifecycle(getLifecycle());
                    navi.startPositioning(new PositioningSetting());
+                   navi.startVoiceEngine(new VoiceEngineInitListener() {
+                       @Override
+                       public void onInitCompleted(ErrorCode errorCode) {
+                       }
+                   });

                    initializeMap();
                }
            }

これで地図を長押しした地点へのルートを探索できるようになりました。

ルート探索

擬似走行して誘導音声を確認する

SDKには机上で動作確認するための手段としてデモ走行機能を提供しています。

次のようなstartDemoRun()関数を追加し、CalcRouteListener.onCompleted()でそれを呼び出せばルート探索完了と同時にルート上の擬似走行を開始します。

    private void startDemoRun() {
        DemoRunSetting demoRunSetting = new DemoRunSetting();
        demoRunSetting.setDemoType(Common.DemoType.AUTO);
        demoRunSetting.setDemoUpdateCycle(Common.DemoUpdateCycle.DEMO_UPDATE_CYCLE_1HZ);
        demoRunSetting.setAutoRepeat(true);
        Navi.getInstance().startDemoRun(demoRunSetting);
    }
            @Override
            public void onCompleted(ErrorCode errorCode, CalcRouteResult calcRouteResult) {
                if (errorCode == CalcRouteListener.ErrorCode.NONE) {
                    Navi.getInstance().startGuidance(null);
+                   startDemoRun();
                    setMapCenterToOwnCarPosition(map);
                }
            }

デモ走行機能の詳細は「Demo Run」を参照してください。

ここまでの手順のサンプル全体像(クリックして展開)

package com.pioneer.android.myapplication;

import android.content.Context; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import com.pioneer.android.mpa.CalcRouteListener; import com.pioneer.android.mpa.CalcRouteResult; import com.pioneer.android.mpa.CameraOptions; import com.pioneer.android.mpa.Common; import com.pioneer.android.mpa.DemoRunSetting; import com.pioneer.android.mpa.GeoCoordinate; import com.pioneer.android.mpa.Map; import com.pioneer.android.mpa.MapSetting; import com.pioneer.android.mpa.Navi; import com.pioneer.android.mpa.NaviInitInfo; import com.pioneer.android.mpa.NaviInitListener; import com.pioneer.android.mpa.NaviInitResult; import com.pioneer.android.mpa.OnMapEventListener; import com.pioneer.android.mpa.OnMapLongClickListener; import com.pioneer.android.mpa.PositioningSetting; import com.pioneer.android.mpa.RouteOptions; import com.pioneer.android.mpa.RoutePlan; import com.pioneer.android.mpa.SupportMapFragment; import com.pioneer.android.mpa.VoiceEngineInitListener; import com.pioneer.sample.myapplication.R; import com.pioneer.sample.myapplication.databinding.MainActivityBinding;

public class MainActivity extends AppCompatActivity {

private Map map = null;
private MainActivityBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = MainActivityBinding.inflate(getLayoutInflater());
    setContentView(binding.getRoot());

    naviInitialize(this);
}

private void naviInitialize(Context context) {
    NaviInitInfo initInfo = new NaviInitInfo(context);
    initInfo.setCloudEnvironment(Common.CloudEnvironment.PRODUCTION);
    initInfo.setTrafficProviderKey(PROVIDER_KEY);
    initInfo.setTrafficProviderUserID(USER_ID);
    initInfo.setApiKey(API_KEY);

    Navi.getInstance().initialize(initInfo, new NaviInitListener() {
        @Override
        public void onInitCompleted(ErrorCode errorCode, NaviInitResult naviInitResult) {
            if (errorCode == ErrorCode.NONE) {
                Navi navi = Navi.getInstance();
                navi.setMobileAppLifecycle(getLifecycle());
                navi.startPositioning(new PositioningSetting());
                navi.startVoiceEngine(new VoiceEngineInitListener() {
                    @Override
                    public void onInitCompleted(ErrorCode errorCode) {
                    }
                });

                initializeMap();
            }
        }
    });
}

private void initializeMap() {
    getSupportFragmentManager().beginTransaction()
            .replace(R.id.container, SupportMapFragment.newInstance(), "supportMapFragment")
            .commitNow();

    SupportMapFragment supportMapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.container);
    supportMapFragment.initialize(new MapSetting(), new OnMapEventListener() {
        @Override
        public void onInitializationCompleted(Error error) {
            if (error == Error.NONE) {
                map = supportMapFragment.getMap();
                Navi.getInstance().attach(map);
                setMapCenterToOwnCarPosition(map);

                map.addOnMapLongClickListener(new OnMapLongClickListener() {
                    @Override
                    public boolean onMapLongClick(GeoCoordinate point) {
                        startNavigation(point);
                        return false;
                    }
                });

            }
        }

        @Override
        public void onMapModeChanged(Map.MapMode mode) { }
    });
}

private void setMapCenterToOwnCarPosition(Map map) {
    CameraOptions cameraOptions = new CameraOptions();
    cameraOptions.setCenter(Navi.getInstance().getRunInfo().getOwnCarInfo().getGeoCoordinate());
    map.moveToPoint(cameraOptions, null);
    map.setMapMode(Map.MapMode.HEADING_UP);
}

private void startNavigation(GeoCoordinate goal) {
    RoutePlan routePlan = new RoutePlan();
    routePlan.setEndPoint(goal);
    routePlan.setRouteOptions(new RouteOptions());

    Navi.getInstance().calculateRoute(routePlan, new CalcRouteListener() {
        @Override
        public void onCompleted(ErrorCode errorCode, CalcRouteResult calcRouteResult) {
            if (errorCode == CalcRouteListener.ErrorCode.NONE) {
                Navi.getInstance().startGuidance(null);
                startDemoRun();
                setMapCenterToOwnCarPosition(map);
            }
        }
    });
}

private void startDemoRun() {
    DemoRunSetting demoRunSetting = new DemoRunSetting();
    demoRunSetting.setDemoType(Common.DemoType.AUTO);
    demoRunSetting.setDemoUpdateCycle(Common.DemoUpdateCycle.DEMO_UPDATE_CYCLE_1HZ);
    demoRunSetting.setAutoRepeat(true);
    Navi.getInstance().startDemoRun(demoRunSetting);
}

}

SDKの責務について

SDKは以下の機能について責任を持ちます。

  • 自車位置更新処理。
  • 地図描画、地図のジェスチャー検知、地図への線描画、地図へのアイコン描画処理。
  • 地点検索処理とその結果。
  • ルート探索処理とその結果。
  • システム標準TTSを用いた音声によるルート誘導。
  • 渋滞情報の取得処理とその結果。

SDKが提供するGUI部品は次の2点のみです。

これ以外のGUI部品は、アプリが自由に構築できます。