当前位置: 首页 > 知识库问答 >
问题:

Flutter:带有StreamBuilder的FirebaseAuth(v1.2.0)无法在Flutter Web中进行热重新加载

仇航
2023-03-14

所以在过去的几周里,我一直在测试FirebaseAuth的网页版和Android版,体验都很糟糕。我已经尽可能多的添加信息给你足够的背景。

我的目标

我的最终目标是制作一个包来简化Flutter中的FirebaseAuth。基本上,StreamBuilder在FirebaseAuth的authStateChanges流上运行,它在用户登录后或当我重新加载整个页面(Flutter Web)时立即给出一个用户,但在热重新加载期间不会返回用户,尽管我知道用户已经过身份验证。当我重新加载网页时,它再次工作。这在Android中是不存在的,并且它像预期的那样工作。这很令人沮丧,我需要任何人的帮助!

颤抖医生

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 2.0.2, on Microsoft Windows [Version 10.0.21296.1010], locale en-US)
[√] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
[√] Chrome - develop for the web
[!] Visual Studio - develop for Windows (Visual Studio Community 2019 16.5.5)
X Visual Studio is missing necessary components. Please re-run the Visual Studio installer for the
  "Desktop development with C++" workload, and include these components:
    MSVC v142 - VS 2019 C++ x64/x86 build tools
     - If there are multiple build tool versions available, install the latest
    C++ CMake tools for Windows
    Windows 10 SDK
[√] Android Studio (version 4.0)
[√] VS Code (version 1.56.2)
[√] Connected device (3 available)

飞镖版本控制

Dart VM version: 2.8.4 (stable) (Wed Jun 3 12:26:04 2020 +0200) on "windows_x64"

重现步骤

  • 创建Flutter应用程序
  • 创建Firebase应用程序
  • 在Firebase控制台中启用匿名身份验证
  • Flutter链接到Firebase Android应用程序(常规方式)
  • 链接Flutter到Firebase Web App(常规方式)
  • 添加依赖项(稍后显示)
  • 添加main。省道代码(稍后显示)
  • 使用flutter运行-d chrome运行

/web/index.html 中的火基SDK版本控制

<script src="https://www.gstatic.com/firebasejs/8.6.2/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.6.2/firebase-analytics.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.6.2/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.6.2/firebase-firestore.js"></script>

(the setup is correct as signIn works)

pubspec.yaml 依赖项

environment:
  sdk: ">=2.7.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

  #Firebase Dependencies
  firebase_core: ^1.2.0
  firebase_auth: ^1.2.0

颤振代码(main.dart)

import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

FirebaseAuth fa = FirebaseAuth.instance;
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  if (!kIsWeb) {
    await Firebase.initializeApp();
  }
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Auth Demo',
      home: AuthDemo(),
    );
  }
}

class AuthDemo extends StatelessWidget {
  const AuthDemo({Key key}) : super(key: key);

  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("AuthDemo"),
      ),
      body: Column(
        children: [
          ElevatedButton(
            onPressed: () async {
              await fa.signInAnonymously();
            },
            child: Text("Anon"),
          ),
          ElevatedButton(
            onPressed: () async {
              await fa.signOut();
            },
            child: Text("SignOut"),
          ),
          SizedBox(height: 20),
          StreamBuilder(
            stream: fa.authStateChanges(),
            builder: (context, snapshot) {
              return Text(snapshot.data?.uid ?? "[NULL]");
            },
          )
        ],
      ),
    );
  }
}

基本上,它会在页面重新加载时或刚登录后返回UID,但当热重新加载完成时,它会显示null,尽管用户实际上已登录。这正是问题所在!

请备注

我试着用这两个插件的1.0.0版本来测试它,以验证我的flutter版本是否不兼容,但那也不起作用。这与我对以下依赖版本的预期完全一样(热重装时打印UID ):

firebase_core: "^0.7.0"
firebase_auth: "^0.20.1"

这是非常非常令人沮丧的,绝对没有错误,警告或在控制台或任何地方。登录可以工作,但身份验证状态在Web中的Hot reload上不存在,(在android上完美工作),但它仅在这些旧版本上完美地适用于Web。这是一个错误吗?如果不是,请帮帮我。

谢谢大家!

玛纳斯·赫马迪

共有2个答案

寇桐
2023-03-14

Manas的答案有效(通过手动缓存登录状态),但这个错误现在也在flutter dev频道中得到修复。据我所知,这只会影响开发,因为它只会中断热重新加载/重新启动,但不会中断页面刷新。我发现在我的本地工作流程中,网络优先开发非常不方便,所以我切换到本地开发。

flutter channel dev
flutter upgrade

如前所述,这似乎是一个颤抖修复,暴露了DarkSDK错误。对于好奇的人,以下是此问题/修复程序的参考:

FlutterFire问题:https://github.com/FirebaseExtended/flutterfire/issues/6247

DartSDK问题:https://github.com/dart-lang/sdk/issues/45874

DartSDK修复:https://html" target="_blank">github.com/dart-lang/sdk/commit/460887d8149748d3feaad857f1b13721faadeffa

