ユーザーがアプリ ウィジェットを設定できるようにする

アプリ ウィジェットは構成可能です。たとえば、時計ウィジェットでは、表示するタイムゾーンをユーザーが構成できます。

ユーザーがウィジェットの設定を構成できるようにするには、ウィジェットの設定 Activity を作成します。このアクティビティは、指定した構成オプションに応じて、ウィジェットの作成時またはそれ以降に、アプリ ウィジェット ホストによって自動的に起動します。

構成アクティビティを宣言する

Android マニフェスト ファイルで、構成アクティビティを通常のアクティビティとして宣言します。アプリ ウィジェット ホストは ACTION_APPWIDGET_CONFIGURE アクションで起動するため、アクティビティはこのインテントを受け入れる必要があります。次に例を示します。

<activity android:name=".ExampleAppWidgetConfigurationActivity">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
    </intent-filter>
</activity>

AppWidgetProviderInfo.xml ファイルで android:configure 属性を使用してアクティビティを宣言します。詳しくは、このファイルの宣言をご覧ください。以下に、構成アクティビティを宣言する方法の例を示します。

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:configure="com.example.android.ExampleAppWidgetConfigurationActivity"
    ... >
</appwidget-provider>

ランチャーはパッケージ スコープの外部からアクティビティを参照するため、アクティビティは完全修飾名前空間で宣言されます。

構成アクティビティを開始するために必要なものはこれだけです。次に、実際のアクティビティを実装する必要があります。

構成アクティビティを実装する

アクティビティを実装する際は、次の 2 つの重要な点に留意してください。

  • アプリ ウィジェット ホストは構成アクティビティを呼び出し、構成アクティビティは常に結果を返す必要があります。結果には、アクティビティを起動したインテントから渡されたアプリ ウィジェット ID(EXTRA_APPWIDGET_ID としてインテント エクストラに保存されている)が含まれている必要があります。
  • システムは、構成アクティビティの起動時に ACTION_APPWIDGET_UPDATE ブロードキャストを送信しません。つまり、ウィジェットの作成時に onUpdate() メソッドを呼び出しません。ウィジェットを初めて作成するときに AppWidgetManager から更新をリクエストするのは、構成アクティビティの役割です。ただし、onUpdate() は後続の更新で呼び出されます。初回のみスキップされます。

構成から結果を返してウィジェットを更新する方法の例については、次のセクションのコード スニペットをご覧ください。

構成アクティビティからウィジェットを更新する

ウィジェットが構成アクティビティを使用する場合、構成の完了時にウィジェットを更新するのはアクティビティの役割です。そのためには、AppWidgetManager から直接アップデートをリクエストします。

ウィジェットを適切に更新して構成アクティビティを閉じる手順の概要は次のとおりです。

  1. アクティビティを起動したインテントからアプリ ウィジェット ID を取得します。

    Kotlin

    val appWidgetId = intent?.extras?.getInt(
            AppWidgetManager.EXTRA_APPWIDGET_ID,
            AppWidgetManager.INVALID_APPWIDGET_ID
    ) ?: AppWidgetManager.INVALID_APPWIDGET_ID
    

    Java

    Intent intent = getIntent();
    Bundle extras = intent.getExtras();
    int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
    if (extras != null) {
        appWidgetId = extras.getInt(
                AppWidgetManager.EXTRA_APPWIDGET_ID,
                AppWidgetManager.INVALID_APPWIDGET_ID);
    }
    
  2. アクティビティの結果を RESULT_CANCELED に設定します。

    これにより、ユーザーがアプリの終了前にアクティビティを終了した場合、設定がキャンセルされたことと、ホストがウィジェットを追加しないことをアプリ ウィジェット ホストに通知します。

    Kotlin

    val resultValue = Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
    setResult(Activity.RESULT_CANCELED, resultValue)
    

    Java

    int resultValue = new Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    setResult(Activity.RESULT_CANCELED, resultValue);
    
  3. ユーザーの設定に応じてウィジェットを設定します。

  4. 構成が完了したら、getInstance(Context) を呼び出して AppWidgetManager のインスタンスを取得します。

    Kotlin

    val appWidgetManager = AppWidgetManager.getInstance(context)
    

    Java

    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    
  5. updateAppWidget(int,RemoteViews) を呼び出して、ウィジェットを RemoteViews レイアウトで更新します。

    Kotlin

    val views = RemoteViews(context.packageName, R.layout.example_appwidget)
    appWidgetManager.updateAppWidget(appWidgetId, views)
    

    Java

    RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget);
    appWidgetManager.updateAppWidget(appWidgetId, views);
    
  6. 戻りインテントを作成し、アクティビティの結果を設定して、アクティビティを終了します。

    Kotlin

    val resultValue = Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
    setResult(Activity.RESULT_OK, resultValue)
    finish()
    

    Java

    Intent resultValue = new Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    setResult(RESULT_OK, resultValue);
    finish();
    

