質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Firebase Authentication

Firebase Authenticationは、Firebaseを利用したユーザーの認証機能です。バックエンドサービス、SDK、アプリでのユーザー認証に使用できるUIライブラリが用意されています。

Q&A

1回答

1711閲覧

Firebase authでのログイン状態の保持を実装したいです。

kj0221

総合スコア0

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Firebase Authentication

Firebase Authenticationは、Firebaseを利用したユーザーの認証機能です。バックエンドサービス、SDK、アプリでのユーザー認証に使用できるUIライブラリが用意されています。

0グッド

0クリップ

投稿2023/02/02 02:09

編集2023/02/06 01:16

ログイン済みの場合はログイン後の画面(signed_in_screen)、ログインしていない場合はログイン前の画面(community _screen)の画面を表示したいのですがコーディングを教えてください。

main.dart

import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:kaisupo/screens/home_screen.dart'; import 'package:kaisupo/firebase_options.dart'; Future<void> main() async { //main関数を非同期処理にするときに必ず必要になる WidgetsFlutterBinding.ensureInitialized(); //Firebase初期化 await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: "介護従事者応援アプリ", theme: ThemeData( brightness: Brightness.light, primarySwatch: Colors.blue, ), debugShowCheckedModeBanner: false, // home: HomeScreen(), home: HomeScreen(), ); } }

kaisupo/screens/community_screen.dart

import 'package:firebase_auth/firebase_auth.dart'; import 'package:kaisupo/screens/signed_in_screen.dart'; import 'package:flutter/material.dart'; import 'package:kaisupo/parts/back_gradation_setting.dart'; import 'package:kaisupo/parts/bottom_navigation_bar.dart'; import 'package:kaisupo/parts/title_text.dart'; //介護士コミュニティ class CommunityScreen extends StatefulWidget { @override _CommunityScreenState createState() => _CommunityScreenState(); } class _CommunityScreenState extends State<CommunityScreen> { //現在のタブを保持する変数の定義と初期値の設定 var _currentTab = TabItem.community; final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); final TextEditingController _emailController = TextEditingController(); final TextEditingController _passwordController = TextEditingController(); //タブの更新 void _selectedTab(TabItem tabItem) { setState(() => _currentTab = tabItem); } @override Widget build(BuildContext context) => MaterialApp( home: Scaffold( appBar: PreferredSize( preferredSize: const Size.fromHeight(60.0), child: AppBar( title: TitleTextCreate( title: "介護士コミュニティ", size: 30, color: Colors.white, radius: 18, shadow: Colors.indigo), centerTitle: true, backgroundColor: Colors.lightGreen.shade400, ), ), //BottomNavigationBarセット bottomNavigationBar: BottomNavigationBarSet( currentTab: _currentTab, onSelectedTab: _selectedTab, ), body: SafeArea( key: _formKey, child: Stack(children: [ //背景グラデーション BackGroundDecoration( first: Colors.deepOrangeAccent.shade200, second: Colors.amber.shade300, third: Colors.yellow.shade200), StreamBuilder<User?>( stream: FirebaseAuth.instance.authStateChanges(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { // スプラッシュ画面などに書き換えても良い return const SizedBox(); } if (snapshot.hasData) { // User が null でなない、つまりサインイン済みのホーム画面へ return CommunityScreen(); } // User が null である、つまり未サインインのサインイン画面へ return SignedInScreen(); }, ), SingleChildScrollView( child: Container( width: MediaQuery.of(context).size.width, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ TextFormField( controller: _emailController, decoration: InputDecoration(labelText: 'メールアドレス'), keyboardType: TextInputType.emailAddress, validator: (String? value) { if (value?.isEmpty == true) { return 'メールアドレスを入力して下さい'; } return null; }, ), SizedBox(height: 8), TextFormField( controller: _passwordController, decoration: InputDecoration(labelText: 'パスワード'), keyboardType: TextInputType.visiblePassword, obscureText: true, validator: (String? value) { if (value?.isEmpty == true) { return 'パスワードを入力して下さい'; } return null; }, ), SizedBox(height: 16), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () => _onSignIn(), child: Text('ログイン'), ), ), SizedBox(height: 8), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () => _onSignUp(), child: Text('新規登録'), ), ), ]), ), ), ]), ), ), ); Future<void> _onSignIn() async { try { if (_formKey.currentState?.validate() != true) { return; } //新規登録と同じく入力された内容をもとにログイン処理を行う final String email = _emailController.text; final String password = _passwordController.text; await FirebaseAuth.instance .signInWithEmailAndPassword(email: email, password: password); Navigator.of(context).pushReplacement( MaterialPageRoute( builder: (_) => SignedInScreen(), ), ); } catch (e) { await showDialog( context: context, builder: (context) { return AlertDialog( title: Text('エラー'), content: Text(e.toString()), ); }, ); } } Future<void> _onSignUp() async { try { if (_formKey.currentState?.validate() != true) { return; } final String email = _emailController.text; final String password = _passwordController.text; await FirebaseAuth.instance .createUserWithEmailAndPassword(email: email, password: password); Navigator.of(context).pushReplacement( MaterialPageRoute( builder: (_) => SignedInScreen(), ), ); } catch (e) { await showDialog( context: context, builder: (context) { return AlertDialog( title: Text('エラー'), content: Text(e.toString()), ); }, ); } } }

