Flutter实战一Flutter聊天应用(六)

我们将使用Google登录来验证应用程序的用户。Google登录功能可让用户使用其Google帐户(与Gmail、Play、照片和其他Google服务所使用的帐户相同的帐户)进行安全登录。我们还可以根据与用户的Google帐户相关联的个人资料和身份信息,个性化用户体验。用户登录后,我们可以使用个人资料照片个性化聊天消息头像。

要添加对Google登录的支持,我们将使用google_sign_in插件,在main.dart文件中导入相应的包。

import 'package:google_sign_in/google_sign_in.dart';

要启用Google登录,需要在浏览器中打开Firebase控制台并选择我们的项目。导航到Authentication > 登陆方法。启用Google提供商,具体如下:

Flutter实战一Flutter聊天应用(六)_第1张图片

要在iOS上配置Google登录,需要确保生成的GoogleService-Info.plist文件位于Xcode中Runner项目的Runner目录中,因此Google登录框架可以确定您的客户端ID。将客户端ID的捆绑ID和反向URL添加到应用的Info.plist文件的主要字典中:

<key>CFBundleURLTypeskey>
  <array>
      <dict>
         <key>CFBundleTypeRolekey>
         <string>Editorstring>
         <key>CFBundleURLSchemeskey>
         <array>
          
<string>com.googleusercontent.apps.462578386393-kisbgopib3t6plf4dgv3s0n4ur3svjmostring>
         
            <string>com.yourcompany.friendlychatstring>
         array>
      dict>
  array>

我们可以在GoogleService-Info.plist文件中找到客户端ID的反向URL,复制REVERSED_CLIENT_ID字符串的值并粘贴以将其添加到CFBundleURLSchemes。当用户登录到应用程序时,此URL类型将处理回调。

Flutter实战一Flutter聊天应用(六)_第2张图片

第一次启动应用程序时,可能需要一两分钟才能启动。在iOS上,需要额外的时间来初始化Cocapods repo,而在Android上,需要下载maven的依赖关系。在下一组更改之后,我们将能够重新加载应用程序,并且开发周期将快得多。

现在我们的应用程序仅限于单个用户和设备,当用户发送消息时,应用程序将其标记为_name变量的值,并将其显示在同一个屏幕上,头像是一个简单的彩色圆圈。我们现在需要做的是,多个用户将能够通过实时数据库共享消息。为了有利于扩展应用程序,我们将个性化头像以区分用户。由于我们将拥有发件人的Google登录凭据,因此我们可以重用用户的个人资料照片。我们将在稍后的步骤中添加数据库支持。

首先,添加一个名为googleSignIn的全局变量,使用新的GoogleSignIn实例初始化它,我们将用它来调用Google登录API。在main.dart文件添加以下代码。

final googleSignIn = new GoogleSignIn();

现在定义两个私有方法,一个用于登录,另一个用于发送消息。添加_ensureLoggedIn()方法来检查GoogleSignIn实例的currentUser属性。在ChatScreenState中添加_ensureLoggedIn()方法定义。

class ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
  //...
  Future _ensureLoggedIn() async {
    GoogleSignInAccount user = googleSignIn.currentUser;
    if (user == null)
      user = await googleSignIn.signInSilently();
    if (user == null) {
      await googleSignIn.signIn();
    }
  }
  //...
}

以前的代码片段使用多个等待表达式依次执行Google登录方法。如果currentUser属性的值为null,应用程序将首先执行signInSilently(),获取结果并将其存储在user变量中。signInSilently方法尝试在没有交互的情况下登录之前经过身份验证的用户。此方法执行完毕后,如果user值仍为null,则应用程序将通过执行signIn()方法启动登录过程。用户登录后,我们可以从GoogleSignIn实例访问配置文件照片。

现在提交消息的过程有两步,认证和发送。我们需要协调工作,以便首先认证,如果成功,那么用户可以发送消息。首先,将_handleSubmitted方法从ChatScreenState拆分为两种单独的方法。而不是在_handleSubmitted()中执行所有提交的工作,我们将使用它来协调其他方法执行的任务,例如验证用户是否登录并发送消息。

_handleSubmitted()中保留_textController.clear()setState()... _isComposing方法调用。添加_ensureLoggedIn()_sendMessage()调用,如下面代码所示。

class ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
  //...
  Future _handleSubmitted(String text) async {
    _textController.clear();
    setState((){
      _isComposing = false;
    });
    await _ensureLoggedIn();
    _sendMessage(text: text);
  }
  //...
}

修改_handleSubmitted()的签名,表示它是一个不返回任何内容的异步方法。在尝试发送消息之前,将调用添加到await _ensureLoggedIn()以等待用户验证成功。现在我们来定义_sendMessage(),将_handleSubmitted()的其余部分添加到新的私有方法中。我们将使text成为一个命名参数,以便稍后可以向_sendMessage添加更多的String参数。

class ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
  //...
  void _sendMessage({ String text }) {
    ChatMessage message = new ChatMessage(
      text: text,
      animationController: new AnimationController(
        duration: new Duration(milliseconds: 300),
        vsync: this
      )
    );
    setState((){
      _messages.insert(0, message);
    });
    message.animationController.forward();
  }
  //...
}

为了个性化头像,我们在ChatMessage类的build()方法中使用新的GoogleUserCircleAvatar对象替换CircleAvatar控件,以及其Text控件。CircleAvatar可以使用网络图像,但是GoogleUserCircleAvatar帮助器类可以轻松地从GoogleSignIn实例获取正确大小的配置文件照片。google_sign_in.dart插件定义了这个类。

class ChatMessage extends StatelessWidget {
  //...
  @override
  Widget build(BuildContext context) {
    return new SizeTransition(
      //...
      child: new Container(
        margin: const EdgeInsets.symmetric(vertical: 10.0),
        child: new Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            new Container(
              margin: const EdgeInsets.only(right: 16.0),
              child: new GoogleUserCircleAvatar(googleSignIn.currentUser.photoUrl),
            ),
            //...
          ]
        )
      )
    );
  }
}

currentUser属性是身份验证对象,我们使用photoUrl获取新头像的图像。现在,我们需要个性化显示用户名。以前,我们使用硬编码显示用户名。现在我们已经集成了Google登录,我们可以删除_name全局变量。改成从已登录的Google用户处获取用户名。在ChatMessage类中使用来自GoogleSignIn实例的displayName设置_name变量。

class ChatMessage extends StatelessWidget {
  //...
  @override
  Widget build(BuildContext context) {
    return new SizeTransition(
      //...
      child: new Container(
        margin: const EdgeInsets.symmetric(vertical: 10.0),
        child: new Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            //...
            new Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                new Text(
                  googleSignIn.currentUser.displayName,
                  style: Theme.of(context).textTheme.subhead),
                new Container(
                  margin: const EdgeInsets.only(top: 5.0),
                  child: new Text(text),
                )
              ]
            )
          ]
        )
      )
    );
  }
}

现在,当我们发送消息时,头像和发件人姓名与您的Google帐户中的个人资料信息相匹配。随着我们继续进行更改并优化应用程序的UI,我们可以快速查看结果,而不需要重新启动完整的应用程序。使用Flutter的热重新加载功能将更新的源文件注入正在运行的Dart虚拟机(Dart Virtual Machine)并刷新UI。热重载是实验、原型设计和迭代的强大工具。

Flutter实战一Flutter聊天应用(六)_第3张图片

你可能感兴趣的:(dart,flutter,Flutter教程)