NCMBのFlutter SDKを使ってGoogle認証を実装する

NCMBでは多様なプラットフォームに対してSDKを提供しています。公式ではiOS（Swift/Objective-C）、Android（Java/Kotlin）、JavaScript（Web/Node.js/Cordova/Monaca）、Unityがあります。さらにコミュニティSDKとしてRubyやPython、PHPなどのサーバーサイド言語、React NativeやFlutter向けのSDKも開発されています。

今回はそんなコミュニティSDKの一つ、Flutter SDKを使ってGoogle認証を実装します。ソーシャル認証であればパスワードやメールアドレスの管理を行わずに済み、手軽に利用できます。

## GCPでのプロジェクト作成とキーの取得

Google Cloudにてプロジェクトを作成します。そしてOAuth用のキーを作成します。Android向けであれば、これで完了になります。iOS向けにはFirebase Authenticationが必要になりますので注意してください（これはNCMBではなく利用しているライブラリで必要としています）。FirebaseでGCPのプロジェクトを作成するとエラーになることが多い（個人的に）気がするので、まずGCPでプロジェクトを作成して、その後Firebaseから紐付けた方が良いように思います。そしてAuthenticationを有効にし、さらにGoogleを認証プロバイダーに追加後、 `GoogleService-Info.plist` を生成します。

![FireShot_Capture_298_-_20220511112335_NCMB_Auth_-_プロジェクトの設定_-_Firebase_コンソール__-_console_firebase_google_com.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/6d499eb0-8d3d-1990-9016-46865e2f4986.jpeg)

Google Cloudでプロジェクトを作成すると、以下の2つのキーが入手できます。これは後々使うので保存しておきます。

- CLIENT_ID
- REVERSED_CLIENT_ID

## NCMBの設定

NCMBのSNS連携にて、先ほど取得したCLIENT_IDを設定します。Google連携も許可して保存してください。

![FireShot_Capture_299_-_20220511112423_ニフクラ_mobile_backend_-_console_mbaas_nifcloud_com.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/4395bfb7-9a4e-ccd8-dcec-2ea3659caa24.jpeg)


## Flutterの実装

ここからはFlutterでアプリを生成後の実装です。

### Xcodeの設定（iOS向け）

#### Podfileの編集

利用するライブラリが9.0以降にのみ対応なので、 `ios/Podfile` を開いて編集します。

```
platform :ios, '9.0'
```

#### info.plistの編集

`ios/Runner/info.plist` を開いて以下を追加します。 `YOUR_REVERSED_CLIENT_ID` は先ほどの文字列に置き換えてください。

```xml
<!-- Google Sign-in Section -->
<key>CFBundleURLTypes</key>
<array>
	<dict>
		<key>CFBundleTypeRole</key>
		<string>Editor</string>
		<key>CFBundleURLSchemes</key>
		<array>
			<!-- TODO Replace this value: -->
			<!-- Copied from GoogleService-Info.plist key REVERSED_CLIENT_ID -->
			<string>YOUR_REVERSED_CLIENT_ID</string>
		</array>
	</dict>
</array>
```

#### GoogleService-Info.plistの登録

Xcodeにて、GoogleService-Info.plistをRunnerフォルダの中に追加します（Xcode上で）。

![スクリーンショット 2022-05-10 10.59.29.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/c3812503-0efe-ced8-39cf-20af7230dc46.jpeg)


### 実装について

#### ライブラリ、SDKのインストール

利用するライブラリ、SDKをインストールします。

```
flutter pub add google_sign_in
flutter pub add ncmb
```

#### ライブラリのインポート

インストールしたライブラリ、SDKをインポートします。

```dart
import 'package:google_sign_in/google_sign_in.dart';
import 'package:ncmb/ncmb.dart';
```

#### NCMBの初期化

ニフクラ mobile backendにて取得したアプリケーションキー、クライアントキーを使って初期化します。

```dart
void main() {
  // NCMBの初期化
  NCMB('YOUR_APPLICATION_KEY', 'YOUR_CLIENT_KEY');
  runApp(const MyApp());
}
```