例については、GitHub の ListWidgetConfigureActivity.kt サンプルクラスをご覧ください。

ウィジェットの構成オプション

デフォルトでは、アプリ ウィジェット ホストは、ユーザーがホーム画面にウィジェットを追加した直後に、構成アクティビティを 1 回だけ起動します。ただし、ユーザーが既存のウィジェットを再構成できるようにするオプションや、デフォルトのウィジェット構成を指定することでウィジェットの初期構成をスキップできるようにするオプションを指定することもできます。

配置したウィジェットをユーザーが再設定できるようにする

ユーザーが既存のウィジェットを再構成できるようにするには、appwidget-providerwidgetFeatures 属性に reconfigurable フラグを指定します。詳しくは、AppWidgetProviderInfo.xml ファイルを宣言するためのガイドをご覧ください。次に例を示します。

<appwidget-provider
    android:configure="com.myapp.ExampleAppWidgetConfigurationActivity"
    android:widgetFeatures="reconfigurable">
</appwidget-provider>

ウィジェットを再構成するには、ウィジェットを長押しし、[Reconfigure] ボタン(図 1 の 1)をタップします。

右下にボタンが表示される
図 1. ウィジェットの [Reconfigure] ボタン

ウィジェットのデフォルト設定を使用する

ユーザーが最初の構成手順をスキップできるようにすることで、よりシームレスなウィジェット エクスペリエンスを実現できます。これを行うには、widgetFeatures フィールドに configuration_optional フラグと reconfigurable フラグの両方を指定します。これにより、ユーザーがウィジェットを追加した後の設定アクティビティの起動が省略されます前述のとおり、ユーザーは後でウィジェットを再構成できます。たとえば、時計ウィジェットは初期設定をバイパスして、デフォルトでデバイスのタイムゾーンを表示できます。

構成アクティビティを変更可能とオプションの両方としてマークする方法の例を以下に示します。

<appwidget-provider
    android:configure="com.myapp.ExampleAppWidgetConfigurationActivity"
    android:widgetFeatures="reconfigurable|configuration_optional">
</appwidget-provider>

ユーザーがウィジェットを固定できるようにする

Android 8.0(API レベル 26)以降を搭載しているデバイスでは、ユーザーが固定ショートカットを作成できるランチャーにより、ホーム画面にウィジェットを固定することもできます。次の動画に示すように、固定ショートカットと同様に、これらの固定ウィジェットを使用すると、ユーザーはアプリ内の特定のタスクにアクセスでき、アプリから直接ホーム画面に追加できます。

レスポンシブ レイアウトの例
図 2. ウィジェットを固定する例。

アプリで、サポートされているランチャーにウィジェットを固定するリクエストを作成するには、次の手順を行います。

  1. アプリのマニフェスト ファイルでウィジェットを宣言していることを確認します。

  2. 次のコード スニペットに示すように、requestPinAppWidget() メソッドを呼び出します。

Kotlin

val appWidgetManager = AppWidgetManager.getInstance(context)
val myProvider = ComponentName(context, ExampleAppWidgetProvider::class.java)

if (appWidgetManager.isRequestPinAppWidgetSupported()) {
    // Create the PendingIntent object only if your app needs to be notified
    // when the user chooses to pin the widget. Note that if the pinning
    // operation fails, your app isn't notified. This callback receives the ID
    // of the newly pinned widget (EXTRA_APPWIDGET_ID).
    val successCallback = PendingIntent.getBroadcast(
            /* context = */ context,
            /* requestCode = */ 0,
            /* intent = */ Intent(...),
            /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT)

    appWidgetManager.requestPinAppWidget(myProvider, null, successCallback)
}

Java

AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
ComponentName myProvider = new ComponentName(context, ExampleAppWidgetProvider.class);

if (appWidgetManager.isRequestPinAppWidgetSupported()) {
    // Create the PendingIntent object only if your app needs to be notified
    // when the user chooses to pin the widget. Note that if the pinning
    // operation fails, your app isn't notified. This callback receives the ID
    // of the newly pinned widget (EXTRA_APPWIDGET_ID).
    PendingIntent successCallback = PendingIntent.getBroadcast(
            /* context = */ context,
            /* requestCode = */ 0,
            /* intent = */ new Intent(...),
            /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT);

    appWidgetManager.requestPinAppWidget(myProvider, null, successCallback);
}