2017-09-05 31 views
1

我一直在試圖通過我的應用程序的基礎上FirebaseAuth值找出正確的方法來設置導航(即:瀏覽他們登錄後才用戶)如何正確設置基於認證的導航

所以我創建了一個場景,我有三個類,首先列出我的測試用例,然後討論我最後面臨的問題。

User類是在我的應用程序的第一頁,它吸引它是小部件檢查是否有後currentUser或不

class User extends StatefulWidget { 
     @override 
     _UserState createState() => new _UserState(); 
    } 

    class _UserState extends State<User> { 
     FirebaseUser _user; 


     @override 
     initState() { 
     super.initState(); 
     _checkUser(); 
     } 

     @override 
     Widget build(BuildContext context) { 
     return _user == null? new SignInPage(): new HomePage(); 
     } 

     _checkUser()async { 
     FirebaseUser user = await FirebaseAuth.instance.currentUser(); 
     setState((){ 
      this._user = user; 
     }); 

     } 
    } 

當應用程序在第一次啓動時,它加載SignInPage自沒有用戶數據:

class SignInPage extends StatefulWidget { 
    @override 
    _SignInPageState createState() => new _SignInPageState(); 
} 

class _SignInPageState extends State<SignInPage> { 

    final FirebaseAuth _auth = FirebaseAuth.instance; 
    final GoogleSignIn _googleSignIn = new GoogleSignIn(); 


    _handleSignIn() async{ 

    final GoogleSignInAccount googleUser = await _googleSignIn.signIn(); 
    final GoogleSignInAuthentication googleAuth = 
    await googleUser.authentication; 
    final FirebaseUser user = await _auth.signInWithGoogle(
     accessToken: googleAuth.accessToken, 
     idToken: googleAuth.idToken, 
    ); 
    assert(user.email != null); 
    assert(user.displayName != null); 
    assert(!user.isAnonymous); 
    assert(await user.getToken() != null); 
    print (user); 

     } 
    @override 
    Widget build(BuildContext context) { 
    return new Scaffold(
     appBar: new AppBar(
      title: new Text("Sign In"), 
      centerTitle: true, 
      leading: new Container(), 
      backgroundColor: new Color.fromARGB(255,17,165,137)), 
     body: new Container(
      child: new Center(
       child: 
       new Column(
        mainAxisAlignment: MainAxisAlignment.center, 
        children: <Widget>[ 
        new Row(
         mainAxisAlignment: MainAxisAlignment.center, 
         mainAxisSize: MainAxisSize.max, 
         children: <Widget>[new RaisedButton(
          child: new Container(
           child: new Row(children: <Widget>[ 
           new Container(
            child: new Image(
             image: new NetworkImage(
              "https://maxcdn.icons8.com/Share/icon/Logos//google_logo1600.png"), 
            ), 
            margin: new EdgeInsets.only(right: 8.0)), 
           new Text("Login with Google", style: new TextStyle(color: Colors.redAccent)), 
           ], mainAxisAlignment: MainAxisAlignment.center)), 
          onPressed:(){_handleSignIn().whenComplete((){Navigator.of(context).pushNamed("/Home");});} 

          ,color: Colors.white), 
         ],), 
        new Row(
         mainAxisAlignment: MainAxisAlignment.center, 
         mainAxisSize: MainAxisSize.max, 
        ) 


        ], 
       ) 
      ) 
     ) 
    ); 
    } 


} 

這是我HomePage類,這是隻有在通過身份驗證訪問;我的首頁包含了中央的RaisedButton,並具有Text孩子當前用戶的displayName的,和onPressed()行動調用_signOut()方法,並返回到SignInage

final GoogleSignIn _googleSignIn = new GoogleSignIn(); 


class HomePage extends StatefulWidget { 
    @override 
    _HomePageState createState() => new _HomePageState(); 
} 

class _HomePageState extends State<HomePage> { 
    FirebaseUser _currentUser; 

    initState() { 
    super.initState(); 
    _myUser(); 
    } 
    @override 
    Widget build(BuildContext context) { 
    return new Scaffold(
     appBar: new AppBar(
     title: new Text("Hello:)"), 
    ), 
     body: new Center(
     child: new RaisedButton(child: new Text(_currentUser.displayName), 
      onPressed:(){_signOut().whenComplete((){Navigator.of(context).pushNamed("/SignInPage");});}) 
    ), 
    ); 
    } 
    _signOut() async { 
    await FirebaseAuth.instance.signOut(); 

    await _googleSignIn.signOut(); 

    return "Signed out"; 
    } 

    _myUser()async { 
    FirebaseUser user = await FirebaseAuth.instance.currentUser(); 

    setState((){ 
     this._currentUser = user; 
    }); 
    } 


} 

問題:

  1. 當應用程序第一次啓動時,它會像平常一樣加載SignInPage,但是當我成功登錄到我的Google帳戶時,它凍結而不導航我,因爲displayName was called on Null,從我的理解,撲沒有足夠的時間來準備用戶數據導航發生前,我猜測是因爲在點2發生了什麼和3

  2. 當重新啓動應用程序,並保留先前的身份驗證會話本,該應用程序將自動從Home頁開始,並正確顯示displayName。

  3. 在同一次會議上,我點擊它簽署了RaisedButton正確導航我回到SignInPage,我嘗試再次登錄,我們又回到了主要問題,它會嘗試之前的導航我到我Home獲得displayName

這是我如何理解問題,所以我在這裏做錯了什麼,以及如何設計正確的流程?

P.S:我想這樣做的原因是因爲我想在我的HomePage使用的currentUser一些數據。

更新:

控制檯打印如下:

'package:test/SignInScreen.dart': Failed assertion: line 26: 'user.email != null': is not true. 

這是在_handleSignInassert語句。

我也嘗試創建一個預置主頁,發生同樣的問題,我不知道現在有什麼問題。

回答

1

我建議使用FutureBuilderFirebaseAuth.instance.currentUser()作爲future的參數。然後在您的builder方法中,如果AsyncSnapshothasData屬性爲false,那麼您知道該小部件仍在加載,並且應該顯示一個佔位符。 Future完成後,您可以使用AsyncSnapshotdata屬性獲取FirebaseUser

或者,您可以檢查_currentUser在您的build方法中是否爲空,並返回空容器,因爲用戶信息尚不可用。

+0

我仍然遇到同樣的問題,但讓我們說如果hasData是false,那麼如何保持主頁的加載直到它是真實的,什麼樣的佔位符將重定向到我的家當currentUser()終於準備好了。 如果您在帖子中查看更新的部分,您會發現我甚至試圖在SignInPage之後放置一個虛擬頁面,以便爲我的HomePage準備好一切,並且仍然是同樣的問題。 – aziza

+0

,當我們檢查_currentUser爲null時,我們知道它是空的,至少對於當前運行,直到我重新啓動應用程序,這是問題的核心。 – aziza

+0

請問你有沒有設法重現相同的問題,或者我錯過了什麼? – aziza