[Flutter]Issueから考えるautofill+autocorrect問題
1行まとめ
FlutterのTextFieldやTextFormFieldにautofillHintsを指定する場合には、autocorrectをfalseに設定しよう。
以下、詳細です。
autofillHintsとautocorrect
TextFieldやTextFormFieldには、autofillHintsプロパティとautocorrectプロパティがあります。これらは適切に組み合わせるべきプロパティです。不適切な組み合わせは、特定の環境で問題を引き起こす可能性があります。
この記事では、FlutterにおけるautofillHintsとautocorrectの適切な指定について考察します。
autofillHints
autofillHintsは入力フォームに自動入力するためのヒントを提供します。デフォルト値はnullです。
ユーザーにメールアドレスを入力してもらう場合、autofillHintsにAutofillHints.emailを指定することで、自動入力の候補が表示されるようになります。意味合いとしてはkeyboardTypeと似ていますが、keyboardTypeはキーボードの種類を指定するのに対して、autofillHintsは自動入力のヒントを指定するという違いがあります。
FormとAutofillGroupを組み合わせるケースが大半でしょう。たとえばAutofillHints.usernameとAutofillHints.passwordによるログイン機能が典型例です。そのほか、クレジットカード情報であったり、住所情報であったりを自動入力できます。
ユーザービリティを高めることができるため、筆者のお気に入りの機能です。[1]
autocorrect
autocorrectは、テキスト入力中に自動修正するかどうかを指定します。デフォルト値はtrueです。
調べてみると、この"correct"が何を意味するかは、Flutterが各プラットフォームのAPIをどの様に呼び出しているかに依存します。筆者が調べた範囲では、iOSでは自動修正とスペルチェックをセットで管理し、Androidでは自動修正のみを管理しているようです。Webはブラウザごとにサポート状況が異なっており、Safariの場合には言語によっては自動修正が行われるようです。
iOSのソフトウェアキーボードのパスワード欄がちらつく問題
iOS 17より、ソフトウェアキーボードのパスワード欄のちらつき問題が発生しています。
筆者の調査によると、この問題は「iOSのソフトウェアキーボードがパスワード欄を表示する際に、autocorrectがtrueの場合に発生」します。このため、autocorrectをfalseに設定することで問題を回避できます。
PRでは、パスワードマネージャーを呼び出す設定が有効な場合、autocorrectionTypeとspellCheckingTypeをNoに設定することで問題を回避しました。
この動作は、UIKitのUITextFieldを利用するケースでも同様のようです。FlutterはiOSのUITextFieldをラップしているため、このような問題が発生していると考えられます。PRに添付した再現するプロジェクトを添付したので、興味がある方は試してみてください。
なお、SwiftUIの場合はパスワードにSecureFieldを利用することでこの問題を回避できましたが、ユーザー名にTextFieldを利用する必要があるため回避できませんでした。詳しい方がいれば、どうするのがいいのかコメントいただけると助かります。
autocorrectは設定するべきなのか?
autocorrectのデフォルト値はtrueです。このため、autocorrectの設定を意識したことがない開発者も多いのではないかな、と思います。[2]
今一度「autocorrectを設定することは、ユーザーにとって便利なのか」を考えてみるのはいかがでしょうか。
筆者の個人的な経験になりますが、ユーザー名にautocorrectが設定されていたために、「正しいメールアドレスを入力したのに単語を修正された」ことがあります。具体的には(zennのアカウント名でもある)kojiを入力すると、kokiに修正されがちです。また、パスワードの入力欄にはautocorrectを設定するべきでないことは明らかです。もしもパスワードがautocorrectされてしまった場合、ユーザーが"正しくない"英単語を用いたパスワードを設定しにくくなってしまいます。
その他のケースを考えてみると、そもそもautofillHintsを設定するようなTextFieldにautocorrectを設定するメリットがあるのか、という疑問が湧いてきます。見渡す限り、メリットよりもデメリットの方が上回るように感じます。
「ここはautocorrectされて欲しい」というTextFieldに対して、限定的にautocorrectを設定する方が、結果的にユーザーにとって良い体験になるのではないでしょうか。筆者はデフォルト値がtrueであることに疑問を感じています。とはいえ、この値が変わることはまずないため、開発者がautocorrectに注意を払うことが重要だと考えます。
Flutterの実装を読む
Flutterの3.29.0をベースに、各プラットフォームごとの実装をコードを見つつ整理します。
前提知識として必要なのは、FlutterのTextFieldが生成されフォーカスを合わせると、TextInputを介してネイティブのテキスト入力用オブジェクトにアクセスが行われるということです。
当然ではあるのですが、FlutterのTextFieldは各プラットフォームのテキスト入力に関するAPIと直接やり取りできません。しかしパスワードマネージャーを呼び出すためには、各プラットフォームのお作法に則ってテキスト入力を制御する必要があります。
そのため、Flutterは各プラットフォームのテキスト入力用Widgetをラップし、いい感じに制御することで機能を実現しています。
iOSの実装
autocorrectがfalseの場合、autocorrectionとspell checkが無効になります。
前述の不具合があるため、設定についてのドキュメントを探したのですが、明確に組み合わせについて述べている箇所を見つけられませんでした。いくつかのクラスのドキュメントを合わせて眺めると、示唆が得られるかな…? といったところです。
Setting this property to true in any view that conforms to UITextInputTraits disables the user’s ability to copy the text in the view and, in some cases, also disables the user’s ability to record and broadcast the text in the view.
isSecureTextEntryをセットすると、パスワード入力用のテキストフィールドになります。内部的に機能が制限され、文字の表示が*に置き換わります。
The default value for this property is UITextSpellCheckingType.default, which enables spell-checking when autocorrection is also enabled.
スペルチェックはautocorrectionとセットの機能です。autocorrectionが無効な場合はスペルチェックも無効になります。
autofillHintsに関しては、AutofillHints.newUsername以外はプラットフォームが定義する定数に変換されます。newUsernameについては、動作しているっぽいので問題ないのかな…って感じです。react-nativeも見てみたのですが、イマイチわからなかったです。
Androidの実装
autocorrectがtrueの場合、InputType.TYPE_TEXT_FLAG_AUTO_CORRECTが設定されます。
iOSと異なり、spell checkの設定はautocorrectと分離しています。筆者も今回調べていて知ったのですが、spellCheckConfigurationを通して設定が行えるようです。
追加されたのはFlutter v3.7.0からでした。機能追加PRとrevert後にrelandされたPRがあります。
autofillHintsに関しては、autofillHintsに指定された値がそのままsetAutofillHintsで渡されます。
ここで渡している値は、Android 8.0(26)以降ではAutofill frameworkを利用するよう、文字列の変換がなされます。それ以前のバージョンでは、Flutterでセットした値がそのまま使われるようです。
定数の一覧は以下のリンクを参照してください。実際に利用される定数はViewに定義された定数なのですが、一覧性が非常に低いため、androidxの一覧を確認するのが良いはずです。
Webの実装
autocorrectがtrueの場合、autocorrect属性がonに設定されます。
MDNを見てみると、Firefox[3]とSafari[4]がサポートしています。2025年3月現在Chromeはサポートしていません。とはいえ、autocorrectが仕様に反映されたPRを見てみると、Chromeにもサポートが入りそうな気配はあります。[5]
<input> elements, except for password, email, and url, which do not support autocorrection.
MDNのドキュメントによると、autocorrectは<input>要素に対して有効ですが、password、email、urlはサポートしていないとのことです。またautofillHintsにAutofillHints.passwordやAutofillHints.newPasswordを指定する場合、<input>要素はpasswordになります。このためパスワード用のTextFieldではautocorrectは無効になります。
一方で、AutofillHints.usernameは<input>要素に対してtextになります。このため、autocorrectは有効にできます。
上記のコメントの通り、機能の実装時にはSafariのみがautocorrectをサポートしていました。しかし他のブラウザが徐々にサポートに向けて動いているため、ある日を境にautocorrectが利用されるかもしれません。
一方で、spellcheckはFlutterがサポートする全てのブラウザがサポートしています。しかし未実装のようです。P2なので、実装まではまだ時間がかかりそうです。
MDNのドキュメントは「sensitive informationを入力する場合には、spellcheckをfalseにすることを検討するべき」と述べています。
Using spellchecking can have consequences for users' security and privacy. The specification does not regulate how spellchecking is done and the content of the element may be sent to a third party for spellchecking results (see enhanced spellchecking and "spell-jacking").
You should consider setting spellcheck to false for elements that can contain sensitive information.
筆者の理解では、この"sensitive information"とはパスワードやクレジットカード情報などのことを指していると考えられます。AndroidやiOSの実装を見る限り、これらの情報を入力するTextFieldに対するベストプラクティスが語られていないため、注意すべき文言のように感じます。
まとめ
autofillHintsとautocorrectは、適切に組み合わせることでユーザーにとって良い体験を提供できます。autocorrectはtrueがデフォルト値ですが、autofillHintsを指定する場合にはfalseに設定することを検討しましょう。
Discussion