Flutter: MacデスクトップアプリからのGoogle SignInが突如エラーになる

※当サイトは、アフィリエイト広告を利用しています

結論:「google_sign_in_dartio」パッケージを利用する、もしくはセキュリティソフトを無効化する

2022/7/17 Flutter エラー・バグ日記

 

以前、こちらの日記にも記載したが、Flutter2.10にアップグレードしたタイミングから、「エラー400: invalid_request」が出て、突然、MacからのGoogleサインインができなくなった(サインインの目的はGoogle Driveへのアクセス)。

 

しばらく対応を塩漬けしていたが、、、今回調査していくつかの解決方法が分かったのでメモ(後述のとおり、Flutterのアップグレード自体は関係なかった。。)。

 

本記事はライトな日記思考で書いているので、詳細説明はしておらず、基本、テキストのみで画像とかは載せておりません。。m(_ _)m

解説記事ではないため、解決していない内容や、その時々の間違った解釈を述べてしまっている可能性が大いにありますので、何卒、ご了承ください。

 

Flutterで一般的に使用されるGoogleサインイン用のパッケージ「google_sign_in」は、iOS、Android、Webのみの対応のため、デスクトップアプリにGoogleサインインを実装するためは、他の方法を模索する必要がある。

 

当初、対応方法を調べて「googleapis_auth」パッケージを用いれば、ブラウザを経由してGoogleサインインできると分かったので、下記方法(要点のみ掲載)で実装していた。

 

// クラス名、メソッド名、プロパティ名(変数名)について、
// パッケージ等で規定済の名称と区別するため、筆者が作成したもの(名前変更可のもの)
// の名前の末尾には、大文字のオー「O」を付記

import "package:googleapis_auth/auth_io.dart";
import 'package:url_launcher/url_launcher.dart';
import 'package:googleapis/drive/v3.dart'

// ・・・(略)・・・

// ここではGoogle Driveを使用する例として、scopeを設定
scopeO = [DriveApi.driveAppdataScope,];

// Googleサインイン・ユーザー同意の画面をブラウザで表示するためのメソッドを設定
void promptO(String urlO) async {
        if (await canLaunch(urlO)) {
          await launch(urlO);
        } else {
          throw 'Could not launch $urlO';
        }
      }

// "・・・・"には、Google Cloudで取得したClientIDを入れる
var clientIdO = ClientId("・・・・", "");

// ここでブラウザを起動させてサインイン画面を表示
httpClientO = await clientViaUserConsent(clientIdO, scopeO, promptO);

// Google Drive APIのインスタンスを作成
// 以降、このインスタンスを用いてGoogle Driveへのアクセス処理を記述する
googleDriveApiO = DriveApi(httpClientO);

// ・・・(略)・・・

 

(以下、参考情報)

↓Dart向けのGoogle API公式説明

 

↓Google カレンダーへのアクセス実装例

 

しかし、この方法が使えなくなってしまい、調べても解決策を見いだせなかったので、仕方なく他の方法を探すことにした。

 

他のMacデスクトップからのGoogleサインイン方法

結論としては、以下2つのパッケージを使う方法が見つかった。

 

① 「desktop_webview_auth」 を使う方法

 

 

以下のイシューで、本パッケージの具体的な実装例が紹介されている。

 

 

② 「google_sign_in_dartio」 を使う方法

 

 

こちらは、「pub.dev」内で関連しそうなパッケージが無いか探したところ、見つかった。

 

①「desktop_webview_auth」については、パッケージのExampleや、上記イシューの実装例を元に試したところ、確かにGoogleサインインの画面を起動でき、ユーザー同意を取得の上、サインインさせることができた。

 

しかし、恥ずかしながら、自分の理解が及ばず、「サインアウト」させる方法が分からなかった。。

 

※ソースコード内をひたすら探したが、サインアウトさせるメソッドが見つからなかった(無い訳はないと思うのだが、、、)。

 

そこで、②「google_sign_in_dartio」の方も試してみた。

 

ネット上に実装例が見当たらないので、パッケージのExampleを元に実装したところ、こちらもGoogleサインインの画面を起動でき、ユーザー同意を取得の上、サインインさせることができた。

 

