Flutter でスマホアプリを作成する際、Google Drive にアプリデータを保存して端末間で同期できるようにしました。
その際、google_sign_in プラグインを利用しました。
そこで苦労したことを書こうと思います。
Google Drive 利用のためのスコープ
前提として、Google Drive にアプリ向けのデータ保存を行うには、以下の2つのスコープが必要になります。
final List<String> _scopes = [
drive.DriveApi.driveAppdataScope,
drive.DriveApi.driveFileScope,
];
サインインの際に、これらを利用することの承認画面が表示され、ユーザーが同意することでアプリから Google Drive にデータを保存することができるようになります。
認可で問題発生
今回、google_sign_in は v6.x を利用していましたが、途中から最新の v7.2.0 を使うように変更しました。
v6.x から v7.x へは破壊的変更が入り、v6.x で書いたコードがそのまま使えない感じになります。
Google Drive の利用には、シングルトンである GoogleSignIn インスタンスの初期化が必要です。
GoogleSignIn.instance.initialize()
次にサインインの認証を行います。
この時、スコープを渡すことができます。
final account = await GoogleSignIn.instance.authenticate(
scopeHint: _scopes,
);
ここまでで、サインイン(認証)とGoogle Drive を利用することの同意(認可)が行われます。
そう思っていた時期もありました。。。w
実際は、ここまでを実行した場合、iOS では Google Drive の利用の同意画面が表示されますが、Android では表示ません。
両方NGであれば、コードが悪いと思うのですが、なぜか iOS だけうまく動くので、混乱しました。
Android を利用するための Firebase や Google Cloud Platform の設定を疑い、しかし何度確認しても問題はなさそうで、さらに混乱。。。
対策
結論から言うと、google_sign_in のドキュメント(google_sign_in6.x から 7.x への移行)を読むと、認証と認可は分ける必要がありそうでした。
これらのステップを同時に実行する必要があるアプリケーションでは、scopeHint認証ステップ中に を渡すことができます。これをサポートするプラットフォームでは、これにより認証と認可のUIフローを組み合わせたフローが可能になります。ただし、すべてのプラットフォームでこれらのフローの組み合わせが許可されているわけではないため、必要に応じてアプリケーションで個別の認可プロンプトをトリガーできるように準備しておく必要があります。
iOS と Android で動きが異なったのは、Android がサポートしていないプラットフォームだったと思われます。
以下のような実装で、両方で動作するようになりました。
// 初期化
// Firebase 利用時は、serverId などの指定は不要.
await GoogleSignIn.instance.initialize();
// サインイン(認証)
// ここでスコープを指定すると、次のスコープの確認の際に正しく確認できない.
final account = await GoogleSignIn.instance.authenticate();
// スコープの確認
final auth = await account.authorizationClient.authorizationForScopes(_scopes);
if (auth == null) {
// スコープが存在しない、不足している場合は、スコープを要求する(認可)
final authResult = await account.authorizationClient.authorizeScopes(_scopes);
}
ポイントは、以下です。
- authenticate で scopeHint を指定すると、iOS は認可画面が表示されるが、Android では表示されない。
- authenticate で scopeHint を指定すると、Android では authorizationForScopes の結果が null にならない。
認可の同意プロセスを経ていないのに、認可されたものとなっていると思われる。 - authorizationForScopes の結果が null の場合、 authorizeScopes で認可の同意プロセスを実行する。
わかればその通りの手順で実装すれば良いだけなのですが、ライブラリ利用はロジックではなく、知っているか否かなので難しいですね。
さいごに
公式ドキュメントをよく読み、迷ったらサンプル通りに書いてみろ!と。
今回のアプリは、AIのバイブコーディングでどこまでできるかを試していたため、ほとんどコードを書いてませんでした。
そのため、AIに解決してもらおうとして沼にハマって、公式をよく読まなかったのも良くなかったです。
AIも使い方、使い所が重要で、沼った時の経験や知識は重要であることも再認識できました。