アプリ ウィジェットは、他のアプリ(ホーム画面など)に埋め込むことができる小型のアプリビューで、定期的な更新を受信できます。これらのビューは、ユーザー インターフェースではウィジェットと呼ばれ、アプリ ウィジェット プロバイダ(またはウィジェット プロバイダ)で公開できます。他のウィジェットを保持するアプリ コンポーネントをアプリ ウィジェット ホスト(またはウィジェット ホスト)と呼びます。図 1 に音楽ウィジェットの例を示します。
このドキュメントでは、ウィジェット プロバイダを使用してウィジェットを公開する方法について説明します。アプリ ウィジェットをホストする独自の AppWidgetHost
を作成する方法については、ウィジェット ホストを作成するをご覧ください。
ウィジェットの設計方法については、アプリ ウィジェットの概要をご覧ください。
ウィジェット コンポーネント
ウィジェットを作成するには、次の基本コンポーネントが必要です。
AppWidgetProviderInfo
オブジェクト- ウィジェットのレイアウト、更新頻度、
AppWidgetProvider
クラスなど、ウィジェットのメタデータを記述します。AppWidgetProviderInfo
は、このドキュメントで説明されているように、XML で定義されています。 AppWidgetProvider
クラス- ウィジェットをプログラムで操作するための基本的なメソッドを定義します。これにより、ウィジェットが更新、有効化、無効化、削除されたときにブロードキャストを受信します。マニフェストで
AppWidgetProvider
を宣言してから、このドキュメントの説明に従って実装します。 - ビューのレイアウト
- ウィジェットの初期レイアウトを定義します。レイアウトは、このドキュメントで説明されているように、XML で定義されます。
図 2 は、アプリ ウィジェットの処理フロー全体におけるこれらのコンポーネントの位置付けを示しています。
ウィジェットにユーザー構成が必要な場合は、アプリ ウィジェット構成アクティビティを実装します。このアクティビティでは、ユーザーがウィジェットの設定(時計ウィジェットのタイムゾーンなど)を変更できます。
- Android 12(API レベル 31)以降では、デフォルト構成を指定して、ユーザーが後でウィジェットを再構成できるようにすることができます。詳しくは、ウィジェットのデフォルト設定を使用すると配置されたウィジェットをユーザーが再構成できるようにするをご覧ください。
- Android 11(API レベル 30)以前では、このアクティビティはユーザーがホーム画面にウィジェットを追加するたびに起動されます。
また、柔軟なウィジェット レイアウト、その他の機能強化、高度なウィジェット、コレクション ウィジェット、ウィジェット ホストの作成などの改善もおすすめします。
AppWidgetProviderInfo XML を宣言する
AppWidgetProviderInfo
オブジェクトは、ウィジェットの基本的な特性を定義します。単一の <appwidget-provider>
要素を使用して XML リソース ファイルで AppWidgetProviderInfo
オブジェクトを定義し、プロジェクトの res/xml/
フォルダに保存します。
これを次の例に示します。
<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/example_loading_appwidget"
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 より大きい場合、または縦のサイズ変更が有効になっていない場合、maxResizeHeight 属性は無視されます。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() コールバック メソッドを呼び出して AppWidgetProvider に更新をリクエストする頻度を定義します。実際の更新がこの値で正確に行われることを保証するものではありません。電池を節約するため、できるだけ低い頻度(たとえば 1 時間に 1 回以下)に設定することをおすすめします。適切な更新期間を選択する際の考慮事項の一覧については、ウィジェット コンテンツの更新を最適化するをご覧ください。 |
initialLayout |
ウィジェット レイアウトを定義するレイアウト リソースを指定します。 |
configure |
ユーザーがウィジェットを追加したときに起動して、ウィジェット プロパティを設定できるようにするアクティビティを定義します。ユーザーがウィジェットを設定できるようにするをご覧ください。Android 12 以降では、アプリは初期構成をスキップできます。詳しくは、ウィジェットのデフォルト設定を使用するをご覧ください。 |
description |
ウィジェットに表示するウィジェット選択ツールの説明を指定します。Android 12 で導入されました。 |
previewLayout (Android 12)および previewImage (Android 11 以前) |
previewImage と previewLayout の両方の属性を指定することをおすすめします。これにより、ユーザーのデバイスが previewLayout をサポートしていない場合に、アプリが previewImage を使用するようにフォールバックできます。詳しくは、スケーラブルなウィジェット プレビューとの下位互換性をご覧ください。 |
autoAdvanceViewId |
ウィジェットのホストによって自動進行されるウィジェット サブビューのビュー ID を指定します。 |
widgetCategory |
ウィジェットをホーム画面(home_screen )、ロック画面(keyguard )、またはその両方に表示できるかどうかを宣言します。Android 5.0 以上では home_screen のみ有効です。 |
widgetFeatures |
ウィジェットでサポートされている機能を宣言します。たとえば、ユーザーがウィジェットを追加したときにウィジェットでそのデフォルト設定が使用されるようにする場合は、configuration_optional フラグと reconfigurable フラグの両方を指定します。これにより、ユーザーがウィジェットを追加した後の設定アクティビティの起動が省略されます。ユーザーは後でウィジェットを再設定できます。 |
AppWidgetProvider クラスを使用してウィジェット ブロードキャストを処理する
AppWidgetProvider
クラスは、ウィジェット ブロードキャストを処理し、ウィジェットのライフサイクル イベントに応答してウィジェットを更新します。以降のセクションでは、マニフェストで AppWidgetProvider
を宣言して実装する方法について説明します。
マニフェストでウィジェットを宣言する
まず、次の例に示すように、アプリの AndroidManifest.xml
ファイルで AppWidgetProvider
クラスを宣言します。
<receiver android:name="ExampleAppWidgetProvider"
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/example_appwidget_info" />
</receiver>
<receiver>
要素は android:name
属性を必要とします。ウィジェットで使用される AppWidgetProvider
を指定する属性です。別のプロセスで AppWidgetProvider
にブロードキャストする必要がある場合を除き、コンポーネントはエクスポートしないでください(通常は該当しません)。
<intent-filter>
要素には、android:name
属性を持つ <action>
要素を含める必要があります。この属性は、AppWidgetProvider
が ACTION_APPWIDGET_UPDATE
ブロードキャストを受け入れることを指定します。明示的に宣言する必要があるブロードキャストはこれだけです。AppWidgetManager
は、必要に応じて他のすべてのウィジェット ブロードキャストを自動的に AppWidgetProvider
に送信します。
<meta-data>
要素では AppWidgetProviderInfo
リソースを指定します。次の属性が必要です。
android:name
: メタデータ名を指定します。android.appwidget.provider
を使用して、データをAppWidgetProviderInfo
記述子として識別します。android:resource
:AppWidgetProviderInfo
リソースの場所を指定します。
AppWidgetProvider クラスを実装する
AppWidgetProvider
クラスは、ウィジェットのブロードキャストを処理するコンビニエンス クラスとして BroadcastReceiver
を拡張します。ウィジェットの更新、削除、有効化、無効化など、ウィジェットに関連するイベント ブロードキャストのみを受け取ります。これらのブロードキャスト イベントが発生すると、次の AppWidgetProvider
メソッドが呼び出されます。
onUpdate()
AppWidgetProviderInfo
のupdatePeriodMillis
属性で定義された間隔でウィジェットを更新するために呼び出されます。詳細については、このページのその他のウィジェット属性を説明する表をご覧ください。- このメソッドは、ユーザーがウィジェットを追加したときにも呼び出され、
View
オブジェクトのイベント ハンドラの定義や、ウィジェットに表示するデータを読み込むジョブの開始など、基本的なセットアップを実行します。ただし、configuration_optional
フラグなしで設定アクティビティを宣言した場合、このメソッドはユーザーがウィジェットを追加したときには呼び出されず、以後の更新時に呼び出されます。構成の完了時に最初の更新を行うのは、構成アクティビティの役割です。詳細については、ユーザーがアプリ ウィジェットを設定できるようにするをご覧ください。 - 最も重要なコールバックは
onUpdate()
です。詳細については、このページのonUpdate()
クラスでイベントを処理するをご覧ください。 onAppWidgetOptionsChanged()
このメソッドは、ウィジェットが最初に配置されたときと、ウィジェットのサイズが変更されたときに呼び出されます。このコールバックを使用して、ウィジェットのサイズ範囲に基づいてコンテンツを表示または非表示にします。サイズ範囲(Android 12 以降では、ウィジェット インスタンスが使用できるサイズのリスト)を取得するには、
getAppWidgetOptions()
を呼び出します。これにより、次の情報を含むBundle
が返されます。OPTION_APPWIDGET_MIN_WIDTH
: ウィジェット インスタンスの幅の下限を dp 単位で指定します。OPTION_APPWIDGET_MIN_HEIGHT
: ウィジェット インスタンスの高さの下限を dp で表したもの。OPTION_APPWIDGET_MAX_WIDTH
: ウィジェット インスタンスの幅の上限を dp 単位で指定します。OPTION_APPWIDGET_MAX_HEIGHT
: ウィジェット インスタンスの高さの上限を dp 単位で指定します。OPTION_APPWIDGET_SIZES
: ウィジェット インスタンスが使用できるサイズ(List<SizeF>
)のリスト(dp 単位)が含まれます。Android 12 で導入されました。
onDeleted(Context, int[])
ウィジェットがウィジェット ホストから削除されるたびに呼び出されます。
onEnabled(Context)
これは、ウィジェットのインスタンスが初めて作成されるときに呼び出されます。たとえば、ユーザーがウィジェットのインスタンスを 2 つ追加した場合は、初回のみ呼び出されます。新しいデータベースを開く必要がある場合や、その他ウィジェットのすべてのインスタンスについて計 1 回だけ必要なセットアップを行う必要がある場合は、このタイミングが適しています。
onDisabled(Context)
これは、ウィジェットの最後のインスタンスがウィジェット ホストから削除されたときに呼び出されます。
onEnabled(Context)
で行った作業がある場合はこのタイミングで消去します(一時データベースを削除するなど)。onReceive(Context, Intent)
これはすべてのブロードキャストで、上記の各コールバック メソッドの前に呼び出されます。デフォルトの
AppWidgetProvider
実装では、すべてのウィジェット ブロードキャストをフィルタリングし、必要に応じて上記のメソッドを呼び出すため、通常はこのメソッドを実装する必要はありません。
AndroidManifest
の <receiver>
要素を使用して、AppWidgetProvider
クラスの実装をブロードキャスト レシーバとして宣言する必要があります。詳しくは、このページのマニフェストでウィジェットを宣言するをご覧ください。
onUpdate() クラスでイベントを処理する
最も重要な AppWidgetProvider
コールバックは onUpdate()
です。各ウィジェットがホストに追加されたときに呼び出されるためです(configuration_optional
フラグのない設定アクティビティを使用する場合を除く)。ウィジェットがユーザー操作イベントを受け入れる場合、このコールバックにイベント ハンドラを登録します。ウィジェットが一時ファイルやデータベースを作成したり、クリーンアップが必要な他の作業を行ったりすることがない場合は、onUpdate()
のみを定義すれば足りる場合があります。
たとえば、タップするとアクティビティを起動するボタンのあるウィジェットを作成する場合は、AppWidgetProvider
の次の実装を使用できます。
Kotlin
class ExampleAppWidgetProvider : AppWidgetProvider() { override fun onUpdate( context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray ) { // Perform this loop procedure for each widget that belongs to this // provider. appWidgetIds.forEach { appWidgetId -> // Create an Intent to launch ExampleActivity. val pendingIntent: PendingIntent = PendingIntent.getActivity( /* context = */ context, /* requestCode = */ 0, /* intent = */ Intent(context, ExampleActivity::class.java), /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) // Get the layout for the widget and attach an onClick listener to // the button. val views: RemoteViews = RemoteViews( context.packageName, R.layout.appwidget_provider_layout ).apply { setOnClickPendingIntent(R.id.button, pendingIntent) } // Tell the AppWidgetManager to perform an update on the current // widget. appWidgetManager.updateAppWidget(appWidgetId, views) } } }
Java
public class ExampleAppWidgetProvider extends AppWidgetProvider { public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // Perform this loop procedure for each widget that belongs to this // provider. for (int i=0; i < appWidgetIds.length; i++) { int appWidgetId = appWidgetIds[i]; // Create an Intent to launch ExampleActivity Intent intent = new Intent(context, ExampleActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity( /* context = */ context, /* requestCode = */ 0, /* intent = */ intent, /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE ); // Get the layout for the widget and attach an onClick listener to // the button. RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget_layout); views.setOnClickPendingIntent(R.id.button, pendingIntent); // Tell the AppWidgetManager to perform an update on the current app // widget. appWidgetManager.updateAppWidget(appWidgetId, views); } } }
この AppWidgetProvider
は onUpdate()
メソッドのみを定義し、それを使用して Activity
を起動し、setOnClickPendingIntent(int,
PendingIntent)
を使用してウィジェットのボタンにアタッチする PendingIntent
を作成します。appWidgetIds
の各エントリで繰り返されるループがあることに注意してください。このプロバイダが作成した各ウィジェットを特定する ID の配列です。ユーザーがウィジェットの複数のインスタンスを作成した場合、それらはすべて同時に更新されます。ただし、ウィジェットのすべてのインスタンスについて 1 つの updatePeriodMillis
スケジュールのみが管理されます。たとえば、更新スケジュールが 2 時間ごとに定義され、ウィジェットの 2 番目のインスタンスが最初のインスタンスの 1 時間後に追加された場合、両方のインスタンスは最初のインスタンスで定義された期間に更新され、2 番目の更新期間は無視されます。どちらも 1 時間ではなく 2 時間ごとに更新されます。
詳細については、ExampleAppWidgetProvider.java
サンプルクラスをご覧ください。
ウィジェットのブロードキャスト インテントを受け取る
AppWidgetProvider
はコンビニエンス クラスです。ウィジェットのブロードキャストを直接受け取るようにするには、独自の BroadcastReceiver
を実装するか、onReceive(Context,Intent)
コールバックをオーバーライドする方法があります。注意が必要なインテントは次のとおりです。
ACTION_APPWIDGET_UPDATE
ACTION_APPWIDGET_DELETED
ACTION_APPWIDGET_ENABLED
ACTION_APPWIDGET_DISABLED
ACTION_APPWIDGET_OPTIONS_CHANGED
ウィジェット レイアウトを作成する
ウィジェットの初期レイアウトを XML で定義し、プロジェクトの res/layout/
ディレクトリに保存する必要があります。詳しくは、設計ガイドラインをご覧ください。
レイアウトに慣れているデベロッパーであれば、ウィジェットのレイアウトの作成は簡単に行えます。ただし、ウィジェットのレイアウトは RemoteViews
をベースとしており、すべての種類のレイアウトやビューがサポートされているわけではないことに注意が必要です。RemoteViews
でサポートされているビューのカスタムビューまたはサブクラスは使用できません。
RemoteViews
は ViewStub
もサポートしています。これは、サイズがゼロの目に見えない View
であり、実行時にレイアウト リソースを遅延インフレートするために使用できます。
ステートフル動作のサポート
Android 12 では、以下の既存のコンポーネントを使用したステートフル動作のサポートが追加されています。
このウィジェットはまだステートレスであるため、アプリが状態を保存し、状態変化イベントを登録できるようにする必要があります。
次のコードサンプルは、これらのコンポーネントを実装する方法を示しています。
Kotlin
// Check the view. remoteView.setCompoundButtonChecked(R.id.my_checkbox, true) // Check a radio group. remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2) // Listen for check changes. The intent has an extra with the key // EXTRA_CHECKED that specifies the current checked state of the view. remoteView.setOnCheckedChangeResponse( R.id.my_checkbox, RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent) )
Java
// Check the view. remoteView.setCompoundButtonChecked(R.id.my_checkbox, true); // Check a radio group. remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2); // Listen for check changes. The intent has an extra with the key // EXTRA_CHECKED that specifies the current checked state of the view. remoteView.setOnCheckedChangeResponse( R.id.my_checkbox, RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent));
2 つのレイアウトを用意します。1 つは res/layout-v31
で Android 12 以降を搭載しているデバイスをターゲットにし、もう 1 つはデフォルトの res/layout
フォルダにあります。
角の丸みを実装する
Android 12 では、次のシステム パラメータが導入され、ウィジェットの角の丸みを設定できるようになりました。
system_app_widget_background_radius
: ウィジェットの背景の角の半径。28 dp 以下にする必要があります。system_app_widget_inner_radius
: ウィジェット内のビューの角の丸み。8 dp のパディングを使用する際に適切に調整されるように、背景の角の丸みよりちょうど 8 dp 小さくなっています。
次の例は、system_app_widget_background_radius
をウィジェットの角に、system_app_widget_inner_radius
をウィジェット内のビューに使用したウィジェットを示しています。
1 ウィジェットの角。
2 ウィジェット内のビューの角。
角の丸みに関する重要な考慮事項
- サードパーティのランチャーとデバイス メーカーは、
system_app_widget_background_radius
パラメータをオーバーライドして 28 dp 未満にすることができます。system_app_widget_inner_radius
パラメータは常にsystem_app_widget_background_radius
の値より 8 dp 小さくなります。 - ウィジェットで
@android:id/background
を使用していない場合、または枠線に基づいてコンテンツをクリップする背景を定義している場合(android:clipToOutline
をtrue
に設定している場合)、ランチャーは背景を自動的に識別し、最大 16 dp の角の丸い長方形を使用してウィジェットをクリップします。ウィジェットが Android 12 に対応していることを確認するをご覧ください。
ウィジェットを以前のバージョンの Android に対応させるには、カスタム属性を定義し、カスタムテーマを使用して Android 12 向けにオーバーライドすることをおすすめします。次に XML ファイルの例を示します。
/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>
/layout/my_widget_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
...
android:background="@drawable/my_widget_background" />