Flutter: Firebase auth から twitter サインインを行う。AndroidとiPhone
1.ながれ
Flutterアプリ用の部品集め、バックエンドは、Firebaseを使用する。
Google サインインを実現したので、twitterを試す。
firebase_auth プラグイン で全部行けるかと思ったら、Firebaseにかかる部分のみで、twitterからアクセストークンをもらうあたりの処理は範囲外のよう。
flutter_twitter_login プラグインを試したが、内部で非推奨のjava apiを利用しているというログが出ることと、公式プラグインでないことから、対処をググる中で、Stackoverflowのコメントを参考に処理を実装することとする。
動いたところ(Android/iPhone)
2.準備
2.1 twitter
以下のサイトから、アプリの登録を行い、アプリケーションの詳細 – Key and Tokens から、API key と API secret key を発行する。
Twitter Developer
2.2 Firebase Console
Firebaseが、アプリケーションのバックエンドとして、リダイレクト先のURLやらを準備してくれる。
プロジェクトから、Authentication 、Sign in method から twitter を選択
2.1で取得した、API Key と API secret key を登録、有効にする。
3.実装
3.1 呼び出し側
- Tiwtter Sign In ボタン押下で、上記2で取得したAPIキーを、TwitterSiginInPageに引き渡す
- 画面遷移を終え、戻ってくると、credential に、トークンが含まれている
- 取得したトークンをFirebase authに渡して、ユーザー情報を取得し画面表示
lib\firebase_auth.dart
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import './twitter_sign_in.dart';
class FirebaseAuthPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => FIrebaseAuthPageState();
}
enum Menu {
twitter_sign_in,
item2,
}
class FIrebaseAuthPageState extends State<FirebaseAuthPage> {
final FirebaseAuth _auth = FirebaseAuth.instance;
String _userAvatarUrl = '';
String _userDisplayName = '';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Firebase Auth Sample"),
),
body: Column(
children: <Widget>[
PopupMenuButton(
onSelected: popupMenuSelected,
itemBuilder: (BuildContext context) =>
<PopupMenuEntry<Menu>>[
const PopupMenuItem( child: const ListTile( leading:Icon(Icons.account_box),
title:Text("Twitter Sign In")), value: Menu.twitter_sign_in),
const PopupMenuItem( child: const ListTile( leading:Icon(Icons.account_circle),
title:Text("item2")), value: Menu.item2),
],
),
ListTile(leading :
CircleAvatar(
backgroundImage: NetworkImage(_userAvatarUrl),
),
title:Text(_userDisplayName ?? ''),),
],
),
);
}
void popupMenuSelected(Menu selectedMenu){
switch(selectedMenu) {
case Menu.twitter_sign_in:
_pushTwitterPage(context);
break;
default:
break;
}
}
void _pushTwitterPage(BuildContext context) async {
Widget page = TwitterSignInPage(
consumerKey: "***** your api key ****",
consumerSecret: "***** your api secret key ****",
oauthCallbackHandler: "https://**** firebase call back url ****");
final credential = await Navigator.of(context).push(
MaterialPageRoute<AuthCredential>(builder: (_) => page)
);
FirebaseUser user;
if (credential != null) {
user = (await _auth.signInWithCredential(credential)).user;
}
setState(() {
if (user != null) {
_userAvatarUrl = user.photoUrl;
_userDisplayName = user.displayName;
} else {
_userDisplayName = 'Failed to sign in with Twitter. ';
}
});
}
// void _twitterSignOut() async {
// _auth.signOut();
// }
}
3.2 twitter ログイン主処理
5年ほど前5年ほど前にも、Djangoで同じことをやっていた。以下を参考にSTEP1~3を実装
STEP1
STEP2
STEP3
lib/twitter_sign_in.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:oauth1/oauth1.dart';
import 'package:firebase_auth/firebase_auth.dart';
///
/// https://stackoverflow.com/questions/60461547/how-to-sign-in-with-twitter-using-firebase-auth-with-flutter
///
class TwitterSignInPage extends StatefulWidget {
final twitterPlatform = Platform(
'https://api.twitter.com/oauth/request_token', // temporary credentials request
'https://api.twitter.com/oauth/authorize', // resource owner authorization
'https://api.twitter.com/oauth/access_token', // token credentials request
SignatureMethods.hmacSha1, // signature method
);
final ClientCredentials clientCredentials;
final String oauthCallbackHandler;
TwitterSignInPage({
@required final String consumerKey,
@required final String consumerSecret,
@required this.oauthCallbackHandler,
}) : clientCredentials = ClientCredentials(consumerKey, consumerSecret);
@override
State<StatefulWidget> createState() => TwitterSignInPageState();
}
enum Menu {twitter_sign_in, twitter_sign_out}
class TwitterSignInPageState extends State<TwitterSignInPage> {
final flutterWebviewPlugin = FlutterWebviewPlugin();
Authorization _oauth;
@override
void initState() {
super.initState();
// Twitter OAuth の初期化
_oauth = Authorization(widget.clientCredentials, widget.twitterPlatform);
flutterWebviewPlugin.onUrlChanged.listen((url) {
// STEP2のコールバックを、STEP3へ移動するために監視
if (url.startsWith(widget.oauthCallbackHandler)) {
final queryParameters = Uri.parse(url).queryParameters;
final oauthToken = queryParameters['oauth_token'];
final oauthVerifier = queryParameters['oauth_verifier'];
if (null != oauthToken && null != oauthVerifier) {
_twitterLogInFinish(oauthToken, oauthVerifier);
}
}
});
_twitterLogInStart();
}
@override
void dispose() {
flutterWebviewPlugin.dispose();
super.dispose();
}
Future<void> _twitterLogInStart() async {
assert(null != _oauth);
// STEP1:リクエストトークンの入手
// oauth/request_tokenをPOST送信することで、リクエストトークンを入手
// oauth_callbackは、STEP2が成功したときにリダイレクトされるURL
final requestTokenResponse =
await _oauth.requestTemporaryCredentials(widget.oauthCallbackHandler);
// STEP2: 認証ページへのリダイレクト
// oauth/authenticate のGETリクエストに、STEP1で入手したトークンを、oauth_tokenとして渡す
final authorizationPage = _oauth.getResourceOwnerAuthorizationURI(
requestTokenResponse.credentials.token);
flutterWebviewPlugin.reloadUrl(authorizationPage);
}
Future<void> _twitterLogInFinish(
String oauthToken, String oauthVerifier) async {
// STEP3: リクエストトークンをアクセストークンに変換
// リクエストトークンをアクセストークンに書換えるのに、アプリケーションはPOST oauth/access_token へ STEP2で入手した、
// oauth_verifier POSTリクエストを送信する必要がある。
// リクエストトークンは、oauth_token ヘッダーにも渡されるが、これは署名プロセスに追記される
final tokenCredentialsResponse = await _oauth.requestTokenCredentials(
Credentials(oauthToken, ''), oauthVerifier);
final result = TwitterAuthProvider.getCredential(
authToken: tokenCredentialsResponse.credentials.token,
authTokenSecret: tokenCredentialsResponse.credentials.tokenSecret,
);
print("result $result");
Navigator.pop(context, result);
}
@override
Widget build(BuildContext context) {
return WebviewScaffold(
appBar: AppBar(title: Text("Twitter Login")),
url: "https://twitter.com",
);
}
}
以上。