しかも、実装方法が非常に簡単で、通常のiOS、Android用に「google_signin」パッケージを実装するコードの前に、以下のコードを入れるだけだった。

 

await GoogleSignInDart.register(clientId: "・・・・");

 

※"・・・・"の部分には、パッケージの説明ページのとおり、Google Cloudで、デスクトップ用に取得したClient ID(「アプリケーションの種類」で「デスクトップアプリ」を選択して作成)を記載する。

 

若干の注意点としては、「scopes:」の設定時に、「'email'」と「'profile'」も入れておく必要がある点。

 

当初、これらを入れずにscopesを設定したところ、サインイン画面は起動するものの、「Null check operator used on a null value」のエラーが出て、サインインできなかった。

 

具体的な実装例(一部のみ)は以下のとおり。

 

import 'package:google_sign_in_dartio/google_sign_in_dartio.dart';
import 'package:google_sign_in/google_sign_in.dart'
import 'package:googleapis/drive/v3.dart'
import 'package:extension_google_sign_in_as_googleapis_auth/extension_google_sign_in_as_googleapis_auth.dart';

// ・・・(略)・・・

// ↓この1文を追加するのみ
await GoogleSignInDart.register(clientId: "・・・・");

// 以降はiOS、Android用に記述するコードと同じ

googleSignInO = GoogleSignIn(
        scopes: [
          // この2つがないと、nullエラーになるため必要
          'email',
          'profile',

          DriveApi.driveAppdataScope,
        ]);

await googleSignInO.signIn();

httpClientO = (await googleSignInO.authenticatedClient())!;
googleDriveApiO = driveO.DriveApi(httpClientO);

// ・・・(略)・・・

 

「googleapis_auth」を使うときに必要だったurl_launcher」パッケージを用いてブラウザを起動するコードなどが不要なので楽

 

ただ、1つ難点があるのは、この方法だとアクセストークンがリフレッシュされないため、1時間経つとトークンが失効し、再度サインインが必要になってしまう点。

 

この問題を解消するには、下記説明ページを参考に、エンドポイント(endpoint)のURIを用意して、「register」メソッドの「exchangeEndpoint:」プロパティに設定する必要があるようだが、方法が難解で理解が及ばず。。。

 

 

自分のアプリでは、Google Driveとの間でのデータのバックアップ・リストアが目的だったので、サインインの維持は必要ないと判断し、エンドポイントの設定は割愛することとした。

 

「googleapis_auth」を用いたサインインも復活(セキュリティソフトの問題)

なぜ従前の「googleapis_auth」を用いる方法が使えなくなったのか、再度調べてみた。

 

すると、こちらのDart公式説明ページにおいて、「http://localhost:8080」を使用する、と書かれている事に気づく。

 

そこで、ローカルホスト関連のエラーについて調べたところ、以下の情報が見つかった。

 

 

 

いずれも「ESET(セキュリティソフト)のファイアウォールを無効化したらつながった」とのこと。

 

そこで、自分のMacに入れているのセキュリティソフトを無効化したところ、なんとアクセスできるようになった。。

 

ちょうどエラーが出るようになったタイミングで、当該セキュリティソフトの再インストール・アップデートをしており、それが影響したのかもしれない。。

 

まさかセキュリティソフトが原因とは。。

 

ただ、「google_sign_in_dartio」を用いる方法は、「googleapis_auth」を使う方法に比べ、実装の手間が少ないので、引き続き前者を採用しようと思う。

 

 

\一般的なエラー対処法をまとめた記事はこちら/

 

リリースしたアプリ(全てFlutterで開発)

 

個人アプリ開発で役立ったもの

おすすめの学習教材

超初心者向けでオススメな元Udemyの講座/

 

 \キャンペーン時を狙えば安価で網羅的な内容が学べる(日本語訳あり)/

 

\Gitの基礎について無料で学べる/

 

おすすめの学習書籍

実用的image_pickerに関してかなり助けられた/

 

Dartの基礎文法を素早くインプットできる/


Dart入門 - Dartの要点をつかむためのクイックツアー

タイトルとURLをコピーしました