Compose での自動入力

パスワード マネージャーなどのアプリを利用すると、別のアプリのコンポーネントにおいて、ユーザーが入力したデータを次回以降もそのまま入力できます。このように別のアプリに対して入力を行うアプリは、「自動入力サービス」と呼ばれます。自動入力フレームワークは、アプリと自動入力サービス間の通信を管理します。

認証情報やフォームの入力は時間がかかる作業であり、ミスが発生する可能性があります。自動入力を使用すると、項目に入力する時間を省き、ユーザー入力ミスを最小限に抑えることができます。

数行のコードだけで、Compose で自動入力を実装できます。この機能には、ユーザーにとって次のようなメリットがあります。

認証情報を入力する

自動入力では、ユーザーは次の方法で認証情報を入力できます。

  • 自動入力のセマンティクスが設定されているフィールドをタップすると、自動入力の候補が表示されます。
  • システムは、ユーザーに自動入力候補を表示し、ユーザーが入力した内容に基づいて候補をフィルタします。

認証情報を保存する

ユーザーは、自動入力を使用して次の方法で認証情報を保存できます。

  • 自動入力が有効になっているフィールドに新しい情報や更新された情報を入力すると、システムによって保存ダイアログがトリガーされ、情報の保存を求めるメッセージがユーザーに表示されます。保存は次の 2 つの方法で行うことができます。
    • 明示的に(ボタンをクリックするなどして情報をコミットする)
    • ユーザーがページから移動したとき(暗黙的)
  • 認証情報プロバイダによっては、フィールドに ContentType.NewPassword が設定されている場合、システムがユーザーに強力なパスワードを提案することがあります。

アプリで自動入力を使用すると、ユーザーが保存したデータを簡単に取得できます。自動入力は、BasicTextField を介したテキスト コンポーネントと、そのコンポーネントをベースに構築されたすべてのマテリアル テキスト フィールドをサポートします。

自動入力を設定

デバイスまたはエミュレータで自動入力 API を使用する前に、[設定] で自動入力を有効にする必要があります。ここで、自動入力の認証情報プロバイダを指定して、認証情報を保存できます。

認証情報プロバイダの指定方法を示す設定ページ。
図 1. 認証情報プロバイダを指定する方法を示す設定ページ。

コンテンツ タイプを使用してテキスト フィールドに自動入力を追加する

TextField が自動入力に対応していることを示すには、フィールドが受け入れ可能な型で ContentType セマンティクスを設定します。これは、この特定のフィールドに関連する可能性のあるユーザーデータの種類を自動入力サービスに示します。ContentType.Username を使用して、ユーザーがユーザー名を入力できる TextField を設定します。

ContentType セマンティクスを設定すると、ユーザーはデバイスの認証情報プロバイダにすでに保存されている自動入力情報にアクセスできます。たとえば、ユーザーがノートパソコンの Chrome ブラウザでアプリにログインし、認証情報プロバイダでパスワードを保存している場合、自動入力によって認証情報が提供されます。

値ベースのテキスト フィールド

TextField(
    value = textFieldValue.value,
    onValueChange = {textFieldValue.value = it},
    modifier = Modifier.semantics { contentType = ContentType.Username }
)

状態ベースのテキスト フィールド

TextField(
    state = rememberTextFieldState(),
    modifier = Modifier.semantics { contentType = ContentType.Username }
)

複数のタイプの自動入力フィールドを追加する

場合によっては、TextField が複数の ContentType を受け取るようにしたいことがあります。たとえば、ログイン フィールドでメールアドレスまたはユーザー名のいずれかを入力できる場合があります。+ 演算子を使用すると、TextField に複数のコンテンツ タイプを追加できます。

自動入力で保存できるすべてのデータタイプについては、ContentType リファレンスをご覧ください。

値ベースのテキスト フィールド

TextField(
    value = textFieldValue.value,
    onValueChange = { textFieldValue.value = it },
    modifier = Modifier.semantics {
        contentType = ContentType.Username + ContentType.EmailAddress
    }
)

状態ベースのテキスト フィールド

TextField(
    state = rememberTextFieldState(),
    modifier = Modifier.semantics {
        contentType = ContentType.Username + ContentType.EmailAddress
    }
)

自動入力でデータを入力する

TextFieldContentType を追加すると、ユーザーが認証情報を入力できるようになります。

ユーザーが自動入力が有効になっているフィールドをクリックすると、関連するデータが保存されている場合は、キーボードの上にあるツールバーに、認証情報を入力するよう求めるチップが表示されます。

テキスト ツールバーに保存された認証情報が表示されているチップ。
図 2. テキスト ツールバーに表示された保存済みの認証情報のチップ。

ナビゲーションによる自動入力でデータを保存する

Compose は、ユーザーがページから移動して入力した認証情報を commit するタイミングを自動的に判断しようとします。フィールドで自動入力が有効になると、ユーザーがページから移動したときに、追加のコードを必要とせずに認証情報が自動的に保存されます。

自動入力でデータを明示的に保存する

自動入力を使用してテキスト フィールド経由で新しい認証情報を明示的に保存するには、自動入力マネージャーによって自動入力コンテキストがコミット(またはキャンセル)される必要があります。ローカルの自動入力マネージャーは、必要に応じて自動入力フレームワークと通信します。ユーザーが入力した認証情報を削除する場合は、AutofillManager.cancel を呼び出して、保留中のデータを保存せずに削除します。

