Android Auto を学ぶその1 とにかく表示してみる
Android Auto を学びたいな〜と思って勉強してみることにしました。
概要
Android で自動車にてアプリを動かす仕組みは2つあります。一つは Android Auto、もう一つが Android Automotive。
Android Auto はスマートフォンで動くアプリを車のナビ画面に投影するイメージ。ナビ側が Android Auto をサポートしている必要があります。動作にはスマートフォンが必要で、純粋な車用アプリというよりも、スマフォ用アプリに車用画面を用意してあげる、という形になります。
Android Automotive は、車のナビに Android OS が組み込まれている場合に利用できます。スマートフォンを必要とせず、車の画面のみでアプリをインストールできます。この機能を積んでいる車は2022/09/26現在市場にまだ全然ないはずで、おそらくボルボとポルシェの一部にしか存在していないと思います。日本車に至っては1台も存在しない気がします。
自分の持っている車(Mazda3)は Android Automotive を使うことができないので、Android Auto にまとを絞って学んでいきます。なお、Android Auto が前提のアプリは避けるべきであるため、基本的には車に接続しなくとも単体で動くアプリ + 車用画面があるアプリとするべきですが、ここではとりあえず Android Auto の画面だけに絞っています。
ホストについて
Android Auto 対応車で作成したアプリを動かすとき、アプリは車と直接やりとりする訳ではありません。このときの接続先はスマフォに入っている Android Auto アプリです。Android Auto アプリはホストと呼ばれ、全ての Auto 対応アプリはこのホストとやりとりします。もし Android Automotive 対応の車で動かす場合は車載器に OS が入っているので、Android Automotive がホストになります。
developer.android.com このドキュメントに、ホストとは何かが記載されています。
ホストは、ライブラリの API によって提供される、アプリを車で実行するための機能を実装するバックエンド コンポーネントです。ホストは、アプリの検出とそのライフサイクルの管理、モデルのビューへの変換、ユーザー操作のアプリへの通知にいたるまで、幅広い役割を担います。モバイル デバイスでは、このホストは Android Auto によって実装されます。
API Level について
Android Auto には API Level という概念が存在しています。これはどの機能までを利用可能かを示すものです。ホストのバージョンに左右されます。現在利用可能なのは API Level 5です。これを動かすには Android Auto 8.1 以降のアプリが端末にインストールされている必要があります。
個人的に重要と考えているのは API Level 3 で追加された API です。これがあると CarHardwareManager
を利用できます。CarHardwareManager
を使うことができれば、車のコンピュータから吐き出される速度、燃料残量、ジャイロ、位置情報、ETCカードの状態などを取得することが可能になるのです。絶対取得したいですよね!!それぞれの API Level で何ができるかはリリースノートを参照することでわかります。
とりあえず文字列を表示してみる
まずは簡単な表示を、簡単なコードで試してみるのが良さそうです。早速コードを書いてみることにします。まずは何を書く必要があるのかをみてみましょう。
- gradle に Android Auto の依存を追加する
- AndroidManifest.xml に Android Auto に必要な記述を追加する
automotiveApp
を記載した xml リソースを作成するandroidx.car.app.CarAppService
クラスを実装するandroidx.car.app.CarAppService
から起動されるandroidx.car.app.Session
を実装するandroidx.car.app.Session
から呼ばれるandroidx.car.app.Screen
を実装する
gradle に Android Auto の依存を追加する
app/build.gradle
に、以下の依存を追加します。
dependencies { implementation "androidx.car.app:app:1.3.0-beta01" implementation "androidx.car.app:app-projected:1.3.0-beta01" }
2022/11/07時点の最新版は 1.3.0-beta01
であり、これを試すのであれば API Level 5 の機能が利用可能になります。端末に最新の Android Auto アプリをインストールしておきましょう(8.1 以降でないと API 呼び出しでクラッシュします)。
余談ですが1.3.0系がでた当初、Android Auto は 8.1 より前のバージョンしかストアにありませんでした。そのため 1.3.0 を利用するには Android Auto アプリのテスターになってより新しいバージョンを得る必要があったのかなと思います。ですがテスター募集はもう締め切られているので、SDK はあるが動かせない状態になっていました。
AndroidManifest.xml に Android Auto に必要な記述を追加する
まずは既存の application
内にエントリポイントとなる service
クラスの記述を追加しましょう。
<service android:name=".SampleAndroidAutoAppService" android:exported="true"> <intent-filter> <action android:name="androidx.car.app.CarAppService"/> </intent-filter> </service>
次に、最低限必要な CarApiLevel 、及びテンプレートを利用する旨を宣言しましょう。automotive_app_desc
ファイルは次で作成します。
<application> ... <meta-data android:name="androidx.car.app.minCarApiLevel" android:value="1" tools:ignore="MetadataTagInsideApplicationTag" /> <meta-data android:name="com.google.android.gms.car.application" android:resource="@xml/automotive_app_desc"/> </application>
automotiveApp を記載した xml リソースを作成する
automotive_app_desc.xml
を作成しましょう。今回のアプリでは、情報を表示するためにテンプレートと言うものを使うことになります。この時、<automotiveApp>
内に利用する旨を宣言する必要があります。
<?xml version="1.0" encoding="utf-8"?> <automotiveApp> <uses name="template" /> </automotiveApp>
もしsmsを利用するアプリを作りたい場合、ここに <uses name="sms" />
を、またメディアアプリを作りたい場合、<uses name="media"/>
を宣言することになります。
androidx.car.app.CarAppService クラスを実装する
Android Auto では、Activity
ではなく Service
が起動されます。そして車向けアプリ用として Service
を拡張した CarAppService
が用意されているので、これを継承する形になります。
class SampleAndroidAutoAppService : CarAppService() { override fun createHostValidator(): HostValidator { return if (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0) { HostValidator.ALLOW_ALL_HOSTS_VALIDATOR } else { HostValidator.Builder(applicationContext) .addAllowedHosts(R.array.hosts_allowlist_sample) .build() } } override fun onCreateSession(): Session { return SampleAndroidAutoAppSession() } }
createHostValidator
は、接続しているホストをチェックするものです。何をチェックしたいのでしょうか?今回の場合、Android Auto アプリからの呼び出しかどうかをチェックしているのです。
今回のコードの場合、デバッグ中は HostValidator.ALLOW_ALL_HOSTS_VALIDATOR
を返すことになります。この実態は空っぽの許可リストを持ち、全てを許可するフラグを ON にした HostValidator クラスのインスタンスです。
@NonNull public static final HostValidator ALLOW_ALL_HOSTS_VALIDATOR = new HostValidator(null, new HashMap<>(), true);
そうでない場合は else に入ることになります。ここでは、R.array.hosts_allowist_sample
をビルダに渡していますが、この中身はどうなっているのでしょう?
<string-array name="hosts_allowlist_sample" translatable="false"> <item>fdb00c43dbde8b51cb312aa81d3b5fa17713adb94b28f598d77f8eb89daceedf, com.google.android.projection.gearhead</item> <item>70811a3eacfd2e83e18da9bfede52df16ce91f2e69a44d21f18ab66991130771, com.google.android.projection.gearhead</item> <item>1975b2f17177bc89a5dff31f9e64a6cae281a53dc1d1d59b1d147fe1c82afa00, com.google.android.projection.gearhead</item> <item>c241ffbc8e287c4e9a4ad19632ba1b1351ad361d5177b7d7b29859bd2b7fc631, com.google.android.apps.automotive.templates.host</item> <item>dd66deaf312d8daec7adbe85a218ecc8c64f3b152f9b5998d5b29300c2623f61, com.google.android.apps.automotive.templates.host</item> <item>50e603d333c6049a37bd751375d08f3bd0abebd33facd30bd17b64b89658b421, com.google.android.apps.automotive.templates.host</item> </string-array>
com.google.android.projection.gearhead
とはなんでしょうか?その答えは Android Auto アプリのパッケージ名です。
https://play.google.com/store/apps/details?id=com.google.android.projection.gearhead&hl=ja&gl=US
試しに、DHU に接続すると com.google.android.projection.gearhead
パッケージ名を検証している様子を窺い知ることができます。
androidx.car.app.CarAppService から起動される androidx.car.app.Session を実装する
Session を実装しましょう。Session は onCreateScreen
に abstract メソッドがあるのですが、これを上書きして Screen
を実装します。この Screen で、カーナビ画面に表示する画面を実装しますが、ここでは Screen
を実装するクラスを別に分けることにします。
class SampleAndroidAutoAppSession : Session() { override fun onCreateScreen(intent: Intent): Screen { return SampleAndroidAutoAppScreen(carContext) } }
Screen
を実装するには carContext
が必要です。これは Session
がプロパティとして持っているのでそのまま渡せば良いです。
androidx.car.app.Session から呼ばれる androidx.car.app.Screen を実装する
クルマの画面に出す UI を実装しましょう!Android Auto では、自由に UI を作成するのは許されていません(とある技を使えばなんでも表示できますが、規約的に許されていません)。Template から選んで表示することになります。 developer.android.com
また、表示内容の更新回数にも厳しい制限があることに注意が必要です。Template によって異なりますが、今回書くコードの場合、6回表示内容を更新したらクラッシュします。 developer.android.com
class SampleAndroidAutoAppScreen(carContext: CarContext) : Screen(carContext) { override fun onGetTemplate(): Template { val carAppLevel = carContext.carAppApiLevel val row = Row.Builder().setTitle("carAppLevel: $carAppLevel").build() val pane = Pane.Builder().addRow(row).build() return PaneTemplate.Builder(pane) .setHeaderAction(Action.APP_ICON) .build() } }
ここまでやれば、とりあえず実行して画面に表示できるはずです!次回は DHU(Desktop Head Unit) を使い、コンピュータの画面上で Android Auto をテストしてみましょう。