こんにちは。KyashのMobileチームに所属しているAndroidエンジニアのどすこいです。
10月下旬にAndroid Dev Summit 2021が開催され、様々なアップデートが公開されましたね。
そこでAppWidgetに関するとても大きなアップデートがありました。今回はそのアップデートに関して一部抜粋して深掘りしていきたいと思います。
※このブログが公開された時点ではAPIが公開されているわけではないので、今後実装方法が変更される可能性があります。ご了承ください。
AppWidgetとは何か
まずはAppWidgetの説明からです。
Android Dev Summitの動画では、アプリを起動しなくてもアプリの機能が一目見てわかるもの、と紹介されています。
公式の方には次のような記述もあり、アプリを開かずにアプリの機能を提供できるものと考えてよいでしょう。
アプリ ウィジェットとは、他のアプリ(ホーム画面など)に埋め込んで定期的に更新を取得することができる小さなアプリビューです。
Widgetには以下のような特徴があります。
- AppWidgetHostのプロセス上にある
- Widgetでできること、表示できることには一定の制限がある
AppWidgetはどのように動くのか
Widgetがどのように振る舞うかを定義したAppWidgetProviderや、metadataを定義したAppWidgetProviderInfoをAndroidManifestに登録すると、OSはWidgetのプレビューを表示できます。
AppWidgetProviderはRemoteViewとWidgetのレイアウトが定義されたxmlを使います。AppWidgetには使えるViewの制限があります*1。
そしてAppWidgetProviderはAppWidgetManagerを通じてWidgetを更新します。
AndroidManifestにはBroadcastReceiverとしてAppWidgetProviderを定義します。OSがブロードキャストイベントを通じて、定期的にWidgetを更新します。
AppWidgetの歴史
AppWidgetのAPIは2008年から提供され、今に至るまで大きく変わってきませんでした。実際、2012年から2021年ではAppWidgetに関するアップデートは1つしかありません。しかしAndroid12では大きなアップデートがあります。
AppWidgetの改善
Rounded corners
今までのAppWidgetはデフォルトでは角が角ばっているものでした。Android12では多くのUI要素が角丸になり、AppWidgetsが他のウィジェットやシステムの外観と一貫して見えるようになりました。
角丸を表現するパラメータが2つ追加されました。
1つ目はAppWidgetの背景の角丸を表す @android:dimen/system_app_widget_background_radius
です。
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <corners android:radius="@android:dimen/system_app_widget_background_radius"/> </shape>
2つ目は似たようなパラメータで、AppWidgetの中のViewの角丸を表す @android:dimen/system_app_widget_inner_radius
です。
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <corners android:radius="@android:dimen/system_app_widget_inner_radius"/> </shape>
Responsive Layout
Responsive Layoutを実現するために新たなAPIが追加されました。
まずはコードを見てみましょう。
SizeF(180f, 110f) to RemoteViews( context.packageName, R.layout.widget_small ) SizeF(270f, 110f) to RemoteViews( context.packageName, R.layout.widget_medium ) SizeF(270f, 280f) to RemoteViews( context.packageName, R.layout.widget_large )
例えば縦幅が110dp固定の時、Widgetの横幅が180dp以上269dp以下の場合はR.layout.widget_smallのレイアウトがWidgetに適用され、それ以上の場合は270dpをサポートしているR.layout.widget_mediumが適用されます。
同様に横幅が180dp固定の時、Widgetの縦幅が110dp以上279dp以下の場合はR.layout.widget_smallのレイアウトがWidgetに適用され、それ以上の場合は280dpをサポートしているR.layout.widget_largeが適用されます。
横幅が270dp固定の時も同じように、Widgetの縦幅が110dp以上279dp以下の場合はWidgetにR.layout.widget_mediumのレイアウトが適用され、それ以上の場合は280dpをサポートしているR.layout.widget_largeが適用されるという仕組みです。
Sizing
サイズを設定するための新しいattributeが追加されました。
今まではminWidth, minHeightでの指定しかできず、端末の横幅や縦幅によって使うセルの数が違ってきましたが、Android12から使うセルの数を指定できるため端末によっての差異がなくなるだろうと考えられます。
ComposeによるWidgetの作成
今回のアップデートの目玉はこれでしょう。
今まではRemoteViewの制約により、Widget内で使えるViewの種類には限りがありました。この制約によりWidget作成に苦戦した方も少なくないかと思います。
ですが、Android12からはComposeによるWidget作成が可能になります。
Glanceとは
今回新たに追加されたAPIにGlanceというものがあります。
Glanceは、Compose Runtimeを経由して従来のRemoteViewに置き換えてくれる仕組みです。
これにより開発者はRemoteViewの制限に苦しめられることなく、ComposeでUIを表現できるようになります。
Creating a Glance AppWidget
今までのAppWidgetと同じようにAndroidManifestにGlanceAppWidgetProviderを宣言を忘れないようにしましょう。
次にこちらのGlanceAppWidgetを継承したクラスのContent関数内でComposeを書いていきます。
Content関数自体がComposableな関数になっているので、開発者はこの関数内でComposeを書けるようになります。
GlanceAppWidget内で使えるComposeは従来のComposeとよく似ていますが、AppWidgetに対応して少し違う箇所があります。
Column( modifier = Modifier.expandHeight().expandWidth() ) { ... }
親Viewいっぱいまで広げたい時、ComposeであればfillMaxHeight()やfillMaxWidth()を使いますが、上のコードにもある通り、GlanceAppWidgetではexpandHeight()やexpandWidth()を使っています。
まだAPIが公開されていないので、どれほど従来のComposeと違いがあるかはわかりませんが、実際に導入する時には公式のドキュメントや実装を読んで使っていく必要がありそうです。
またなぜ従来のComposeと違った関数名なのか深掘りするのも面白そうですね。
Handle user interaction
ユーザーの操作のハンドリングも以前よりも相当楽になりました。
今まではButtonが押下された時、Activityに飛ばすPendingIntentを発行して、RemoteViewのあるidに対して
view.setOnClickPendingIntent(R.id.button, pendingIntent)
などとしなくてはいけませんでしたが、今回のアップデートでは
Modifier.clickable(launchActivity<HogeActivity>(..))
これだけで良くなりました。 非常に簡潔ですね。
WorkManagerの起動などのカスタムアクションの実行も簡単になりました。
Modifier.clickable(customAction<HogeAction>(..))
これだけです。
また、従来のAppWidgetProviderには、onUpdateでWorkManagerを起動すると、onUpdateの無限ループに入ってしまうというバグがありました。(Googleの人曰く、バグというよりも仕様)
ですが、今回のアップデートでネットワーク通信をする場合はWorkManagerを使いましょうという発表があったため、上記の無限ループは回避できるようになったことを期待しています。
Responsive Layout for Compose
ComposeによるResponsive Layoutのオプションも3つ提供されています。
- Single
- Exact
- Reponsive
1つずつ紹介していきます。
Single
Singleはサイズ変更自体は可能なWidgetですが、UIの更新はされずに単にスケール処理されます。
Singleがデフォルトのオプションです。
Exact
ユーザーがWidgetのサイズを変更し、その度にUIの表示を変更したいときはExactを使いましょう。
Responsive
ユーザーがWidgetのサイズを変更し、その度に表示するUIそのものを変えたい場合(smallの時はリストを出さず、mediumからリストを表示するなど)は、Reponsiveを使うことをおすすめします。 DpSize形式で、わかりやすいように特定の形状のWidgetのサイズをマッピングしています。
最後に
Android Dev Summit 2021はとてもワクワクする内容ばかりでしたね!
Room2.4のAuto Migrationも気になりますし、foldable端末の対応も各企業どう行なっていくかも楽しみにしています。
その中でも今までほとんど大きな変化のなかったAppWidgetの内容がここまでアップデートされたのは個人的にものすごくびっくりしました。APIが公開されたらいち早く触ってみたいですね。
Kyashでは一緒に働くAndroidエンジニアを募集しています。
最新の技術やバージョン更新に気を配りつつプロダクトへの導入を積極的に行っています。
流行りのJetpack Composeだけでなく、アクセシビリティ対応であったり、当人のやりたいことを実現できる環境だと感じています。
興味がありましたら、ぜひ下記のリンクからカジュアルにお話ししましょう!