次のスニペットは、ボタンを使用して自動入力でデータを明示的に保存する方法を示しています。

  1. Autofill マネージャーを保持するローカル変数を作成します。これは次のように取得できます。

    val autofillManager = LocalAutofillManager.current

  2. TextField(s) で、Modifier.semantics を使用して選択したコンテンツ タイプを追加します。

    • 値ベースのテキスト フィールドの場合:

      val autofillManager = LocalAutofillManager.current
      
      Column {
          TextField(
              value = textFieldValue.value,
              onValueChange = { textFieldValue.value = it },
              modifier = Modifier.semantics { contentType = ContentType.NewUsername }
          )
      
          Spacer(modifier = Modifier.height(16.dp))
      
          TextField(
              value = textFieldValue.value,
              onValueChange = { textFieldValue.value = it },
              modifier = Modifier.semantics { contentType = ContentType.NewPassword }
          )
      }

    • 状態ベースのテキスト フィールドの場合:

      val autofillManager = LocalAutofillManager.current
      
      Column {
          TextField(
              state = rememberTextFieldState(),
              modifier = Modifier.semantics { contentType = ContentType.NewUsername }
          )
      
          Spacer(modifier = Modifier.height(16.dp))
      
          TextField(
              state = rememberTextFieldState(),
              modifier = Modifier.semantics { contentType = ContentType.NewPassword }
          )
      }

  3. 必要に応じて、ボタンをクリックして自動入力コンテキストをコミットします。

    • 値ベースのテキスト フィールドの場合:

      val autofillManager = LocalAutofillManager.current
      
      Column {
          TextField(
              value = textFieldValue.value,
              onValueChange = { textFieldValue.value = it },
              modifier = Modifier.semantics { contentType = ContentType.NewUsername },
          )
      
          Spacer(modifier = Modifier.height(16.dp))
      
          TextField(
              value = textFieldValue.value,
              onValueChange = { textFieldValue.value = it },
              modifier = Modifier.semantics { contentType = ContentType.NewPassword },
          )
      
          // Submit button
          Button(onClick = { autofillManager?.commit() }) { Text("Reset credentials") }
      }

    • 状態ベースのテキスト フィールドの場合:

      val autofillManager = LocalAutofillManager.current
      
      Column {
          TextField(
              state = rememberTextFieldState(),
              modifier = Modifier.semantics { contentType = ContentType.NewUsername },
          )
      
          Spacer(modifier = Modifier.height(16.dp))
      
          TextField(
              state = rememberTextFieldState(),
              modifier = Modifier.semantics { contentType = ContentType.NewPassword },
          )
      
          // Submit button
          Button(onClick = { autofillManager?.commit() }) { Text("Reset credentials") }
      }

Commit は、ユーザーが画面から移動するたびに呼び出されます。送信ボタンがナビゲーションにリンクされている場合、Commit を呼び出す必要はありません。[送信] をクリックしたときに保存ダイアログをトリガーしたい場合は、ここに Commit を追加します。

ユーザーがボタンをクリックすると、選択した認証情報プロバイダに認証情報を保存するよう求めるボトムシートが表示されます。

パスワードの保存をユーザーに促すボトムシート。
図 3. パスワードの保存をユーザーに促すボトムシート。

安全なパスワードの候補の表示による自動入力でデータを保存する

認証情報プロバイダによっては、NewUsernameNewPassword のコンテンツ タイプを使用しているときに、キーボードに [強力なパスワードを提案] ボタンが表示されることがあります。このボタンをクリックすると、ボトムシートが表示され、認証情報を保存できます。ユーザーがこのエクスペリエンスを利用するために、他に実装する必要はありません。

キーボード ツールバーの安全なパスワードの候補チップ。
図 4. キーボードのツールバーにある安全なパスワードの自動生成チップ。
安全なパスワードの使用を促すボトムシート。
図 5. 安全なパスワードの使用を促すボトムシート。

トラブルシューティング

「保存」のユーザー ジャーニーを呼び出す際に、[今はしない] を複数回クリックすると、認証情報プロバイダがボトムシートを表示しなくなることがあります。再度有効にして表示させるには、[パスワードを保存しますか?] をブロックしている特定のアプリを削除する必要があります。

パスワードの保存をユーザーに促すボトムシート。
図 6.パスワードの保存をユーザーに促すボトムシート。

自動入力をさらにカスタマイズする

自動入力の一般的なユーザー ジャーニーでは、自動入力が有効なコンポーネントに認証情報が入力されると、そのコンポーネントの色が変わり、ハイライト表示されます。これは、自動入力が正常に完了したことをユーザーに知らせるためです。

このハイライトの色をカスタマイズするには、CompositionLocal を使用して、任意の色を指定します。デフォルトの自動入力ハイライト表示の色は Color(0x4dffeb3b) として定義されています。

値に基づくテキスト フィールド

val customHighlightColor = Color.Red

CompositionLocalProvider(LocalAutofillHighlightColor provides customHighlightColor) {
    TextField(
        value = textFieldValue.value,
        onValueChange = { textFieldValue.value = it },
        modifier = Modifier.semantics { contentType = ContentType.Username }
    )
}

状態ベースのテキスト フィールド

val customHighlightColor = Color.Red

CompositionLocalProvider(LocalAutofillHighlightColor provides customHighlightColor) {
    TextField(
        state = rememberTextFieldState(),
        modifier = Modifier.semantics { contentType = ContentType.Username }
    )
}