このドキュメントを読んだので超ざっくりまとめる。
基本的に、この機能はこの為にありますとか、こういうデザインにしましょうという話はしない。
デザインのガイドラインがあるので一度目を通しておくといいかも。
あとツールの使い方とか、細かい手順も省略。
通知編
※Androidに以前からあった通知機能については触れないので悪しからず
Handheld(電話とかタブレット)とWearableが接続してると、Handheldの通知が自動でWearableにも共有される(とは言え、Wearable固有の機能性を通知に追加するとUX的にいいよ)。
通知を作る
-
NotificationCompat.Builder
で通知を作る(従来の方法と同じ) -
NotificationCompat.Builder#addAction
でアクションボタンを追加できる(従来の方法と同じ)
Wearableだけのアクションボタン
-
NotificationCompat.WearableExtender
というクラスをインスタンス化して使う -
WearableExtender#addAction
に(従来の方法で作った)NotificationCompat.Action
を渡す -
NotificationCompat.Builder#extend
にWearableExtender
を渡す - 一度でもこの方法でアクションボタンを追加すると
NotificationCompat.Builder#addAction
で追加されたアクションボタンはWearableの方では表示されなくなる
Big View
-
BigTextStyle
またはInboxStyle
のスタイルが適用された通知は、Wearable側でもいい感じに表示される - スタイルの設定の仕方は、従来のやり方と同じ
通知にWearable固有の機能を追加する
先に少し触れたけどWearableExtender
というクラスをインスタンス化して使う。これに対して必要なプロパティを設定していく。そしてこのWearableExtender
インスタンスをNotificationCompat.Builder#extend
でセットすればOK。
通知を伝える
-
NotificationManagerCompat
を使う -
NotificationManager
だとWearableExtender
で追加した機能が動かないよ
音声入力を受信する
- メールの返信とかテキストを入力するアクションを含んだ通知では、普通はアクティビティを起動してテキストを入力していく
- そのような通知がWearableにあるとき、キーボードからの入力じゃなくてユーザにしゃべらせたり事前に定義しといたテキストを選んでもらうことができる
- そのテキストが付加されたインテントをhandheldのアプリに送信できるよ
- エミュレータでは音声入力できないのでキーボードで入力する
音声入力の定義
-
RemoteInput.Builder
をインスタンス化して使う - コンストラクタは文字列を受け取る: 入力されたテキストを取得するために使うKey
-
RemoteInput.Builder#setChoices
にCharSequence
配列を渡すと、それが事前定義されたテキストとしてユーザは音声入力の代わりに選択できる
通知のアクションとして音声入力を追加する
-
RemoteInput
オブジェクトをNotificationCompat.Action.Builder#addRemoteInput
に渡すことでアクションに音声入力を追加できる
文字列として音声入力を受け取る
- アクションのインテントに
RemoteInput.getResultsFromIntent
を適用して得られるBundle
から取得する - その
Bundle
から、RemoteInput.Builder
のコンストラクタ呼び出し時に渡したKeyで音声入力を文字列として取得する
通知にページを追加する
-
NotificationCompat.Builder
を使って従来と同じ方法で通知を作る(これがWearable側でのメイン、つまり最初のページになる) -
NotificationCompat.Builder
を使ってWearable用の追加ページとしてNotification
を作る -
WearableExtender
のaddPage
メソッドやaddPages
メソッドを使って複数ページのあるNotification
を作る
通知をスタックする
通知をスタック内にグルーピングする方法。
通知をグループに追加する
-
NotificationCompat.Builder#setGroup
を使って当該の通知をグループに追加する -
setGroup
は引数にGroupKey(String
)を取る - ビルドした通知は普通に
NotificationManagerCompat#notify
で発行する - 後ほど同一GroupKeyを持った別の通知が発行された際には、同じスタック内に表示される
Summary Notificationを追加する
- Summary Notificationは、Wearable側では表示されずHandheld側でのみ表示される
-
NotificationCompat.Builder#setGroupSummary
にtrue
を渡すとそれはSummary Notificationになる - グループのSummary(要約)となる通知なので、もちろん
setGroup
でGroupKeyを指定すること - Summary NotificationはWearableには表示されないけど影響を与える:
WearableExtender
でsetBackground
やaddAction
の呼び出しなど(例えばスタック全体の背景を指定したいとき)
Wearable用アプリ編
基本的に普通のアプリと同じ。
だけどデザイン、ユーザビリティ、機能の量で大きく異なるので注意。
↓主な違い
- アクティビティはずっと表示できない。スリープから復帰したらWearホーム画面が表示される。ずっと表示したいのがあるときは通知でやること。
- WearableはHandheldと比べるとサイズも機能も小さい。なので操作は極力Handheldで行い、結果をWearableに送る感じで。
- ユーザはWearableに直接アプリをダウンロードしない。WearableアプリはHandheldアプリにバンドルされてて、Handheldアプリがインストールされるときにシステムが自動でWearableアプリもインストールしてくれる。開発のために直接Wearablにインストールすることはできる。
- Wearableアプリは標準のAndroid APIの大部分にアクセスできるけど、次に挙げるのはダメ
- android.webkit
- android.print
- android.app.backup
- android.appwidget
- android.hardware.usb
Wearableアプリを作って動かす
Android Wearエミュレータ、デバイスのセットアップやプロジェクト作成、インストールについてはこちらを参照。
カスタムレイアウトを作る
Custom Notification
- カスタムレイアウトをアクティビティに載っけて、それで通知できる(ただしHandheldとの自動同期はない)
- アクティビティはマニフェストで、
android:exported="true"
android:allowEmbedded="true"
android:taskAffinity=""
と設定する必要がある - アクティビティのテーマを
Theme.DeviceDefault.Light
にするといいよ - このアクティビティを起動する
PendingIntent
を作る -
WearableExtender#setDisplayIntent
でそのPendingIntent
を設定する - あとは普通に通知を
notify
すればいい
Wearable UI Library
Android Studioで使える非公式のUIライブラリがあるらしい。こちらを参照。
音声機能を追加する
WearはSystem-providedとApp-providedの2種類の音声アクションを提供している。
System-provided
- システム、つまりAndroid Wearプラットフォームが提供する音声アクション
- ユーザがしたいことを言って、システムがそれを理解してアクティビティを起動する
- 具体的にはインテントフィルタで音声アクションを拾う感じ
Wearがサポートする音声インテント一覧はこちらを参照。
App-provided
- 音声アクションによって直接アクティビティを起動できる
- "Start <アクティビティ名>"みたいに言うと、対象のアクティビティが起動する(日本語の場合はどうなんだろ?)
- このアクティビティは、Handheld上でランチャーアイコンから起動するやつと同じ
- <アクティビティ名>はマニフェストでアクティビティに設定した
android:label
の値
Wearableアプリをパッケージングする
- WearableアプリはHandheldアプリ内にパッケージする必要がある
- ユーザはWearableアプリを直接インストールすることはできないから
- システムが自動的にWearableにWearableアプリをプッシュする
Android Studioを使った、あるいは手作業でのパッケージング手順はこちらを参照。
データの送信、同期編
Google Play Servicesの一部であるWearable Data Layer APIは、Handheld-Wearableアプリ間の通信チャネルを提供する。
Data Itemsを同期する
- DataItemはHandheld-Wearable間のデータ同期のためのインタフェースを定義する
- DataItemは一般に、PayloadとPathで構成される
- Payloadは最大100KBのbyte配列(だから好きなデータを載せられるしオブジェクトのシリアライズ/デシリアライズも可能)
- Pathはスラッシュから始まるユニークな文字列(例えば"/path/to/data")
普通はDataItemを直接実装することはない。代わりに
- アイテムを一意に識別するPathを指定して
PutDataRequest
オブジェクトを生成する -
setData
メソッドでPayloadをセットする -
DataApi.putDataItem
を呼び出し、Data Itemの生成を要求する - Data Itemsが要求されるとシステムは
DataItem
インタフェースを適切に実装したオブジェクトを返す
setData
の代わりに次に紹介するData Mapの方が簡単なのでおすすめらしい。
Data Mapで同期する
-
Bundle
に似たインタフェースのDataMap
クラスを使うといいよ -
PutDataMapRequest
オブジェクトを生成してgetDataMap
メソッドでData Mapを取得できる - put...メソッド(例えば
putString
)で必要な値をセットできる -
PutDataMapRequest.asPutDataRequest
でPutDataRequest
が取得できるのでDataApi.putDataItem
に渡してData Itemを生成する
Data Itemイベントをリスンする
Assetの転送
- 画像のようなBLOBをBluetoothで送るには、AssetをData Itemに付加する
- Assetは再送を防ぐため、Bluetoothの帯域幅を節約するためにデータのキャッシュを自動的に扱う
Assetを転送する
- Assetを作るには、
Asset
クラスのcreate...メソッドを使う(例えばcreateFromBytes
) - Assetを得たら
DataMap
とかPutDataRequest
にputAsset
する。
Assetを受信する
メッセージの送受信
- メッセージはData Itemと違ってHandheld-Wearable間同期はないよ
- メッセージは"fire-and-forget"的な片方向通信
- メッセージを送って、なんかして、メッセージを送り返せばrequest/responseモデルにもできる
メッセージを送信する
接続相手側のアクティビティを起動させるメッセージを送るサンプルコード
このコードは、メッセージが受信されるかタイムアウトするまでブロックするらしい
メッセージを受信する
Data Layerイベントのハンドル
Data Layerの呼び出しのステータスを待つ
- Data Layer APIは
PendingResult
を返すことがある(例えばputDataItem
) -
PendingResult
を使って同期的にも非同期的にもオペレーションの結果を得られる -
PendingResult#await
で同期的に結果を得る -
PendingResult#setResultCallback
で非同期で結果を得る
Data Layerイベントをリスンする
Data Layerイベントをリスンするには、WearableListenerService
を継承したサービスを作るか、リスナを実装したアクティビティを作るかの2つの選択肢がある。
WearableListenerService
WearableListenerService
固有のメソッド
-
onDataChanged
: Data Itemオブジェクトの生成、変更、削除時に呼び出される。接続している片方で起こったイベントは、双方に通知される -
onMessageReceived
: 接続相手が送ったメッセージを受信したときに呼び出される -
onPeerConnected
とonPeerDisconnected
: 接続したとき、切断したときに呼び出される。接続している片方で起こったイベントは、双方に通知される
WearableListenerService
を継承したサービスは、上記のメソッドを必要に応じて実装して、com.google.android.gms.wearable.BIND_LISTENER
アクションを拾うようにインテントフィルタを設定する。
Data Layerコールバック内のパーミッション
- Data Layerコールバック内でパーミッションが必要な操作を行うと失敗する: IPCにより呼び出されるため
-
Binder.clearCallingIdentity
メソッドを呼び出せば大丈夫 - 最後に
Binder.restoreCallingIdentity
を呼び出して元に戻すこと
リスナアクティビティ
次のリスナを1つ以上実装すればアクティビティでイベントをリスンできる。
DataApi.DataListener
MessageApi.MessageListener
NodeApi.NodeListener
アクティビティのライフサイクルに合わせていろいろやる必要がある(詳細は公式ドキュメントを参照)。