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

https://cdn-ak.f.st-hatena.com/images/fotolife/g/go_dev/20241030/20241030152309.jpg

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 向けの開発機能は以下のものが提供されています。

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

スタンドアロンアプリ

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回タップして開発者オプションを有効にします。

https://cdn-ak.f.st-hatena.com/images/fotolife/g/go_dev/20241030/20241030152310.jpg

SettingsDeveloper optionsADB debuggingをONにします。

https://cdn-ak.f.st-hatena.com/images/fotolife/g/go_dev/20241030/20241030152303.jpg

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

Wi-Fi経由で接続する

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

https://cdn-ak.f.st-hatena.com/images/fotolife/g/go_dev/20241030/20241030152301.jpg

$ 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にします。

https://cdn-ak.f.st-hatena.com/images/fotolife/g/go_dev/20241030/20241030152304.jpg

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

https://cdn-ak.f.st-hatena.com/images/fotolife/g/go_dev/20241030/20241030152305.jpg

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

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

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

$ adb connect localhost:4444
connected to localhost:4444

接続が成功するとWearOSアプリでは以下の表示になります。

https://cdn-ak.f.st-hatena.com/images/fotolife/g/go_dev/20241030/20241030152302.jpg

接続を解除するにはスマートフォンのADB接続を解除するか以下のコマンドを実行します。

$ adb disconnect
disconnected everything

仮想デバイスを作成する

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

https://cdn-ak.f.st-hatena.com/images/fotolife/g/go_dev/20241030/20241030152312.jpg

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

https://cdn-ak.f.st-hatena.com/images/fotolife/g/go_dev/20241030/20241030152259.jpg

Round

https://cdn-ak.f.st-hatena.com/images/fotolife/g/go_dev/20241030/20241030152300.jpg

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

https://cdn-ak.f.st-hatena.com/images/fotolife/g/go_dev/20241030/20241030152258.jpg

重要なのは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)
}

https://cdn-ak.f.st-hatena.com/images/fotolife/g/go_dev/20241030/20241030152306.jpg

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()
}

https://cdn-ak.f.st-hatena.com/images/fotolife/g/go_dev/20241030/20241030152308.jpg

WearableRecyclerView

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

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

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

https://cdn-ak.f.st-hatena.com/images/fotolife/g/go_dev/20241030/20241030152311.jpg

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]
}

https://cdn-ak.f.st-hatena.com/images/fotolife/g/go_dev/20241030/20241030152307.jpg

まとめ

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

Mobility Technologies では共に日本のモビリティを進化させていくエンジニアを募集しています。話を聞いてみたいという方は、是非 募集ページ からご相談ください!