flutter使用firebase实现google、facebook、apple登录

1,697 阅读2分钟

本文不做名词解释,不说明如何配置开发者相关后台,在配置都没有问题的情况下,直接梭哈食用。使用的第三方库也都是主流高分的,不需要担心维护问题!如果刚拿到需求,直接看本文,可能有点懵逼,建议先收藏,去看一下相关的文章,再来结合代码,实现需求!

开发环境:

flutter sdk: 3.0.1 + dart sdk : 2.17.1

yaml文件配置:

  # firebase服务
  firebase_auth: ^3.6.0
  google_sign_in: ^5.2.4
  google_sign_in_web: ^0.10.0+5
  # facebook login
  flutter_login_facebook: ^1.6.0
  # apple login
  sign_in_with_apple: ^4.1.0

fireBaseUtils

///@author zhc 2022/3/14 1:28 下午
///@description: fireBase管理工具

import 'dart:convert';

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';

// import 'package:flutter_facebook_login/flutter_facebook_login.dart';
import 'package:flutter_login_facebook/flutter_login_facebook.dart';
import 'package:nft_wallet/scr/util/toast_utils.dart';
import 'package:sign_in_with_apple/sign_in_with_apple.dart';

typedef void onData<T>(T value);

class FireBaseUtils {
  static final FirebaseAuth _auth = FirebaseAuth.instance;
  static final GoogleSignIn _googleSignIn = GoogleSignIn(
    scopes: <String>[
      'email',
      //********这里注意 没有获取账号联系人的需求 不要打开这个初始化范围 ******************
      //********如果需要其他或者联系人 还要在google play console 同意屏幕上开通这个api范围 然后提交申请批申请 ******************
      // 'https://www.googleapis.com/auth/contacts.readonly',
    ],
  );
  static final FacebookLogin facebookSignIn = FacebookLogin(debug: false);

