FlutterでAutoFillに対応した際の躓きポイント

先日、担当しているFlutter案件でAutoFillを実装する機会があったのですが、iOSで動作確認ができるようになるまで幾つかの躓きポイントがあったので共有したいと思います。

# AutoFillとは
ログイン画面等に良くあるフォーム入力の際、ユーザー名やパスワードを自動で入力してくれる仕組みのことです。
（アプリで使用したい場合、Android 8.0以上、iOS 11.0以上である必要があります）
\
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3849089/709128b5-f730-795f-9bda-3ba623148573.gif" width=240px>

※上記はAndroidでの動作サンプル
\
AutoFillを実装するとソフトウェアキーボード上にアカウントの候補が表示されるようになり、それを選択することで簡単にアカウント情報を反映することができます。


# Flutterでの実装方法
FlutterでAutoFillを使用するには、ユーザー名やパスワードを入力するTextFieldやTextFormField等の親として[AutoFillGroup](https://api.flutter.dev/flutter/widgets/AutofillGroup-class.html)を設置してグループ化し、入力Widget側の[autoFillHints](https://api.flutter.dev/flutter/material/TextField/autofillHints.html)プロパティを設定する必要があります。
\
参考までに先ほどお見せした動作サンプルのコードを一部載せておきます。
```dart
@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text('AutoFill Sample'),
      centerTitle: true,
    ),
    body: Center(
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 40.0),
        // AutofillGroupを使ってユーザー名とパスワードの入力をグループ化する
        child: AutofillGroup(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              Container(
                margin: const EdgeInsets.symmetric(vertical: 20.0),
                child: TextFormField(
                  controller: mailController,
                  onChanged: mailChanged,
                  decoration: const InputDecoration(
                    hintText: 'ユーザー名',
                    focusedBorder: OutlineInputBorder(
                      borderSide: BorderSide(
                        color: Colors.blue,
                      ),
                    ),
                    enabledBorder: OutlineInputBorder(
                      borderSide: BorderSide(
                        color: Colors.black,
                      ),
                    ),
                  ),
                  keyboardType: TextInputType.emailAddress,
                  // 入力の種類として「メールアドレス」を設定
                  autofillHints: const <String>[AutofillHints.email],
                ),
              ),
              Container(
                margin: const EdgeInsets.symmetric(vertical: 20.0),
                child: TextFormField(
                  controller: passwordController,
                  onChanged: passwordChanged,
                  decoration: const InputDecoration(
                    hintText: 'パスワード',
                    focusedBorder: OutlineInputBorder(
                      borderSide: BorderSide(
                        color: Colors.blue,
                      ),
                    ),
                    enabledBorder: OutlineInputBorder(
                      borderSide: BorderSide(
                        color: Colors.black,
                      ),
                    ),
                  ),
                  keyboardType: TextInputType.visiblePassword,
                  enableSuggestions: false,
                  autocorrect: false,
                  obscureText: true,
                  // 入力の種類として「パスワード」を設定
                  autofillHints: const <String>[AutofillHints.password],
                  onEditingComplete: () => TextInput.finishAutofillContext(),
                ),
              ),
            ],
          ),
        ),
      ),
    ),
  );
}
```

:::note warn
入力に使用するキーボードの種類とautofillHintsプロパティで設定した内容の組み合わせによっては動作しない場合があるので注意してください。
:::

Androidについては上記のようなコードの記述だけでAutoFillが使えるようになるのですが、iOSではWebサーバーへのapple-app-site-associationファイルの設置やInfo.plistへのドメイン設定等の作業が追加で必要です。

これらの作業についてここでは紹介しませんが、以下の記事が参考になると思います。

https://dev.classmethod.jp/articles/ios-11-password-autofill/#toc-3

ここまでの内容でAutoFillが使えるようになる筈なのですが、iOSでは動作するようになるまで幾つかの躓きポイントがありました。その内容について紹介していきたいと思います。


# apple-app-site-associationの修正が反映されない
apple-app-site-association内の記述を間違えてしまった場合、注意が必要です。
\
[Supporting associated domains](https://developer.apple.com/documentation/xcode/supporting-associated-domains)

> Apple’s content delivery network requests the apple-app-site-association file for your domain within 24 hours. Devices check for updates approximately once per week after app installation.

Appleのドキュメントにきちんと書かれていますが、apple-app-site-associationを参照するタイミングはアプリインストール後であれば約1週間に1回となります。

アプリがインストール済みの場合、apple-app-site-association内の記述を書き換えてもすぐに反映されることは殆どないため、アプリを再インストールして検証することをオススメします。


# apple-app-site-associationを正しく設定したが、iOSでAutoFillが動作しない
iOSではAutoFili実装に必要な作業が多いこともあり、動作していない場合には、どこで問題が発生しているのか原因を切り分けていく必要があります。
\
特に問題がわかりづらいapple-app-site-associationについては、Appleがデバッグする方法を共有しているので参考にすると良いでしょう。

https://developer.apple.com/documentation/technotes/tn3155-debugging-universal-links#Host-and-verify-your-AASA

私が担当しているサービスでもiOSのみAutoFillが動作していなかったため、Appleの情報を元に調査を行ってみました。
\
**curlコマンドを使ったapple-app-site-associationの検証**
```
curl -v https://app-site-association.cdn-apple.com/a/v1/example.com
```

**実行結果**
```
* Host app-site-association.cdn-apple.com:443 was resolved.
 :
 :
* Request completely sent off
< HTTP/1.1 404 Not Found
< Apple-Failure-Details: {"status":"403 Forbidden"}
< Apple-Failure-Reason: SWCERR00101 Bad HTTP Response: 403 Forbidden
< Apple-From: https://example.com/.well-known/apple-app-site-association
 :
 :
< 
Not Found
* Connection #0 to host app-site-association.cdn-apple.com left intact
```
\
検証の結果、403エラーが返ってきていることが判明しました。

Appleのドキュメントによると、403や404が返ってくる場合、サイトがアクセスを拒否しているようです。

> If you see a 403 or 404 HTTP error, your site denied access. Generally, this happens when the AASA file path is not publicly accessible from all IP addresses or your site is blocked for some other reason. Confirm your website’s configuration allows direct access to the AASA file in the .well-known directory, in all geographical locations, from any IP address. Specific IP addresses and ranges are not published as they cannot be guaranteed.

上記の結果を元にインフラ側を調査したところ、AWS WAFのBot Controlがアクセスをブロックしていたことがわかりました。

このようにインフラ側の設定によっても動作しないことがあるため、そうなってしまった場合には根気強く原因を潰していく作業が必要になります。


# おわりに
Androidは動作確認までスムーズに進んだのですが、iOSは今回紹介した問題によって確認まで時間がかかってしまいました。
apple-app-site-associationについては躓くポイントが多いため、今回の記事が少しでも助けになれば幸いです。
\
\
株式会社ボトルキューブではFlutterを使ったお仕事を募集中です。
お問い合わせは下記リンク先のフォームからご連絡ください。

https://www.bottlecube.co.jp/contact