Wear OS by Google アプリ開発はじめの一歩

木村
ソフトウェア開発部IoTグループの木村です。乗務員さん向けに提供しているJapanTaxi DRIVER’SというサービスのAndroidアプリ開発を担当しています。

JapanTaxi Advent Calendar 2018 16日目の記事です。

はじめに

日本ではウェアラブルOSといえばAppleWatchに搭載されているWatchOSが知られていますが、
GoogleでもWear OS By GoogleというウェアラブルOSが提供されています。
この記事ではWear OS by Google向けウェアラブルアプリ開発を始めるための準備やウェアラブルアプリ向けのUIを簡単に実装できるWear UI Libraryについて紹介します。

Wear OS by Googleについて

GoogleのウェアラブルOSは2014年6月にAndroid Wearという名称のAndroidベースの独立したウェアラブルOSとして提供されましたが、2018年3月にWear OS by Google 1.0 としてリニューアルされ、2018年12月現在ではWear OS by Google 2.1が最新バージョンとなっています。

Wear OS 向けの開発機能は以下のものが提供されています。

  • ウェアラブルアプリの作成
  • ウォッチフェイスの作成
  • 通知の作成
  • Actions on Google を用いた音声操作

今回は ウェアラブルアプリの作成 について、スタンドアロンアプリの開発環境の準備からウェアラブル用レイアウトの簡単な利用法について紹介します。

スタンドアロンアプリ

Android Wear 1.xではウェアラブルアプリのAPKはスマートフォン側のAPKに内包する必要があり、あくまでスマートフォンと連動する機能として提供されていました。しかしAndroid Wear 2.0よりスタンドアロンアプリが導入されたことによりウェアラブル用APKをスマートフォンのAPKに内包する必要がなく、ウェアラブルデバイス上で単独動作し、GooglePlayからの直接インストールも可能となりました。国内ではAndroid Wear 1.xのデバイスはあまり流通していないので特別な理由がない限りはスタンドアロンアプリとして開発するのがよいでしょう。

app/build.gradle

スタンドアロンアプリの開発を行うためにはAndroid Wear 2.0のベースであるAndroid7.1.1(APILevel 25)以上の開発環境が必要となります。

android {
    ...
    defaultConfig {
        minSdkVersion 25
        ...
    }
}

AndroidManifest.xml

マニフェストに以下の定義をすることでWearOSアプリとして認識されます。

インストール対象の準備

ウェアラブルアプリをインストールするにはウェアラブルデバイスの実機かエミュレーターを用意する必要があります。

実機との接続

実機にインストールするには通常のAndroid端末同様に開発者オプションを有効にしてデバッグを有効にする必要があります。

SettingsSystemAboutを開きBuild numberを7回タップして開発者オプションを有効にします。
wearos_settingswearos_system
wearos_aboutwearos_build_number
wearos_you_are_now_a_developer

SettingsDeveloper optionsADB debuggingをONにします。
developer_optionswearos_adb_debuging

これでUSB接続であればデバックが可能ですがWear OSを搭載しているデバイスの多くは無接点充電を採用しており、USB接続ができません。その場合は次のような無線接続でデバッグを行うことが可能です。

Wi-Fi経由で接続する

SettingsDeveloper optionsDebug over Wi-FiをONにします。
(表示されるウェアラブルデバイスのIPアドレスは後ほどで利用します)
wearos_wifi_debug
以下のコマンドを実行しADBをTCP/IP接続モードに変更します。

$ adb tcpip 5555
restarting in TCP mode port: 5555

Debug over Wi-FiをONにした際に表示されたIPアドレスに対してADB接続します。

$ adb connect xxx.xxx.xxx.xxx

結果が以下のようになる場合はウェアラブルデバイス側で接続を許可するか表示されるので許可を選択する必要があります。

failed to authenticate to xxx.xxx.xxx.xxx:5555

正しくされると以下の表示になります。

