📖
FlutterでFacebookログインを実装する
前提
- Facebook DeveloperでアプリIDの作成が済んでる。
- Firebaseプロジェクトの作成が済んでいる。
Facebook/iOS側/Android側の設定
以下のリンクの手順に沿って設定を進めます。
(項目が少し増えてたりしますが、概ね以下のサイトの方法で賄えます。)
iOSの最終設定
info.plist
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>Bundle ID</string>
<key>CFBundleURLSchemes</key>
<array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
</dict>
// 以下追加
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>fb$(FACEBOOK_APP_ID)</string> // 頭にfbを忘れずに
</array>
</dict>
</array>
<key>FacebookAppID</key>
<string>$(FACEBOOK_APP_ID)</string>
<key>FacebookClientToken</key>
<string>$(FACEBOOK_CLIENT_TOKEN)</string>
<key>FacebookDisplayName</key>
<string>$(APP_ID_SUFFIX)アプリの名前</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-share-api</string>
</array>
Androidの最終設定
デフォルトでstrings.xmlがなかったのでファイルを新規作成しました。
android/app/src/main/res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="facebook_app_id">1234567890123456</string>
<string name="fb_login_protocol_scheme">fb1234567890123456</string>
<string name="facebook_client_token">***********************</string>
</resources>
android/app/src/main/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hogehoge">
<uses-permission android:name="android.permission.INTERNET" />
// queriesを追加
<queries>
<provider android:authorities="com.facebook.katana.provider.PlatformProvider" />
</queries>
// queriesを追加ここまで
<application
android:label="${appNamePrefix}アプリの名前"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data
android:name="flutter_deeplinking_enabled"
android:value="true" />
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="hogehoge.page.link" />
</intent-filter>
</activity>
<!-- image croper start -->
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
<!-- image croper end -->
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
// 追加
<!-- facebook login start -->
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="@string/facebook_app_id" />
<meta-data
android:name="com.facebook.sdk.ClientToken"
android:value="@string/facebook_client_token"/>
<!-- facebook login end -->
// 追加ここまで
</application>
</manifest>
Firebaseの設定
- AuthenticationのプロバイダでFacebookを有効にし、アプリIDとアプリシークレットをコピペします。
- OAuth リダイレクト URI(3つ目の黒塗り)はFacebook Developer側で設定します。
こちらも以下のサイトを参考にさせていただきました↓
Flutter側の実装
今回は以下のパッケージを使用します。
Firebaseとの連携は以下を参考にしています。
最終的な実装
facebook_auth.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hogehoge/log.dart';
import 'package:hogehoge/models/sns_login_result.dart';
class FacebookAuth {
FacebookAuth() {
facebookAuth = FacebookAuth.instance;
}
late FacebookAuth facebookAuth;
Future<SNSLoginResult?> login() async {
try {
final loginResult = await facebookAuth.instance.login();
if (loginResult.accessToken == null) {
return null;
}
final userData = await facebookAuth.getUserData();
final facebookAuthCredential =
FacebookAuthProvider.credential(loginResult.accessToken!.token);
return SNSLoginResult(
name: userData['name'] as String,
credential: facebookAuthCredential,
);
} on Exception catch (e) {
Log.d(e);
rethrow;
}
}
}
// DIできるようriver_podを使用
final facebookAuthProvider = Provider<FacebookAuth>((ref) {
return FacebookAuth();
});
firebase_manager.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class FirebaseManager {
FirebaseManager() {
auth = FirebaseAuth.instance;
}
late FirebaseAuth auth;
// Firebase関連のメソッドを書いてたりしますがここでは使わないので割愛
}
final firebaseManagerProvider = Provider<FirebaseManager>((ref) {
return FirebaseManager();
});
login_repository.dart
class LoginRepository {
LoginRepository(
this._facebookAuth,
this._firebaseManager,
);
final FacebookAuth _facebookAuth;
final FirebaseManager _firebaseManager;
// これをViewModelから呼び出す
Future<Result<SNSLogin?>> facebookLogin() async {
try {
final facebookLoginResult = await _facebookAuth.login();
if (facebookLoginResult == null) {
// ログインをキャンセルした時など
return const ApiResult.success(null);
}
// Firebaseにユーザを登録する
await _firebaseManager.auth
.signInWithCredential(facebookLoginResult.credential);
// ViewModelにfacebookアカウントの名前を渡す
return Result.success(
SNSLogin(name: facebookLoginResult.name),
);
} on Exception catch (e) {
return Result.failure(convertError(e));
}
}
}
final loginRepositoryProvider = Provider<LoginRepository>((ref) {
final facebook = ref.read(facebookAuthProvider);
final firebase = ref.read(firebaseManagerProvider);
return LoginRepository(facebook, firebase);
});
あとはViewModel側でLoginRepository.を呼ぶだけです。
おわり。
Discussion