邹胜泫
2023-03-14

我刚找到解决这个问题的方法!基本上,FireFlutter团队已经修复了一个生产级bug和inturn,它暴露了Dart SDK的一个缺陷。由于这只是一个仅限开发的bug(仅在热重启期间出现),所以没有给予重视。

在我的研究中,我发现支持StreamBuilder和热重启的最后一个版本组合是

firebase_auth:0.20.1;firebase_core 0.7.0型

firebase_auth:1.1.0;firebase_core:1.0.3型

这些是它正常工作的唯一版本。每个后续版本都有暴露该 bug 的新升级。

解决方案非常简单!适用于最新版本(1.2.0)的firebase_auth和firebase_core插件!

首先导入Sharedpreferences

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart' as Foundation;
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class HotRestartBypassMechanism {
  ///The Standard SharedPreference instance
  static final Future<SharedPreferences> prefs =
      SharedPreferences.getInstance();

  ///Saves the Login State (true) for LoggedIn and (false) for LoggedOut
  static saveLoginState(bool isLoggedIn) async {
    //Ignore Operation if Not in DebugMode on Web
    if (!Foundation.kDebugMode && !Foundation.kIsWeb) return;

    SharedPreferences p = await prefs;
    p.setBool('is_logged_in', isLoggedIn);
  }

  ///Gets the login status from SharedPreferences
  static Future<bool> getLoginStatus() async {
    SharedPreferences p = await prefs;
    return p.getBool('is_logged_in') ?? false;
  }
}

class HotRestartByPassBuilder extends StatelessWidget {
  final Widget destinationFragment;
  final Widget loginFragment;
  const HotRestartByPassBuilder({
    Key key,
    this.destinationFragment,
    this.loginFragment,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<bool>(
      future: HotRestartBypassMechanism.getLoginStatus(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          if (snapshot.data) {
            return destinationFragment;
          } else {
            return loginFragment;
          }
        } else {
          return loginFragment;
        }
      },
    );
  }
}


//Usage In StreamBuilder
StreamBuilder(
  stream: FirebaseAuth.instance.authStateChanges(),
  builder: (context, snapshot) {
      if (snapshot.hasData) {
        return HomePage();
      } else {
        //Only in Debug Mode & in Web
        if (Foundation.kDebugMode && Foundation.kIsWeb) {
          //---------------------HOT RESTART BYPASS--------------------------
          return HotRestartByPassBuilder(
            destinationFragment: HomePage(),
            loginFragment: LoginPage(),
          );
          //-----------------------------------------------------------------
        } else {
          return LoginPage();
        }
      }
    },
);

//When User Logs in Use
await HotRestartBypassMechanism.saveLoginState(true);

//When User Logs out use
await HotRestartBypassMechanism.saveLoginState(false);

这确保了它在Flutter Web中的热重启期间按预期工作!

 类似资料:
  • 我有一个包含在StreamBuilder中的刷新指标。每当StreamBuilder添加了新数据时,刷新指标都会重建其Listview。建筑商在这个过程中跳到了顶端。 StreamBuilder(stream: apiResultStream.stream,Builder:(BuildContext上下文,AsyncSnapshot快照){if(snapshot.has错误){print(有错误)

  • 在最新的Flutter 1.0稳定版和Dart更新到vscode之后,我无法使用vscode的热加载。如果我从终端运行它,一切都很好。颤抖的医生没有抱怨,我不知道如何解决它。我试图从vscode中卸载颤动和飞镖,但到目前为止没有运气。我得到的错误是 ../../third _ party/dart/runtime/VM/object . h:8954:错误:句柄检查失败:see ' home pa

  • 我刚刚开始使用jhipster,已经面临一个问题, 这是我的开发堆栈: -os windows 7 -eclipse Juno -maven 3.1 -最新节点和npm -mysql作为ubuntu vm中的db 以下是我所做的: -生成jhipster“yo jhipster” -将其转换为maven项目“mvn eclipse:eclipse” -maven编译“mvn clean” 感谢所有

  • 问题内容: 我目前正在研究应用程序的聊天功能。并且我在StreamBuilder中设置了AnimatedList,以使消息反向显示。这是我的代码 我的问题是该构建器从未被点击,因此AnimatedList从未被调用。我不确定设置是否正确,因此对此表示感谢。 编辑:我正在尝试使其像FirebaseAnimatedList小部件一样工作。我不知道这是否有助于了解我的目标。 谢谢 问题答案: 更新:我通

  • 我是Flutter的新手,面临着StreamBuilder的问题 我在点击卡片列表中可用的按钮(应用按钮)时进行网络呼叫,基于显示的其他按钮。 我面临的问题是,小部件不更新成功的网络调用后,但当我刷新页面我得到更新的结果。 我做错了什么? 我没有在这方面使用任何状态。我需要用它吗? //下面是我如何将数据添加到流中的 预期结果:当我进行网络呼叫时,如果成功,那么根据网络结果,其他按钮必须显示在相应

  • ****无法在新的数据框架中追加行**任何afert都将被应用**