1. 程式人生 > >Flutter實戰一Flutter聊天應用(六)

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提供商,具體如下:

這裡寫圖片描述

要在iOS上配置Google登入,需要確保生成的GoogleService-Info.plist檔案位於Xcode中Runner專案的Runner目錄中,因此Google登入框架可以確定您的客戶端ID。將客戶端ID的捆綁ID和反向URL新增到應用的Info.plist檔案的主要字典中:

<key>CFBundleURLTypes</key>
  <array>
      <dict>
         <key>CFBundleTypeRole</key>
         <string
>
Editor</string> <key>CFBundleURLSchemes</key> <array> <!-- 反轉客戶端ID的URL --> <string>com.googleusercontent.apps.462578386393-kisbgopib3t6plf4dgv3s0n4ur3svjmo</string> <!-- 捆綁ID --> <string>com.yourcompany.friendlychat</string
>
</array> </dict> </array>

我們可以在GoogleService-Info.plist檔案中找到客戶端ID的反向URL,複製REVERSED_CLIENT_ID字串的值並貼上以將其新增到CFBundleURLSchemes。當用戶登入到應用程式時,此URL型別將處理回撥。

這裡寫圖片描述

第一次啟動應用程式時,可能需要一兩分鐘才能啟動。在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<Null> _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: <Widget>[
            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: <Widget>[
            //...
            new Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                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。熱過載是實驗、原型設計和迭代的強大工具。

這裡寫圖片描述