connected to xxx.xxx.xxx.xxx:5555

接続の解除する際は以下のコマンドを実行します。

$ adb disconnect
disconnected everything

※Wi-Fi経由でデバッグするにはウェアラブルデバイスとAndroidStudioを実行しているデバイスが同一のLANに接続している必要があります。

Bluetooth経由で接続する

SettingsDeveloper optionsDebug over BluetoothをONにします。
wearos_bluetooth_debug

ウェアラブルデバイスとペアリングしているスマートフォンをAndroidStudioを実行しているデバイスにADB接続し、スマートフォン内のWearOSアプリ内でBluetooth経由のデバッグをONにします。

wearosapp_bluetooth_off

以下のコマンドを実行して特定のポートへの接続をウェアラブルデバイスに転送します。
(ポート番号は任意のもので大丈夫です)

$ adb forward tcp:4444 localabstract:/adb-hub

設定したポート番号で接続します。

$ adb connect localhost:4444
connected to localhost:4444

接続が成功するとWearOSアプリでは以下の表示になります。
wearosapp_bluetooth_on
接続を解除するにはスマートフォンのADB接続を解除するか以下のコマンドを実行します。

$ adb disconnect
disconnected everything

仮想デバイスを作成する

ここまで実機との接続について記載しましたが、ウェアラブルデバイスの仮想デバイスを作成して接続する方法もあります。
仮想デバイスの作成については従来のAndroidデバイスと同じくAndroidStudioからToolsAVD Managerを起動し、Create Virtual DeviceWearで行います。
wearos_create_virtual_device
WearOSデバイスのディスプレイは以下の種類から作成することができます。

  • Square – 四角形ディスプレイ
  • Round – 円形ディスプレイ
  • Round Chin – 円形ディスプレイの下部が欠けているタイプ

この内、RoundとRound ChinはWear OSの特徴の一つでもある特殊な形状のディスプレイです。
従来のアナログな時計と同じ円形の形状を保ちつつ円形のディスプレイに最適化されたUXを実現するためのサポートライブラリが提供されています。

Wear UI Library

Wear OS 向けウェアラブルアプリでは画面が小さいことや前述した円形ディスプレイなど通常のスマートフォンとは異なる配慮が必要となります。
ウェアラブルに特化したUIコンポーネントを利用できるWear UI Libraryというサポートライブラリが提供されているため、その一部を紹介します。

導入方法

サポートライブラリとしての提供なので他のサポートライブラリとのバージョンを合わせてください

dependencies {
    implementation "com.android.support:wear:$support_lib_version"
}

BoxInsetLayout

従来のAndroidアプリ同様にボタンを配置した場合、以下のよう表示になります。

Square

wearod_button_square

Round

wearod_button_round

Squareでは問題がありませんがRoundだとボタンの端が見切れてしまっています。
円形ディスプレイでも見切れないように表示するにはBoxInsetLayoutを利用します。

wearod_button_round_box_inset

重要なのはapp:boxedEdges="all"の箇所でこの指定をすると円形ディスプレイの時に上下左右方向が見切れないように調整してくれます。リストなどで上下は制限したくない場合などはapp:boxedEdges="left|right"とすることで左右のみの調整も可能です。

ConfirmationActivity

ウェアラブルデバイスは画面が小さいので操作した結果を大きなアニメーションで見せることで遠目でもわかりやすくなります。その機能を提供しているのがConfirmationActivityです。
利用方法は簡単で呼び出す際に用意されているパラメータとメッセージを付与するだけです。