#### ステートクラスの変数

ステートクラスではログイン状態を管理するための NCMBUser オブジェクトを定義します。初期値は null です。

```dart
class _MyHomePageState extends State<MyHomePage> {
  NCMBUser? _user;
```

#### ステートクラスの初期化

ステートクラスの初期化 `initState` では認証状態をチェックします。ログインしている場合には `await NCMBUser.currentUser()` でNCMBUserオブジェクトが取得できます。認証していない場合には null が返ってきます。

```dart
@override
void initState() {
	super.initState();
	Future(() async {
		// 現在ログインしているユーザー情報（未ログインの場合はnull）を取得
		final user = await NCMBUser.currentUser();
		setState(() {
			_user = user;
		});
	});
}
```

#### 画面構築

`build` は次のように記述しています。 `_user` の状態によって表示を変えています。そして認証していない場合には `login` 、認証している場合には `logout` を処理するボタンを配置しています。

```dart
@override
Widget build(BuildContext context) {
	return MaterialApp(
		home: Scaffold(
			appBar: AppBar(
				title: const Text('Google Login App'),
			),
			body: Center(
					child: _user == null
							// 未ログインの場合
							? TextButton(
									child: const Text('Login With Google'),
									onPressed: login,
								)
							// ログインしている場合
							: TextButton(
									child: Text(
											'Logged in by ${_user!.getString('displayName', defaultValue: 'No name')}'),
									onPressed: logout,
								)),
		),
	);
}
```

![Simulator Screen Shot - iPod touch (7th generation) - 2022-05-10 at 11.07.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/5fa431e0-bcae-782c-85bc-d3b49b6a3be8.png)


#### login処理

ログイン処理です。ちょっと長いですが、Google認証は `googleSignIn.signIn()` だけで完了します。その後、 `account` が入っていれば、ログイン成功です。ログイン成功していない場合（ユーザーキャンセルやエラー）は何もせず終了します。

ログイン成功した場合には、アクセストークンを取得します。さらにIDと組み合わせて、リクエストデータを作成します。後は `NCMBUser.loginWith` でGoogle認証が完了します。

Google認証ではuserNameなどは自動生成された文字列でユーザーが作成されます。そこで displayName フィールドにGoogleの表示名を適用してデータ更新しています。

```dart
// ログイン処理
login() async {
	final googleSignIn = GoogleSignIn(
		scopes: <String>[
			'email',
		],
	);
	// ログインを実行して結果を受け取る
	final account = await googleSignIn.signIn();
	if (account == null) return;
	final accessToken = (await account.authentication).accessToken;
	// 認証用データの作成
	final data = {'id': account.id, 'access_token': accessToken};
	// ログイン実行
	var user = await NCMBUser.loginWith('google', data);
	// 表示名を追加
	if (user.getString('displayName', defaultValue: '') == '') {
		user.set('displayName', account.displayName!);
		// 更新実行
		await user.save();
	}
	// 表示に反映
	setState(() {
		_user = user;
	});
}
```

![Simulator Screen Shot - iPod touch (7th generation) - 2022-05-10 at 11.08.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/1a5ddbb0-1376-7808-ac12-6f02d3b8a013.png)

#### ログアウト処理

`logout` メソッドは以下のようになります。 `NCMBUser.logout()` で認証データを削除し、 `_user` を null にすることで画面表示を更新しています。

```dart
// ログアウト処理
logout() async {
	await NCMBUser.logout();
	setState(() {
		_user = null;
	});
}
```

## まとめ

Googleアカウントを持っている人は世界中に多いので、ソーシャルログインとして利用されることが多いです。利用したことがある方も多いでしょう。

NCMBを使うことでユーザーごとにデータアクセス権限を制御したり、ソーシャルログイン機能が手軽に実装できます。ぜひお試しください。

[mBaaSでサーバー開発不要！ | ニフクラ mobile backend](https://mbaas.nifcloud.com/)