  /// facebook登录
  static Future<String?> signInFacebook() async {

    try {
      final FacebookLoginResult result = await facebookSignIn
          .logIn(permissions: [FacebookPermission.email]).catchError((err) {
        debugPrint("face book ${err.toString()}");
      });
      switch (result.status) {
        case FacebookLoginStatus.success:

        ///这里没问题
          final FacebookAccessToken? accessToken = result.accessToken;
          if (accessToken != null) {
            final AuthCredential credential =
            FacebookAuthProvider.credential(accessToken.token);
            //这里的user可能为空
            final User? user =
                (await _auth.signInWithCredential(credential)).user;
            if (user != null) {
              IdTokenResult idTokenResult = await user.getIdTokenResult(true);
              final String? idToken = idTokenResult.token;
              return idToken;
            }
          }
          return null;
        case FacebookLoginStatus.cancel:
          debugPrint('Login cancelled by the user.');
          break;
        case FacebookLoginStatus.error:
          debugPrint('Something went wrong with the login process.\n'
              'Here's the error Facebook gave us: ${result.error.toString()}');
          break;
      }
    } on FirebaseAuthException catch (e) {
      if (e.code == 'account-exists-with-different-credential') {
        // ...https://github.com/firebase/flutterfire/issues/4612
        // 您已经使用google账号注册过应用了,请使用google账号登录
        debugPrint("code : true");
        //amtalktest01@gmail.com
        debugPrint("email : ${e.email}");
        // final List<String> list =  await FirebaseAuth.instance.fetchSignInMethodsForEmail(e.email!);
        // final UserCredential uc = await FirebaseAuth.instance.signInWithCredential(e.credential!);
        // uc.user?.linkWithCredential(e.credential!);
       ToastUtils.show(
            "You have already registered the app with your google account, please log in with your google account");
      }
    }
    return null;
  }

  /// google登录
  static Future<String?> signInWithGoogle() async {
    final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
    if (googleUser != null) {
      final GoogleSignInAuthentication googleAuth =
          await googleUser.authentication;
      final AuthCredential credential = GoogleAuthProvider.credential(
        accessToken: googleAuth.accessToken,
        idToken: googleAuth.idToken,
      );
      final User? user = (await _auth.signInWithCredential(credential)).user;
      assert(user?.email != null);
      assert(user?.displayName != null);
      assert(!user!.isAnonymous);
      assert(await user?.getIdToken() != null);
      IdTokenResult? idTokenResult = await user?.getIdTokenResult(true);
      return idTokenResult?.token;
    }
    return null;
  }

  /// Apple login
  /// 参考 : https://stackoverflow.com/questions/62805312/android-sign-in-with-apple-and-firebase-flutter
  /// 参考 :https://github.com/aboutyou/dart_packages/issues/91
  static Future<String?> signInWithApple() async {
    var redirectURL = "https://SERVER_AS_PER_THE_DOCS.glitch.me/callbacks/sign_in_with_apple";
    var clientID = "AS_PER_THE_DOCS";
    final appleIdCredential = await SignInWithApple.getAppleIDCredential(
        scopes: [
          AppleIDAuthorizationScopes.email,
          AppleIDAuthorizationScopes.fullName,
        ],
        webAuthenticationOptions: WebAuthenticationOptions(
            clientId: clientID,
            redirectUri: Uri.parse(
                redirectURL))
    );
    final oAuthProvider = OAuthProvider('apple.com');
    final credential = oAuthProvider.credential(
      idToken: appleIdCredential.identityToken,
      accessToken: appleIdCredential.authorizationCode,
    );
    final User? user = (await _auth.signInWithCredential(credential)).user;
    assert(user?.email != null);
    assert(user?.displayName != null);
    assert(!user!.isAnonymous);
    assert(await user?.getIdToken() != null);
    IdTokenResult? idTokenResult = await user?.getIdTokenResult(true);
    return idTokenResult?.token;
  }

  ///获取当前用户
  static User? currentUser() {
    return FirebaseAuth.instance.currentUser;
  }

  ///用户改变监听
  void listener(onData listener) {
    FirebaseAuth.instance.userChanges().listen((event) {
      listener(event);
      // if (event != null && mounted) {
      //   setState(() {
      //     user = event;
      //   });
      // }
    });
  }

  /// sign out.
  static Future<void> signOut() async {
    await FirebaseAuth.instance.signOut();
    await _googleSignIn.signOut();
    await facebookSignIn.logOut();
  }
}

使用:

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:nft_wallet/application.dart';
import 'package:nft_wallet/generated/l10n.dart';
import 'package:nft_wallet/main.dart';
import 'package:nft_wallet/scr/login/api/login_api.dart';
import 'package:nft_wallet/scr/login/models/user_info.dart';
import 'package:nft_wallet/scr/login/utils/firebase_utils.dart';
import 'package:nft_wallet/scr/util/provider_util.dart';
import 'package:nft_wallet/scr/util/sp_utils.dart';
import 'package:nft_wallet/scr/util/toast_utils.dart';

import '../binding_email.dart';

///@author zhc 2022/3/10 3:37 下午
///@description: 其他登陆方式模块封装

class OtherLogin extends StatefulWidget {
  //用户是否勾选协议
  final bool isSelectedUserProtocol;

  const OtherLogin({Key? key, required this.isSelectedUserProtocol})
      : super(key: key);

