こんにちは。スタディサプリ Androidエンジニアの@moraylと@omtians9425 です。
スタディサプリのAndroidアプリでは、ID/パスワードの記憶に CredentialsApi
を使っている箇所がありました。現在はCredential Manager
が推奨となっており、そちらへ移行するために調べたことをまとめました。
「ID/パスワードの記録」の性質上、実装の確認や検証では「その記録をリセットする」ことが必要になるので、その方法についても解説します。
ライブラリandroidx.credentials:credentials
は1.3.0
を利用しました。
移行の背景
Smart Lock for Password(CredentialsApi
)は2022年にdeprecatedになり、com.google.android.gms:play-services-auth:21.0.0
から削除されています。 これにより、21.0.0以降ではCredentialsApi
を使うことは出来ません。
それに変わる新しいAPIとして、Credential Manager
が登場しています。ライブラリが変更になっているため、推奨APIを使うためには、単純なバージョンアップだけでなく、コードの書き換えが必要です。
移行方法
公式のマイグレーションガイドが用意されています。 developer.android.com
準備
ガイドのSign in with passwords using Credential Managerに実際の移行手順が載っていて、dependenciesやproguardの記載、その他必要な手順が書かれています。
dependenciesは、Android13(API33)以前の端末をサポートする場合、androidx.credentials:credentials-play-services-auth
が必要になります。
minSdk>=33でなければ必要なので、現状ほぼ必要だと言えるでしょう。
パスワードを保存する
マイグレーションガイドをぱっと見るとコード例は読み取りしかないのですが、Sign in with passwords using Credential ManagerにSave a user's passwordのリンクがあります。
簡単な流れとしては、CredentialManager#createCredential
に、IDとパスワードを入れたCreatePasswordRequest
を渡すだけです。
呼び出すとこのようなボトムシートが表示されます。
ただしこのメソッドにより表示されるパスワード保存ボトムシートに Activity Context が使われるため、呼び出しタイミングには注意が必要です。例えばログイン成功時に別の Activity に遷移するようなケースでログイン画面の Context が直ちに破棄される場合、クラッシュするリスクがあるため遷移先の Context を用いるとより安全かもしれません。
保存済みのパスワードを取得する
Sign in with saved passwordsで解説されていますが、suspendな関数CredentialManager#getCredential
を使うと、結果を取得でき、そこの結果からIDとパスワードが取得できます。
この方法で、マイグレーション前のアプリでCredentialsApi
を使って保存したID/パスワードも取得することが出来ます。
保存済みのパスワードがあると、このようなボトムシートが表示されます。
保存されたパスワードを更新する
現状、CrendentialManager には明示的にパスワードを更新する API がなさそうでした。再度パスワード保存することで上書きできるため、ユーザーが手入力した場合は一律パスワードを保存することによって新規保存・更新の両方に対応しています。
保存されたパスワードを削除する
CredentialsApi
では、保存したIDとパスワードを削除することが出来ました。昔のドキュメントにも、下記のように削除について記載があります。
Delete credentials from Smart Lock when either of the following circumstances occur:
- Signing in with the credentials fails because the account no longer exists or the password is incorrect.
- The user completes the app's account deletion flow.
To delete credentials, call CredentialsClient.delete():
CredentialManagerからはこの機能が削除されたようで、見当たりませんでした。ユーザーがGoogleパスワードマネージャーを通じて自分で削除することになりそうです。
CredentialManagerには clearCredentialState
という関数が存在しますが、これはID/パスワードの削除とは関係ありませんでした。
ドキュメントを見ると、GoogleSignInなどの認証を利用した場合に、認証情報をクリアするために利用するもののようです。
Digital Asset Link を利用したアプリとウェブサイト間の自動ログイン
Smart Lock for Passwords では指定したアプリとウェブサイト間で保存したパスワードを共有する仕組みがありましたが、CredentialManager でも動作します。設定方法は Smart Lock for Passwords と同じであり、移行に必要な作業はありません。
移行時の落とし穴
移行を試している際、落とし穴にはまりました。
事象
AndroidOS14以降で、パスワード保存・読み出しボトムシートが重複表示される。
1つ目の保存ボトムシートが出てから、2つ目の保存ボトムシートが出てきます。
原因
AndroidOS14以降では、オートフィルが強化され、Password入力のEditTextがあると、自動的にパスワード保存・読み出しUIが表示される。これはオートフィルの属性をいじっても無効化出来ない。
CredentialManagerで意図的にパスワード保存・読み出しをしていると、どちらも実行され、重複表示されてしまう。
解決方法
EditTextにisCredential=true
を付ける。
または、
Composeに移行する。
この落とし穴について、詳しくは下記資料をご覧ください。
動作確認時に役立つパスワードマネージャーの使い方
開発や検証において、端末に保存したパスワードを管理したいことがあります。
- 保存処理の確認のため、以前保存したパスワードを削除したい
- 一度「保存しない」を選択すると、二度と保存確認が出ないので、出るようにしたい
これらを行うには、端末のパスワードマネージャーを操作します。
パスワードマネージャーの開き方
パスワードマネージャーの開き方がいくつかあるので紹介します。
奥まったところにいるので、最初の「検索して開く」が一番簡単ですが、他の方法合わせて4つ紹介します。
A. 検索して開く
- 端末の設定アプリを開く
- 上部の検索窓に「パスワードマネージャー」と入力する
- パスワードマネージャーを選択する
B. Googleから開く
- 端末の設定アプリを開く
- Googleを選択
- 「すべてのサービス」タブを選択(ここで「推奨設定」タブにパスワードマネージャーが出てくる場合はそれを押せば完了)
- 自動入力 > Google自動入力 > Googleパスワードマネージャーを選択
C. パスワードとアカウントから開く
D. セキュリティとプライバシーから開く
保存したパスワードを消す
Googleパスワードマネージャーから消すことが出来ます。
- Googleパスワードマネージャーを開く
- 「パスワード」タブ(初期タブ)にアプリ名が表示されるので、対象のアプリを選択する
- ロック解除が出たら解除する
- ここで削除や編集が出来る
注意点として、Googleパスワードマネージャーは、端末に登録されているGoogleアカウント毎に設定が保存されています。
登録したはずなのに見つからない、といった場合は、アカウントが異なる可能性があります。
アカウントは右上のアカウントアイコンから変更できます。(Playストアでアカウントを切り替えるときと同じ方法です。)
「保存しない」を押した記録をリセットする
アプリでパスワードを保存するか聞かれた際、拒否した場合は二度と表示されなくなります。
再び検証でパスワード保存を使用したい場合に困りますが、この記録はリセットすることが出来ます。
これもGoogleパスワードマネージャーで行います。
- Googleパスワードマネージャーを開く
- 「設定」タブを開く
- 下にスクロールしていくと「不承認のサイトまたはアプリ」という項目がある
- そこにあるアプリの右側の×ボタンを押す
これでリストからアプリを消すと、また次回から保存するか聞かれるようになります。
パスワードマネージャーをホーム画面に追加する
パスワードマネージャーを頻繁に利用する場合、ホーム画面に追加すると便利です。
- Googleパスワードマネージャーを開く
- 「設定」タブを開く
- 真ん中あたりにある「ホーム画面にショートカットを追加」をタップ
余談:Autofill 機能と組み合わせた自動ログイン体験について
パスワードの提示タイミングとして主に二つ考えられます。
- ログイン画面起動時に自動提示
- ログインフォームタップ時に表示
1 は手間が少ないものの、唐突に出てくるため誤って消してしまう可能性があります。一方 2 は手入力を妨げないよう、一度表示したら次回以降のタップで表示しないようにするといった考慮が必要です。
1 の問題を解消するために、Autofill を組み合わせることが考えられます。これにより、
- ログイン画面起動時は CredentialManager によりパスワードを提示
- 誤って消した場合、ログインフォームをタップすると IME 側でパスワードを提示 (Autofill)
といった体験が実現できます。
ただし現状では、 Jetpack Compose における Autofill サポートは一部不完全であることがわかっており、現時点では EditText 等を用いるのが安心です。
一方で、執筆時点ではまだalphaバージョンであるcompose-ui 1.8には、alpha05から Autofill 周りの変更が入っており、今後の体験向上に期待しています。
おわりに
CredentialsApi
からCredentialManager
に移行するために調べたことについて記載しました。
調べて実装を試す中で、CredentialManagerは直感的で使いやすい印象を受けました。
AutoFillについてはOS・レイアウトによって落とし穴がありましたが、無事解決することが出来ました。
パスワードマネージャーは、設定の奥まった部分にあり、たどり着き方も複数あり最初は迷いました。 設定の検索機能・ショートカット作成機能には助けられました。みなさんもパスワードマネージャーを使う際にはぜひ使ってみてください。
CredentialManagerでは、GoogleSignInやPasskeyなど、別の認証にも対応しているので、試してみたいと思いました。