kaisupo/screens/signed_in_screen.dart

import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:kaisupo/screens/community_screen.dart'; import 'package:kaisupo/parts/back_gradation_setting.dart'; import 'package:kaisupo/parts/bottom_navigation_bar.dart'; import 'package:kaisupo/parts/title_text.dart'; class SignedInScreen extends StatefulWidget { @override _SignedInScreenState createState() => _SignedInScreenState(); } class _SignedInScreenState extends State<SignedInScreen> { var _currentTab = TabItem.community; //タブの更新 void _selectedTab(TabItem tabItem) { setState(() => _currentTab = tabItem); } Widget build(BuildContext context) { return Scaffold( appBar: PreferredSize( preferredSize: const Size.fromHeight(60.0), child: AppBar( title: TitleTextCreate( title: "介護士コミュニティ", size: 30, color: Colors.white, radius: 18, shadow: Colors.indigo), centerTitle: true, backgroundColor: Colors.lightGreen.shade400, actions: [ //ログアウト用ボタン IconButton( onPressed: () => _onSignOut(), icon: Icon(Icons.exit_to_app), ), ], ), ), //BottomNavigationBarセット bottomNavigationBar: BottomNavigationBarSet( currentTab: _currentTab, onSelectedTab: _selectedTab, ), ); } Future<void> _onSignOut() async { //ログアウト処理 await FirebaseAuth.instance.signOut(); //ログアウトに成功したらログイン画面に戻す //現在の画面は不要になるのでpushReplacementを使う Navigator.of(context).pushReplacement( MaterialPageRoute( builder: (_) => CommunityScreen(), ), ); } }

変更
試したこと
[参考サイト]https://qiita.com/KosukeSaigusa/items/b19ec19379c5a2e4ceb2を参考に、実装しようと試みましたが、デバッグした後、RUNすることは出来たものの、community screeの画面が幾重にも重なる現象がおきました。その後、調べてはみたものの修正方法がわからず、お聞きしたく。

UI

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

AbeTakashi

2023/02/02 06:31

「うまくできず」の部分が質問の肝でありこのサービスの要の部分となりますので、その辺はしっかり追記されるといいと思います。 参考) https://teratail.com/help/question-tips 上から下までいちどすべて目を通されるといいかと思います。
moriman

2023/02/02 07:53

リンク先のコードに特に違和感を感じる箇所は無いのですが、エラーが出ますか? エラーが出ている場合エラーメッセージと該当箇所のコードを示すと、求めている情報を得られる可能性が高まると思います。
kj0221

2023/02/06 00:58

承知いたしました。ご丁寧にありがとうございました。今から変更いたします。
moriman

2023/02/06 03:25

一つ確認したいのですが、 リンク先では SignInPage : 未サインイン時に表示する画面 HomePage : サインイン済み時に表示する画面 ということですよね。 あなたのコードで「未サインイン時に表示する画面」「サインイン済み時に表示する画面」は何ですか?
kj0221

2023/02/06 03:30

説明不足で申し訳ございません。 CommunityScreen:未サインイン時に表示する画面 SignedInScreen : サインイン済み時に表示する画面 です。 よろしくお願いいたします。
guest

回答1

0

ということは
「リンク先コード(ページ後半のStreamBuilderを使用しているバージョン)のクラス」

「あなたのコードのクラス」
の対応関係としては、
リンク先 : あなたのコード
SignInPage : CommunityScreen
HomePage : SignedInScreen
App : MyApp + HomeScreen
という対応関係になると思います。

(1)リンク先ではStackは使用されていない
(2)リンク先ではStreamBuilderはAppで使用されているので、あなたのコードではHomeScreenで使用されるべき。しかし実際あなたのコードではCommunityScreen(_CommunityScreenState)で使用している。
(3)

builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { // スプラッシュ画面などに書き換えても良い return const SizedBox(); } if (snapshot.hasData) { // User が null でなない、つまりサインイン済みのホーム画面へ return CommunityScreen(); } // User が null である、つまり未サインインのサインイン画面へ return SignedInScreen(); },

上記のCommunityScreen()とSignedInScreen()の記述箇所が逆。

繰り返しになりますが、リンク先のロジックは基本的に正しいと思います。
ですのであなたがリンク先のロジックを忠実に真似すれば期待通りの挙動になると思います。
現時点で上記に示した箇所がリンク先のロジックと違うので無限呼び出しのような形になり画像のような結果が出ていると思われます。
まず「自分のやろうとしていること」、「リンク先のコードのロジック」を整理・理解して、正確に再現する必要があると思います。

  • (1)に関して、Stackを使用する方法も無くはないと思いますが、リンク先のロジックの方がシンプルで一般的なので、それを正確に真似することが現時点であなたがゴールに到達する一番の近道のような気がします。

投稿2023/02/06 03:46

編集2023/02/06 03:56
moriman

総合スコア615

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kj0221

2023/02/06 04:07

ご丁寧に回答頂きありがとうございました。これから実際に修正していきます。 また、コメントさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問