以降のセクションでは、Glance を使用して基本的なアプリ ウィジェットを作成する方法について説明します。
マニフェストで AppWidget を宣言する
設定手順を完了したら、アプリで AppWidget とそのメタデータを宣言します。
GlanceAppWidgetReceiverからAppWidgetレシーバーを拡張します。class MyAppWidgetReceiver : GlanceAppWidgetReceiver() { override val glanceAppWidget: GlanceAppWidget = TODO("Create GlanceAppWidget") }
AndroidManifest.xmlファイルと関連するメタデータ ファイルにアプリ ウィジェットのプロバイダを登録します。<receiver android:name=".glance.MyReceiver" android:exported="true"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/my_app_widget_info" /> </receiver>
AppWidgetProviderInfo メタデータを追加する
次に、ウィジェットを作成するガイドに沿って、@xml/my_app_widget_info ファイルでアプリ ウィジェット情報を作成して定義します。
Glance の唯一の違いは、initialLayout XML がないことですが、定義する必要があります。ライブラリに用意されている事前定義の読み込みレイアウトを使用できます。
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/glance_default_loading_layout">
</appwidget-provider>
AppWidgetProviderInfo XML を宣言する
AppWidgetProviderInfo オブジェクトは、ウィジェットの重要な特性を定義します。XML メタデータ リソース ファイル(res/xml/my_app_widget_info.xml)の <appwidget-provider> 要素内で AppWidgetProviderInfo を定義します。
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="40dp"
android:minHeight="40dp"
android:targetCellWidth="1"
android:targetCellHeight="1"
android:maxResizeWidth="250dp"
android:maxResizeHeight="120dp"
android:updatePeriodMillis="86400000"
android:description="@string/example_appwidget_description"
android:previewLayout="@layout/example_appwidget_preview"
android:initialLayout="@layout/glance_default_loading_layout"
android:configure="com.example.android.ExampleAppWidgetConfigurationActivity"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen"
android:widgetFeatures="reconfigurable|configuration_optional">
</appwidget-provider>
ウィジェットのサイズ設定属性
デフォルトのホーム画面では、高さと幅が定義されたセルのグリッドに基づいて、ウィンドウ内にウィジェットが配置されます。ほとんどのホーム画面では、ウィジェットのサイズはグリッドセルの整数倍(横 2 セル、縦 3 セルなど)にしかできません。
ウィジェットのサイズ属性を使用すると、ウィジェットのデフォルト サイズを指定し、ウィジェットのサイズの下限と上限を指定できます。このコンテキストでは、ウィジェットのデフォルト サイズは、ウィジェットが最初にホーム画面に追加されたときのサイズです。
次の表に、ウィジェットのサイズ設定に関連する <appwidget-provider> 属性を示します。
| 属性と説明 | |
|---|---|
targetCellWidth、targetCellHeight(Android 12)、minWidth、minHeight |
targetCellWidth と targetCellHeight、minWidth と minHeight の両方の属性セットを指定することをおすすめします。これにより、ユーザーのデバイスが targetCellWidth と targetCellHeight をサポートしていない場合、アプリは minWidth と minHeight の使用にフォールバックできます。サポートされている場合、targetCellWidth 属性と targetCellHeight 属性は minWidth 属性と minHeight 属性よりも優先されます。 |
minResizeWidth、minResizeHeight |
ウィジェットの絶対最小サイズを指定します。これらの値は、ウィジェットが判読不能になるか、使用できなくなるサイズを指定します。これらの属性を使用すると、ユーザーはウィジェットのサイズをデフォルトのウィジェット サイズよりも小さく変更できます。minResizeWidth 属性が minWidth より大きい場合、または水平方向のサイズ変更が有効になっていない場合、この属性は無視されます。resizeMode をご覧ください。同様に、minResizeHeight 属性が minHeight より大きい場合、または垂直方向のサイズ変更が有効になっていない場合、この属性は無視されます。 |
maxResizeWidth、maxResizeHeight |
ウィジェットの推奨最大サイズを指定します。値がグリッドセルの寸法の倍数でない場合は、最も近いセルサイズに切り上げられます。maxResizeWidth 属性は、minWidth より小さい場合、または水平方向のサイズ変更が有効になっていない場合は無視されます。resizeMode をご覧ください。同様に、maxResizeHeight 属性は、minHeight より小さい場合、または垂直方向のサイズ変更が有効になっていない場合は無視されます。Android 12 で導入されました。 |
resizeMode |
ウィジェットのサイズ変更に関するルールを指定します。この属性を使用すると、ホーム画面のウィジェットを水平方向、垂直方向、または両方向にサイズ変更可能にできます。ユーザーがウィジェットを長押しすると、サイズ変更ハンドルが表示されます。水平ハンドルまたは垂直ハンドルをドラッグして、レイアウト グリッド上のサイズを変更します。resizeMode 属性の値には、horizontal、vertical、none があります。ウィジェットを水平方向と垂直方向にサイズ変更可能として宣言するには、horizontal|vertical を使用します。 |
例
上の表の属性がウィジェットのサイズ設定にどのように影響するかを説明するため、次の仕様を想定します。
- グリッドセルの幅は 30 dp、高さは 50 dp です。
- 次の属性仕様が提供されます。
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="80dp"
android:minHeight="80dp"
android:targetCellWidth="2"
android:targetCellHeight="2"
android:minResizeWidth="40dp"
android:minResizeHeight="40dp"
android:maxResizeWidth="120dp"
android:maxResizeHeight="120dp"
android:resizeMode="horizontal|vertical" />
Android 12 以降:
targetCellWidth 属性と targetCellHeight 属性をウィジェットのデフォルト サイズとして使用します。
ウィジェットのデフォルトのサイズは 2x2 です。ウィジェットのサイズは、2x1 まで縮小、4x3 まで拡大できます。
Android 11 以前:
minWidth 属性と minHeight 属性を使用して、ウィジェットのデフォルト サイズを計算します。
デフォルトの幅 = Math.ceil(80 / 30) = 3
デフォルトの高さ = Math.ceil(80 / 50) = 2
ウィジェットのデフォルトのサイズは 3x2 です。ウィジェットは 2x1 まで縮小したり、全画面表示まで拡大したりできます。
その他のウィジェット属性
次の表に、ウィジェットのサイズ設定以外の品質に関連する <appwidget-provider> 属性を示します。
| 属性と説明 | |
|---|---|
updatePeriodMillis |
ウィジェット フレームワークが onUpdate() コールバック メソッドを呼び出して GlanceAppWidgetReceiver からの更新をリクエストする頻度を定義します。バッテリーを節約するため、更新頻度はできるだけ低く(1 時間に 1 回以下)することをおすすめします。詳細については、Glance の状態管理の ウィジェットを更新するタイミング セクションを参照してください。 |
initialLayout |
Glance UI コンポジションがレンダリングされる前に、ウィジェットの読み込みレイアウトを定義するレイアウト リソースを指します。ライブラリで提供されている事前定義の読み込みレイアウト @layout/glance_default_loading_layout を使用できます。 |
configure |
ユーザーがウィジェットを追加したときに起動する構成アクティビティを定義します。ユーザーがアプリ ウィジェットを構成できるようにするガイドをご覧ください。 |
description |
ウィジェット選択ツールに表示されるウィジェットの説明を指定します。Android 12 で導入されました。 |
previewLayout(Android 12)、previewImage(Android 11 以前) |
|
autoAdvanceViewId |
ウィジェットのホストによって自動的に進められるウィジェット サブビューのビュー ID を指定します。 |
widgetCategory |
ウィジェットをホーム画面(home_screen)、ロック画面(keyguard)、またはその両方に表示できるかどうかを宣言します。Android 5.0 以降では、home_screen のみが有効です。 |
widgetFeatures |
ウィジェットがサポートする機能を宣言します。たとえば、ウィジェットの構成がオプションの場合は、configuration_optional と reconfigurable の両方を指定します。 |
GlanceAppWidget を定義する
GlanceAppWidgetを拡張してprovideGlanceメソッドをオーバーライドする新しいクラスを作成します。このメソッドでは、ウィジェットのレンダリングに必要なデータを読み込むことができます。class MyAppWidget : GlanceAppWidget() { override suspend fun provideGlance(context: Context, id: GlanceId) { // In this method, load data needed to render the AppWidget. // Use `withContext` to switch to another thread for long running // operations. provideContent { // create your AppWidget here Text("Hello World") } } }
GlanceAppWidgetReceiverのglanceAppWidgetでインスタンス化します。class MyAppWidgetReceiver : GlanceAppWidgetReceiver() { // Let MyAppWidgetReceiver know which GlanceAppWidget to use override val glanceAppWidget: GlanceAppWidget = MyAppWidget() }
これで、Glance を使用して AppWidget を構成できました。
サイズバケット全体でウィジェットの画像メモリを管理する
ウィジェットにビットマップまたは content:// 画像 URI を表示する場合は、次の方法で、シリアル化された RemoteViews 画像メモリの合計をシステムの上限(6 * width *
height バイト、Android 17 以降では IllegalArgumentException で適用)内に収めます。
provideContentの前に共有ビットマップをデコードする: ウィジェットでSizeMode.ResponsiveまたはSizeMode.Exactを使用している場合、Glance はDpSizeバケットごとにprovideContentラムダを 1 回実行します。provideContent内でBitmapをデコードすると、バケットごとに個別のBitmapインスタンスが割り当てられ、RemoteViews.mBitmapCacheのメモリ使用量が増加します。provideContentの前にprovideGlance内でダウンサンプリングされたビットマップ(不透明な画像の場合はBitmap.Config.RGB_565)を 1 回デコードして、すべてのバケットが単一のBitmap参照を共有するようにします。一致する
ImageProviderインポートを使用する: Jetpack Glance には、2 つのパッケージにわたって 2 つの異なるImageProviderオーバーロードが用意されています。- メモリ内
ImageProvider(bitmap: Bitmap)またはドローアブル リソースImageProvider(resId: Int)を渡す場合は、import androidx.glance.ImageProviderを使用します。 - URI
ImageProvider(uri: Uri)を渡す場合はimport androidx.glance.appwidget.ImageProviderを使用します。FileProviderURI を介してキャッシュに保存されたファイルを提供する場合は、インストールされているすべてのIntent.CATEGORY_HOMEランチャー パッケージにIntent.FLAG_GRANT_READ_URI_PERMISSIONを付与して、ホストが画像をレンダリングできるようにします。
- メモリ内
GlanceAppWidgetReceiver クラスを使用してウィジェット ブロードキャストを処理する
GlanceAppWidgetReceiver 座標ウィジェットは、基盤となる AppWidgetProvider を拡張することで、ブロードキャストとプラットフォームの状態の更新を行います。ウィジェットが更新、削除、有効化、無効化されたときにプラットフォーム イベントを受信し、Compose ライフサイクル リクエストに変換します。
マニフェストでウィジェットを宣言する
AndroidManifest.xml ファイルで、GlanceAppWidgetReceiver クラスのサブクラスをブロードキャスト レシーバとして宣言します。
<receiver android:name="MyReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/my_app_widget_info" />
</receiver>
<receiver> 要素には、レシーバー クラスを指定する android:name 属性が必要です。レシーバは、<intent-filter> 内で ACTION_APPWIDGET_UPDATE ブロードキャスト アクションを受け入れる必要があります。
<meta-data> 要素は、その名前を android.appwidget.provider として識別する必要があります。また、android:resource 属性は、AppWidgetProviderInfo XML メタデータ リソース(@xml/my_app_widget_info)を指す必要があります。
GlanceAppWidgetReceiver クラスを実装する
Glance では、AppWidgetProvider を直接拡張するのではなく、GlanceAppWidgetReceiver を拡張します。これを実装するには、レシーバーを GlanceAppWidget インスタンスにリンクします。GlanceAppWidgetReceiver で使用できる主なコールバックは、次のように動作します。
- Glance によって自動的にオーバーライドされ、コンポジションの更新が実行されます。
onUpdate()onUpdateを手動でオーバーライドする場合は、super.onUpdateを呼び出して、Glance がコンポジション スレッドを正常に起動できるようにする必要があります。 onAppWidgetOptionsChanged(): ウィジェットが最初に配置またはサイズ変更されたときに呼び出されます。Glance は、内部でオプション バンドル アイテムを読み取るため、ランタイム ディメンションに基づいてレイアウトがシームレスに調整されます。onDeleted(Context, IntArray): ユーザーが特定のウィジェット インスタンスを削除するたびに呼び出されます。onEnabled(Context): ウィジェットの最初のインスタンスが正常に作成されたときにトリガーされます。グローバルな移行の実行に最適です。onDisabled(Context): プロバイダの最後のアクティブなインスタンスが削除されたときに呼び出されます。onReceive(Context, Intent): 特定のコールバック メソッドの前に、すべてのプラットフォーム ブロードキャストをインターセプトします。作成するカスタム レシーバ ロジックがsuper.onReceive(context, intent)を呼び出すようにする必要があります。Glance は作業を非同期で自動的にルーティングするため、goAsyncを自分で呼び出すことはできません。
ウィジェットのブロードキャスト インテントを受信する
内部的には、GlanceAppWidgetReceiver は次の基本的なプラットフォーム ウィジェット ブロードキャスト インテントをフィルタして処理します。
ACTION_APPWIDGET_UPDATEACTION_APPWIDGET_DELETEDACTION_APPWIDGET_ENABLEDACTION_APPWIDGET_DISABLEDACTION_APPWIDGET_OPTIONS_CHANGED
UI を作成する
次のスニペットは、UI を作成する方法を示しています。
/* Import Glance Composables In the event there is a name clash with the Compose classes of the same name, you may rename the imports per https://kotlinlang.org/docs/packages.html#imports using the `as` keyword. import androidx.glance.Button import androidx.glance.layout.Column import androidx.glance.layout.Row import androidx.glance.text.Text */ class MyAppWidget : GlanceAppWidget() { override suspend fun provideGlance(context: Context, id: GlanceId) { // Load data needed to render the AppWidget. // Use `withContext` to switch to another thread for long running // operations. provideContent { // create your AppWidget here MyContent() } } @Composable private fun MyContent() { Column( modifier = GlanceModifier.fillMaxSize(), verticalAlignment = Alignment.Top, horizontalAlignment = Alignment.CenterHorizontally ) { Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp)) Row(horizontalAlignment = Alignment.CenterHorizontally) { Button( text = "Home", onClick = actionStartActivity<MyActivity>() ) Button( text = "Work", onClick = actionStartActivity<MyActivity>() ) } } } }
上記のコードサンプルは、次のことを行います。
- 最上位の
Columnでは、アイテムが縦方向に 1 つずつ配置されます。 Columnは、利用可能なスペースに合わせてサイズを拡大し(GlanceModifierを使用)、コンテンツを上部に配置し(verticalAlignment)、水平方向に中央揃えします(horizontalAlignment)。Columnのコンテンツはラムダを使用して定義されます。ここで重要となるのは順序です。
配置値を変更したり、異なる修飾子値(パディングなど)を適用したりして、コンポーネントの配置とサイズを変更できます。各クラスのコンポーネント、パラメータ、使用可能な修飾子の完全なリストについては、リファレンス ドキュメントをご覧ください。
角の丸みを実装する
Android 12 では、アプリ ウィジェットの角丸を動的にカスタマイズするためのシステム パラメータが導入されています。
system_app_widget_background_radius: ウィジェットの背景コンテナの角丸の半径を指定します(28 dp 以下)。- 内側の半径: コンテンツのクリッピングを防ぐため、システム背景のアウトラインに基づいて、内側のコンテンツの半径を比例的に計算します。
systemRadiusValue - widgetPadding
Glance では、GlanceModifier.cornerRadius(android.R.dimen.system_app_widget_background_radius) を使用して、コンポジションで角丸のサイズ設定プロパティを動的に適用できます。
Android 11(API レベル 30)以前を搭載しているデバイスで下位互換性を確保するには、カスタム属性とカスタムテーマ リソースのフォールバックを実装します。
/values/attrs.xml<resources> <attr name="backgroundRadius" format="dimension" /> </resources>/values/styles.xml<resources> <style name="MyWidgetTheme"> <item name="backgroundRadius">@dimen/my_background_radius_dimen</item> </style> </resources>/values-31/styles.xml<resources> <style name="MyWidgetTheme" parent="@android:style/Theme.DeviceDefault.DayNight"> <item name="backgroundRadius">@android:dimen/system_app_widget_background_radius</item> </style> </resources>/drawable/my_widget_background.xml<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="?attr/backgroundRadius" /> </shape>