button1.setOnClickListener {
    val intent = Intent(this, ConfirmationActivity::class.java).also {
        it.putExtra(ConfirmationActivity.EXTRA_ANIMATION_TYPE, ConfirmationActivity.SUCCESS_ANIMATION)
        it.putExtra(ConfirmationActivity.EXTRA_MESSAGE, "success")
    }
    startActivity(intent)
}
button2.setOnClickListener {
    val intent = Intent(this, ConfirmationActivity::class.java).also {
        it.putExtra(ConfirmationActivity.EXTRA_ANIMATION_TYPE, ConfirmationActivity.OPEN_ON_PHONE_ANIMATION)
        it.putExtra(ConfirmationActivity.EXTRA_MESSAGE, "open on phone")
    }
    startActivity(intent)
}
button3.setOnClickListener {
    val intent = Intent(this, ConfirmationActivity::class.java).also {
        it.putExtra(ConfirmationActivity.EXTRA_ANIMATION_TYPE, ConfirmationActivity.FAILURE_ANIMATION)
        it.putExtra(ConfirmationActivity.EXTRA_MESSAGE, "failure")
    }
    startActivity(intent)
}

confirmation

CircularProgressLayout

ウェアラブルデバイスではタップ領域が小さいこともあり操作のたびにダイアログが表示されると億劫に感じてしまいがちです。その場合は都度ダイアログ出すより、一定時間キャンセルの時間を設けてキャンセルされなければ処理を進めるUIを採用すればタップ回数が減らせることができます。
CircularProgressLayoutを利用すればそのようなUIが簡単に実装できます。

circularProgress.let{
    it.setOnTimerFinishedListener {
        val intent = Intent(this, ConfirmationActivity::class.java).also {
            it.putExtra(ConfirmationActivity.EXTRA_ANIMATION_TYPE, ConfirmationActivity.SUCCESS_ANIMATION)
            it.putExtra(ConfirmationActivity.EXTRA_MESSAGE, "success")
        }
        startActivity(intent)
        finish()
    }
    it.setOnClickListener {
        Toast.makeText(this, "canceled", Toast.LENGTH_SHORT).show()
        circularProgress.stopTimer()
        finish()
    }
    it.totalTime = 3000
    it.startTimer()
}

circleprogresslayout

WearableRecyclerView

円形ディスプレイでも無駄なくスクロールできるようにウェアラブルデバイス向けのRecyclerViewとしてWearableRecyclerViewが用意されています。

使い方は非常に簡単でlayoutManagerにWearableLinearLayoutManagerを設定するだけです。adapterは従来のRecyclerViewで利用しているRecyclerView.Adapterがそのまま利用可能です。

wearableRecyclerView.let {
  it.isEdgeItemsCenteringEnabled = true
  it.layoutManager = WearableLinearLayoutManager(this@WearableRecyclerViewActivity)
  it.adapter = adapter
}

wearablerecyclerview

SwipeDismissFrameLayout

スワイプでViewGroupの削除を実装できるSwipeDismissFrameLayoutもあります。これはRecyclerViewにItemTouchHelperを追加してItemTouchHelper.ACTION_STATE_SWIPEを指定した場合と同様の動きが簡単に実現できるウェアラブル向けレイアウトです。WearableRecyclerViewとの相性も良く、簡単に実装することが可能です。

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    holder.itemView.swipeDismissLayout.addCallback(object : SwipeDismissFrameLayout.Callback() {
        override fun onDismissed(layout: SwipeDismissFrameLayout) {
            holder.itemView.visibility = View.INVISIBLE
            listener?.onDismiss(holder.adapterPosition)
        }
    })
    holder.itemView.visibility = View.VISIBLE
    holder.itemView.rowText.text = list[holder.adapterPosition]
}

swipedismissframelayout

まとめ

いつものAndroidとは違うウェアラブルに特化したUIはいかがでしたでしょうか?
Wear UI Libraryで提供されているコンポーネントは他にも色々あるので興味があれば触ってみもらえればと思います。最後まで読んでいただきありがとうございました!

JapanTaxiでは、ITの力で「移動で人を幸せに。」を実現するための一連のサービス開発に取り組んでいます。全部署にてメンバーも積極的に募集しているので、興味のある方はWantedlyもぜひご覧ください!

JapanTaxiに興味を持ったら、まずはお話しませんか?