  @override
  State<OtherLogin> createState() => _OtherLoginState();
}

class _OtherLoginState extends State<OtherLogin> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        const SizedBox(
          height: 20,
        ),
        _buildOneKeyText(context),
        const SizedBox(
          height: 20,
        ),
        _buildQuickLogin(context),
        const SizedBox(
          height: 20,
        ),
      ],
    );
  }

  Widget _buildOneKeyText(BuildContext context) {
    return SizedBox(
      width: MediaQuery.of(context).size.width,
      child: Center(
        child: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            Container(
              height: 1,
              width: 24,
              color: Colors.grey,
            ),
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 12),
              child: Text(
                S.of(context).login_Other_login_methods,
                style: const TextStyle(
                    color: Color(0xFF888888),
                    fontSize: 13,
                    fontWeight: FontWeight.bold),
              ),
            ),
            Container(
              height: 1,
              width: 24,
              color: Colors.grey,
            ),
          ],
        ),
      ),
    );
  }

  _buildQuickLogin(BuildContext context) {
    return SizedBox(
      width: MediaQuery.of(context).size.width,
      child: Center(
        child: Row(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            GestureDetector(
              onTap: () async {
                if (!widget.isSelectedUserProtocol) {
                  ToastUtils.show(S.of(context).selected_user_protocol);
                  return;
                }

                /// google login
                String? idToken;
                try {
                  EasyLoading.show(
                    status: S.of(context).loading,
                    maskType: EasyLoadingMaskType.black,
                    dismissOnTap: false,
                  );
                  var user = FireBaseUtils.currentUser();
                  if (user != null) {
                    await FireBaseUtils.signOut();
                  }

                  /// google email login
                  idToken = await FireBaseUtils.signInWithGoogle();
                } catch (e) {
                  //异常
                  debugPrint("signInWithGoogle Auth error !${e.toString()}");
                } finally {
                  EasyLoading.dismiss();
                }

                if (idToken != null) {
                  //获取成功 登录app
                  handlerToken(idToken);
                }
              },
              child: Image.asset(
                "assets/login/gmail.png",
                width: 42,
                fit: BoxFit.cover,
              ),
            ),
            const SizedBox(
              width: 24,
            ),
            GestureDetector(
              onTap: () async {
                if (!widget.isSelectedUserProtocol) {
                  ToastUtils.show(S.of(context).selected_user_protocol);
                  return;
                }
                String? idToken;
                try {
                  EasyLoading.show(
                    status: S.of(context).loading,
                    maskType: EasyLoadingMaskType.black,
                    dismissOnTap: false,
                  );
                  var user = FireBaseUtils.currentUser();
                  if (user != null) {
                    await FireBaseUtils.signOut();
                  }

                  /// face book login
                  idToken = await FireBaseUtils.signInFacebook();
                } catch (e) {
                  //异常
                  debugPrint("signInWithGoogle Auth error !${e.toString()}");
                } finally {
                  EasyLoading.dismiss();
                }

                if (idToken != null) {
                  //获取成功 登录app
                  handlerToken(idToken);
                }
              },
              child: Image.asset(
                "assets/login/facebook.png",
                width: 42,
                fit: BoxFit.cover,
              ),
            ),

            // apple login
            if (Platform.isIOS)
              GestureDetector(
                onTap: () async {
                  if (!widget.isSelectedUserProtocol) {
                    ToastUtils.show(S.of(context).selected_user_protocol);
                    return;
                  }
                  String? idToken;
                  try {
                    EasyLoading.show(
                      status: S.of(context).loading,
                      maskType: EasyLoadingMaskType.black,
                      dismissOnTap: false,
                    );
                    var user = FireBaseUtils.currentUser();
                    if (user != null) {
                      await FireBaseUtils.signOut();
                    }

                    /// apple login
                    idToken = await FireBaseUtils.signInWithApple();
                  } catch (e) {
                    //异常
                    debugPrint("signInWithApple Auth error !${e.toString()}");
                  } finally {
                    EasyLoading.dismiss();
                  }

                  if (idToken != null) {
                    //获取成功 登录app
                    handlerToken(idToken);
                  }
                },
                child: Padding(
                  padding: const EdgeInsets.only(left: 24),
                  child: Image.asset(
                    "assets/login/apple.png",
                    width: 42,
                    fit: BoxFit.cover,
                  ),
                ),
              )
          ],
        ),
      ),
    );
  }

  // 对token统一处理
  handlerToken(String idToken) async {
    try {
      EasyLoading.show(
        status: S.of(context).loading,
        maskType: EasyLoadingMaskType.black,
        dismissOnTap: false,
      );
      debugPrint("idToken $idToken");
      final data = await LoginApi.sendIdToken(idToken);
      debugPrint("data:$data");
      if (data != null && data['code'] == -1405) {
        ///跳转到绑定邮箱页面
        Navigator.of(context).push(MaterialPageRoute(
            builder: (_) => BindEmailPage(
                  idToken: idToken,
                )));
        return;
      }

      if (data != null && data['code'] == 200) {
        ProviderUtil.publicProvider().setLogin(true);
        UserInfo info = UserInfo.fromJson(data["data"]);
        Application.userInfo = info;
        await SPUtils.saveUserInfo(info);
        //进入首页
        Navigator.of(context).push(MaterialPageRoute(
          builder: (_) => App(),
        ));
      } else {
        ToastUtils.show("unknown error, try again");
      }
    } finally {
      if (EasyLoading.isShow) {
        EasyLoading.dismiss();
      }
    }
  }
}