Web 中的 Flutter firebase 实时数据库
Flutter firebase realtime database in web
我正在尝试让我的 flutter 应用程序在浏览器中运行,这取决于 firebase_database。实际上并没有关于如何执行此操作的任何文档,但我根据 firebase_core 和 firebase_auth 文档做了一些假设:
https://github.com/FirebaseExtended/flutterfire/tree/master/packages/firebase_core/firebase_core_web
https://github.com/FirebaseExtended/flutterfire/tree/master/packages/firebase_auth/firebase_auth_web
我的应用程序正在 iOS 和 android 上运行,但我无法让数据库在 flutter web 中运行。
我已经设置了 index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flutter WebRTC Demo</title>
</head>
<body>
<script src="https://www.gstatic.com/firebasejs/7.6.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.6.1/firebase-database.js"></script>
<script>
const firebaseConfig = {
apiKey: '...',
authDomain: '...',
databaseURL: '...',
projectId: '...',
storageBucket: '...',
messagingSenderId: '...',
appId: '...'
};
firebase.initializeApp(firebaseConfig);
</script>
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
但是,当我尝试使用 firebase 数据库时,我在日志中收到错误消息:
MissingPluginException(No implementation found for method DatabaseReference#set on channel plugins.flutter.io/firebase_database)
package:dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 196:49 throw_
package:flutter/src/services/platform_channel.dart 319:7 invokeMethod
package:dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 47:50 onValue
package:dart-sdk/lib/async/zone.dart 1381:54 runUnary
package:dart-sdk/lib/async/future_impl.dart 139:18 handleValue
package:dart-sdk/lib/async/future_impl.dart 680:44 handleValueCallback
package:dart-sdk/lib/async/future_impl.dart 709:32 _propagateToListeners
package:dart-sdk/lib/async/future_impl.dart 524:5 [_completeWithValue]
package:dart-sdk/lib/async/future_impl.dart 554:7 callback
package:dart-sdk/lib/async/schedule_microtask.dart 43:11 _microtaskLoop
package:dart-sdk/lib/async/schedule_microtask.dart 52:5 _startMicrotaskLoop
package:dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 168:15 <fn>
有什么方法可以让实时数据库在我的网络版 Flutter 应用程序中运行?
FlutterFire 插件最初是为 iOS 和 Android 的原生移动应用程序而构建的。目前正在将对 Web 平台的支持添加到插件中,但要涵盖所有 Firebase 产品还需要一些时间。
您可以在 Github 存储库的 available FlutterFire plugins 列表中检查当前哪些模块与 Flutter for web 兼容。
要在 Flutter for web 的其他功能上使用 Firebase,请使用 firebase-dart
plugin。这意味着您需要为 Web 和移动设备编写单独的代码,但您可以仅在应用的一小部分中隔离差异。
2021 年更新
现在支持对 firebase 数据库的 Web 支持。参见 PR here.
在the main README in the flutterfire github中,有一个“Web?”用于记录哪些插件已准备好用于网络的列。
目前,Flutter Web 应用仅支持 firebase_core
、firebase_auth
、cloud_firestore
和 firebase_functions
。
正如@Frank van Puffelen 提到的,要在 flutter web 中使用 firebase 的全部功能,请使用 firebase-dart 包装器库。
还有一个 Flutter Web Plugins Project Board 显示路线图上有哪些 flutter 插件,以及它们处于哪个开发阶段。在本次编辑时,firebase_storage
是网络路线图上的下一个插件。
pre flutter 2.0解决方案。
在这个问题上经过几天的努力,并且由于评论中几乎没有未解决的问题,我决定 post 一个完整的、长长的答案,以帮助像我一样刚开始的人。
这就是我实现这两个不同包的方式。
当我使用 flutter_bloc
进行状态管理时,我基本上必须像对用户位置所做的那样使存储库平台依赖。
为了实现它,我使用了 stub/abstract class/ web implementation/ device implementation 模式。因此,在我集团的存储库中,我只是调用抽象 class 方法,这些方法将使用适当的包映射到适当的平台实现 class。一开始看起来有点乱,但一旦掌握了这个概念就很容易了,但是 Thera 是一些在开始使用模式时可能会掉入的陷阱。
对于设备实现,使用 flutter_auth
包,而对于 Web 实现,使用 flutter
包,为了简单起见,我制作了一个单例。现在,单例 return 是初始化的 firebase App
,可让您访问所有服务.. auth()
、database()
、firestore()`、remoteconfig()...
无论您需要访问任何 firebase 服务,只需实例化 Firebase 并使用这些服务即可。
App firebase = FirebaseWeb.instance.app;
...
await firebase.auth().signInWithCredential(credential);
return firebase.auth().currentUser;
下面是我用于授权的所有代码,但很容易适应不同的 firebase 服务:
存根:
这只是为了持有一个 (getter) 方法,该方法在抽象 class 工厂方法(我称之为切换器)中得到 returned,并允许有条件的导入抽象 class 到正确的实现 class.
import 'package:firebaseblocwebstub/platform_user_repository/platform_user_repository_switcher.dart';
UserRepositorySwitcher getUserRepository() {
print('user_repository_stub called');
}
摘要class(切换台):
在这里导入存根,以便能够有条件地导入正确的实现 class。 return 中的存根 (getter) 方法在 class 工厂方法中编辑。
在这个class中你需要声明所有你需要使用的方法。这里 returns 是动态的,因为包特定 returns 将在平台实现中 classes。
注意条件导入中的拼写错误和正确的文件路径,因为没有自动检查。我花了很多时间才找到它哈哈。。
import 'package:firebaseblocwebstub/platform_user_repository/platform_user_repository_stub.dart'
if (dart.library.io) 'package:firebaseblocwebstub/platform_user_repository/platform_user_repository_device.dart'
if (dart.library.js) 'package:firebaseblocwebstub/platform_user_repository/platform_user_repository_web.dart';
abstract class UserRepositorySwitcher {
Future<dynamic> signInWithGoogle() async {
print('UserREpository switcher signInWithGoogle() called');
}
Future<void> signInWithCredential({String email, String password}) {}
Future<void> signUp({String email, String password}) {}
Future<void> signOut() async {}
Future<bool> isSignedIn() async {}
Future<dynamic> getUser() async {}
factory UserRepositorySwitcher() => getUserRepository();
}
设备实现class:
必须实现抽象 class 才能掌握并实现具有特定(flutter_auth
在本例中)方法和类型的方法。在这里,您还必须在 class 范围之外声明存根中的相同方法,即 return 的设备实现 class(参见底部代码)。
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebaseblocwebstub/authentication_bloc/app_user.dart';
import 'package:firebaseblocwebstub/platform_user_repository/platform_user_repository_switcher.dart';
import 'package:google_sign_in/google_sign_in.dart';
class UserRepositoryDevice implements UserRepositorySwitcher {
final FirebaseAuth _firebaseAuth;
final GoogleSignIn _googleSignIn;
UserRepositoryDevice({FirebaseAuth firebaseAuth, GoogleSignIn googleSignIn})
: _firebaseAuth = firebaseAuth ?? FirebaseAuth.instance,
_googleSignIn = googleSignIn ?? GoogleSignIn();
Future<FirebaseUser> signInWithGoogle() async {
print('signInWithGoogle() from device started');
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
print('GoogleUser is : $googleUser');
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final AuthCredential credential = await GoogleAuthProvider.getCredential(
idToken: googleAuth.idToken, accessToken: googleAuth.accessToken);
await _firebaseAuth.signInWithCredential(credential);
return _firebaseAuth.currentUser();
}
Future<void> signInWithCredential({String email, String password}) {
return _firebaseAuth.signInWithEmailAndPassword(
email: email, password: password);
}
Future<void> signUp({String email, String password}) {
return _firebaseAuth.createUserWithEmailAndPassword(
email: email, password: password);
}
Future<void> signOut() async {
return Future.wait([
_firebaseAuth.signOut(),
_googleSignIn.signOut(),
]);
}
Future<bool> isSignedIn() async {
final currentUser = _firebaseAuth.currentUser();
return currentUser != null;
}
Future<FixitUser> getUser() async {
String displayName = (await _firebaseAuth.currentUser()).displayName;
String email = (await _firebaseAuth.currentUser()).email;
String uid = (await _firebaseAuth.currentUser()).uid;
String photoUrl = (await _firebaseAuth.currentUser()).photoUrl;
String phoneNumber = (await _firebaseAuth.currentUser()).phoneNumber;
FixitUser user = FixitUser(
// fixitUser
name: displayName ?? '',
email: email,
phoneNumber: phoneNumber ?? '',
uid: uid,
photoUrl: photoUrl ?? '');
return (user);
}
}
UserRepositorySwitcher getUserRepository() => UserRepositoryDevice();
现在终于可以上网了..
firebase 单例:
为了方便地使用 firebase
包,我决定将其设为单例。
在这里你可以 return 一个 Future<App>
实例但是你必须 .then
一切..或者 return 直接 App
..我选择了这种方式..更清洁和更快的实施。
这样你就不必在你的 index.html
文件中初始化 firebase,否则你会得到一个错误,因为它已经初始化了。在这里初始化 firebase 也让你的密钥不暴露..
import 'dart:async';
import 'package:firebase/firebase.dart';
class FirebaseWeb {
// Singleton instance
static final FirebaseWeb _singleton = FirebaseWeb._();
// Singleton accessor
static FirebaseWeb get instance => _singleton;
// A private constructor. Allows us to create instances of AppDatabase
// only from within the AppDatabase class itself.
FirebaseWeb._();
static App _app;
// Database object accessor
App get app {
print('firebase get app called ');
print('_app is $_app');
if (_app != null) {
return _app;
} else {
print('initialize app');
_app = initializeApp(
apiKey: "your key",
authDomain: "your key",
databaseURL: "your key",
projectId: "your key",
storageBucket: "your key",
messagingSenderId: "your key",
appId: "your key");
print('initialized app is $_app'); // await _initializeApp();
return _app;
}
}
}
网络实施:
在这里你只是使用单例实例化Firebase,并实现抽象class方法,使用它的服务和方法..我在这里使用auth()
。
您可以看到(注释掉的部分)如果 return a Future<App>
在单身人士中,实施会更加冗长..
这里存根 getter 方法将 return 这个 class ..(检查底部)
import 'dart:async';
import 'package:firebase/firebase.dart';
import 'package:firebaseblocwebstub/authentication_bloc/app_user.dart';
import 'package:firebaseblocwebstub/firebase_singleton.dart';
import 'package:firebaseblocwebstub/platform_user_repository/platform_user_repository_switcher.dart';
import 'package:google_sign_in/google_sign_in.dart';
class UserRepositoryWeb implements UserRepositorySwitcher {
App firebase = FirebaseWeb.instance.app;
final GoogleSignIn _googleSignIn = GoogleSignIn();
Future<User> signInWithGoogle() async {
print('signInWithGoogle() started');
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
print('GoogleUser is : $googleUser');
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final OAuthCredential credential = await GoogleAuthProvider.credential(
googleAuth.idToken, googleAuth.accessToken);
// singleton retunrning Future<App>
// await firebase.then((firebase) {
// firebase.auth().signInWithCredential(credential);
// return;
// });
// return firebase.then((firebase) {
// return firebase.auth().currentUser;
// });
await firebase.auth().signInWithCredential(credential);
return firebase.auth().currentUser;
}
Future<void> signInWithCredential({String email, String password}) {
return firebase.auth().signInWithEmailAndPassword(email, password);
// singleton retunrning Future<App>
// return firebase.then((firebase) {
// return firebase.auth().signInWithEmailAndPassword(email, password);
// });
}
Future<void> signUp({String email, String password}) {
return firebase.auth().createUserWithEmailAndPassword(email, password);
// singleton retunrning Future<App>
// return firebase.then((firebase) {
// return firebase.auth().createUserWithEmailAndPassword(email, password);
// });
}
Future<void> signOut() async {
return Future.wait([
firebase.auth().signOut(),
// singleton retunrning Future<App>
// firebase.then((firebase) {
// firebase.auth().signOut();
// }),
_googleSignIn.signOut(),
]);
}
Future<bool> isSignedIn() async {
final currentUser = firebase.auth().currentUser;
return currentUser != null;
// singleton retunrning Future<App>
// User firebaseUser = firebase.then((firebase) {
// return firebase.auth().currentUser;
// }) as User;
// return firebaseUser != null;
}
Future<FixitUser> getUser() async {
// singleton retunrning Future<App>
// User firebaseUser = firebase.then((firebase) {
// return firebase.auth().currentUser;
// }) as User;
//
// FixitUser user = FixitUser(
// name: firebaseUser.displayName ?? '',
// email: firebaseUser.email,
// phoneNumber: firebaseUser.phoneNumber ?? '',
// uid: firebaseUser.uid,
// photoUrl: firebaseUser.photoURL ?? '');
// return (user);
// }
String displayName = (firebase.auth().currentUser).displayName;
String email = (firebase.auth().currentUser).email;
String uid = (firebase.auth().currentUser).uid;
String photoUrl = (firebase.auth().currentUser).photoURL;
String phoneNumber = (firebase.auth().currentUser).phoneNumber;
FixitUser user = FixitUser(
name: displayName ?? '',
email: email,
phoneNumber: phoneNumber ?? '',
uid: uid,
photoUrl: photoUrl ?? '');
return (user);
}
}
UserRepositorySwitcher getUserRepository() => UserRepositoryWeb();
我遇到了同样的问题,并决定采取一些措施。所以我继续做了 https://pub.dev/packages/firebase_db_web_unofficial 。它很容易设置并集成到您的代码中。
万一有人还在寻找 flutter web 实时数据库问题的另一种解决方法,我有一个简单而直接的解决方案...
我做了一些挖掘,if(kIsWeb) 似乎有效。
第一
为 android|ios 添加 firebase package that supports Realtime database for web and firebase_databe package。
第二
初始化 firebase
void main() async {
await Firebase.initializeApp();
}
第三
导入如下
import 'package:firebase_database/firebase_database.dart';
import 'package:firebase/firebase.dart' as fb;
第四
关于如何读取 android-ios/web 的实时数据库数据的示例。
在这里,我将图像添加到轮播滑块。
List<SliderImage> sliderList = [];
void getSliderData() async {
FirebaseDatabase firebaseDatabaseference = FirebaseDatabase.instance;
firebaseDatabaseference.setPersistenceEnabled(true);
firebaseDatabaseference.setPersistenceCacheSizeBytes(10000000);
//for web
if (kIsWeb) {
fb.DatabaseReference databaseRef = fb.database().ref("Slider");
await databaseRef.onValue.listen((event) {
fb.DataSnapshot dataSnapshot = event.snapshot;
sliderList.clear();
this.setState(() {
for (var value in dataSnapshot.val()) {
sliderList.add(new SliderImage.fromJson(value));
}
});
});
// for android and ios
} else {
DatabaseReference databaseReference = firebaseDatabaseference.reference();
databaseReference.keepSynced(true);
await databaseReference
.child("Slider")
.once()
.then((DataSnapshot dataSnapshot) {
sliderList.clear();
this.setState(() {
for (var value in dataSnapshot.value) {
sliderList.add(new SliderImage.fromJson(value));
}
});
});
}
}
轮播滑块
CarouselSlider.builder(
itemCount: sliderList.length,
options: CarouselOptions(
autoPlay: true,
aspectRatio: 16 / 9,
viewportFraction: 1,
enlargeCenterPage: false,
enlargeStrategy: CenterPageEnlargeStrategy.height,
),
itemBuilder: (context, index, realIdx) {
return Container(
child: Center(
child: Image.network(sliderList[index].image, loadingBuilder:
(BuildContext context, Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
valueColor:
new AlwaysStoppedAnimation<Color>(Colors.black54),
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes
: null,
),
);
}, fit: BoxFit.cover, width: 1000)),
);
},
));
SliderImage 模型class
class SliderImage {
String image;
SliderImage(this.image);
SliderImage.fromJson(var value) {
this.image = value['image'];
}
}
类似的方法可以应用于 Listview.builder。
干杯
存在一个包https://pub.dev/packages/firebase_db_web_unofficial/install(非官方 Firebase 数据库集成)
这对我有用。以下是底部的 index.html 脚本(我也必须从 firebasedbunofficial 插入脚本),如 index.html
所示
index.html bottom script
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-database.js"></script>
<script src="https://api.daytonsquareroots.org/firebasedatabaseweb/v0.0.2/app.js" defer></script>
<!-- TODO: Add SDKs for Firebase products that you want to use
https://firebase.google.com/docs/web/setup#available-libraries -->
<!-- Initialize Firebase -->
<script>
var firebaseConfig = {
apiKey: "...",
authDomain: "...",
databaseURL: "...",
projected: "...",
storageBucket: "...",
messagingSenderId: "...",
appId: "...",
measurementId: "G-...",
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
</script>
</body>
</html>
在 flutter 方面,您需要添加以下包。
flutter pub add firebase_db_web_unofficial
并执行以下代码
.
.
.
.
import 'package:firebase_db_web_unofficial/firebasedbwebunofficial.dart';
.
.
.
FirebaseApp app = await Firebase.initializeApp();
.
.
.
FirebaseDatabaseWeb.instance
.reference()
.child("Users")
.child("userid")
.set({
"name": "shahid",
"email": "shahid@gmail.com",
"password": "this will work"
});
.
.
.
.
.
今天刚刚合并到 master 中:
好消息!官方包 firebase_database 现在原生支持 flutter web,我们不需要再经历这些麻烦了:D
我正在尝试让我的 flutter 应用程序在浏览器中运行,这取决于 firebase_database。实际上并没有关于如何执行此操作的任何文档,但我根据 firebase_core 和 firebase_auth 文档做了一些假设:
https://github.com/FirebaseExtended/flutterfire/tree/master/packages/firebase_core/firebase_core_web
https://github.com/FirebaseExtended/flutterfire/tree/master/packages/firebase_auth/firebase_auth_web
我的应用程序正在 iOS 和 android 上运行,但我无法让数据库在 flutter web 中运行。
我已经设置了 index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flutter WebRTC Demo</title>
</head>
<body>
<script src="https://www.gstatic.com/firebasejs/7.6.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.6.1/firebase-database.js"></script>
<script>
const firebaseConfig = {
apiKey: '...',
authDomain: '...',
databaseURL: '...',
projectId: '...',
storageBucket: '...',
messagingSenderId: '...',
appId: '...'
};
firebase.initializeApp(firebaseConfig);
</script>
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
但是,当我尝试使用 firebase 数据库时,我在日志中收到错误消息:
MissingPluginException(No implementation found for method DatabaseReference#set on channel plugins.flutter.io/firebase_database)
package:dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 196:49 throw_
package:flutter/src/services/platform_channel.dart 319:7 invokeMethod
package:dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 47:50 onValue
package:dart-sdk/lib/async/zone.dart 1381:54 runUnary
package:dart-sdk/lib/async/future_impl.dart 139:18 handleValue
package:dart-sdk/lib/async/future_impl.dart 680:44 handleValueCallback
package:dart-sdk/lib/async/future_impl.dart 709:32 _propagateToListeners
package:dart-sdk/lib/async/future_impl.dart 524:5 [_completeWithValue]
package:dart-sdk/lib/async/future_impl.dart 554:7 callback
package:dart-sdk/lib/async/schedule_microtask.dart 43:11 _microtaskLoop
package:dart-sdk/lib/async/schedule_microtask.dart 52:5 _startMicrotaskLoop
package:dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 168:15 <fn>
有什么方法可以让实时数据库在我的网络版 Flutter 应用程序中运行?
FlutterFire 插件最初是为 iOS 和 Android 的原生移动应用程序而构建的。目前正在将对 Web 平台的支持添加到插件中,但要涵盖所有 Firebase 产品还需要一些时间。
您可以在 Github 存储库的 available FlutterFire plugins 列表中检查当前哪些模块与 Flutter for web 兼容。
要在 Flutter for web 的其他功能上使用 Firebase,请使用 firebase-dart
plugin。这意味着您需要为 Web 和移动设备编写单独的代码,但您可以仅在应用的一小部分中隔离差异。
2021 年更新 现在支持对 firebase 数据库的 Web 支持。参见 PR here.
在the main README in the flutterfire github中,有一个“Web?”用于记录哪些插件已准备好用于网络的列。
目前,Flutter Web 应用仅支持 firebase_core
、firebase_auth
、cloud_firestore
和 firebase_functions
。
正如@Frank van Puffelen 提到的,要在 flutter web 中使用 firebase 的全部功能,请使用 firebase-dart 包装器库。
还有一个 Flutter Web Plugins Project Board 显示路线图上有哪些 flutter 插件,以及它们处于哪个开发阶段。在本次编辑时,firebase_storage
是网络路线图上的下一个插件。
pre flutter 2.0解决方案。
在这个问题上经过几天的努力,并且由于评论中几乎没有未解决的问题,我决定 post 一个完整的、长长的答案,以帮助像我一样刚开始的人。
这就是我实现这两个不同包的方式。
当我使用 flutter_bloc
进行状态管理时,我基本上必须像对用户位置所做的那样使存储库平台依赖。
为了实现它,我使用了 stub/abstract class/ web implementation/ device implementation 模式。因此,在我集团的存储库中,我只是调用抽象 class 方法,这些方法将使用适当的包映射到适当的平台实现 class。一开始看起来有点乱,但一旦掌握了这个概念就很容易了,但是 Thera 是一些在开始使用模式时可能会掉入的陷阱。
对于设备实现,使用 flutter_auth
包,而对于 Web 实现,使用 flutter
包,为了简单起见,我制作了一个单例。现在,单例 return 是初始化的 firebase App
,可让您访问所有服务.. auth()
、database()
、firestore()`、remoteconfig()...
无论您需要访问任何 firebase 服务,只需实例化 Firebase 并使用这些服务即可。
App firebase = FirebaseWeb.instance.app;
...
await firebase.auth().signInWithCredential(credential);
return firebase.auth().currentUser;
下面是我用于授权的所有代码,但很容易适应不同的 firebase 服务:
存根:
这只是为了持有一个 (getter) 方法,该方法在抽象 class 工厂方法(我称之为切换器)中得到 returned,并允许有条件的导入抽象 class 到正确的实现 class.
import 'package:firebaseblocwebstub/platform_user_repository/platform_user_repository_switcher.dart';
UserRepositorySwitcher getUserRepository() {
print('user_repository_stub called');
}
摘要class(切换台):
在这里导入存根,以便能够有条件地导入正确的实现 class。 return 中的存根 (getter) 方法在 class 工厂方法中编辑。 在这个class中你需要声明所有你需要使用的方法。这里 returns 是动态的,因为包特定 returns 将在平台实现中 classes。 注意条件导入中的拼写错误和正确的文件路径,因为没有自动检查。我花了很多时间才找到它哈哈。。
import 'package:firebaseblocwebstub/platform_user_repository/platform_user_repository_stub.dart'
if (dart.library.io) 'package:firebaseblocwebstub/platform_user_repository/platform_user_repository_device.dart'
if (dart.library.js) 'package:firebaseblocwebstub/platform_user_repository/platform_user_repository_web.dart';
abstract class UserRepositorySwitcher {
Future<dynamic> signInWithGoogle() async {
print('UserREpository switcher signInWithGoogle() called');
}
Future<void> signInWithCredential({String email, String password}) {}
Future<void> signUp({String email, String password}) {}
Future<void> signOut() async {}
Future<bool> isSignedIn() async {}
Future<dynamic> getUser() async {}
factory UserRepositorySwitcher() => getUserRepository();
}
设备实现class:
必须实现抽象 class 才能掌握并实现具有特定(flutter_auth
在本例中)方法和类型的方法。在这里,您还必须在 class 范围之外声明存根中的相同方法,即 return 的设备实现 class(参见底部代码)。
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebaseblocwebstub/authentication_bloc/app_user.dart';
import 'package:firebaseblocwebstub/platform_user_repository/platform_user_repository_switcher.dart';
import 'package:google_sign_in/google_sign_in.dart';
class UserRepositoryDevice implements UserRepositorySwitcher {
final FirebaseAuth _firebaseAuth;
final GoogleSignIn _googleSignIn;
UserRepositoryDevice({FirebaseAuth firebaseAuth, GoogleSignIn googleSignIn})
: _firebaseAuth = firebaseAuth ?? FirebaseAuth.instance,
_googleSignIn = googleSignIn ?? GoogleSignIn();
Future<FirebaseUser> signInWithGoogle() async {
print('signInWithGoogle() from device started');
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
print('GoogleUser is : $googleUser');
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final AuthCredential credential = await GoogleAuthProvider.getCredential(
idToken: googleAuth.idToken, accessToken: googleAuth.accessToken);
await _firebaseAuth.signInWithCredential(credential);
return _firebaseAuth.currentUser();
}
Future<void> signInWithCredential({String email, String password}) {
return _firebaseAuth.signInWithEmailAndPassword(
email: email, password: password);
}
Future<void> signUp({String email, String password}) {
return _firebaseAuth.createUserWithEmailAndPassword(
email: email, password: password);
}
Future<void> signOut() async {
return Future.wait([
_firebaseAuth.signOut(),
_googleSignIn.signOut(),
]);
}
Future<bool> isSignedIn() async {
final currentUser = _firebaseAuth.currentUser();
return currentUser != null;
}
Future<FixitUser> getUser() async {
String displayName = (await _firebaseAuth.currentUser()).displayName;
String email = (await _firebaseAuth.currentUser()).email;
String uid = (await _firebaseAuth.currentUser()).uid;
String photoUrl = (await _firebaseAuth.currentUser()).photoUrl;
String phoneNumber = (await _firebaseAuth.currentUser()).phoneNumber;
FixitUser user = FixitUser(
// fixitUser
name: displayName ?? '',
email: email,
phoneNumber: phoneNumber ?? '',
uid: uid,
photoUrl: photoUrl ?? '');
return (user);
}
}
UserRepositorySwitcher getUserRepository() => UserRepositoryDevice();
现在终于可以上网了..
firebase 单例:
为了方便地使用 firebase
包,我决定将其设为单例。
在这里你可以 return 一个 Future<App>
实例但是你必须 .then
一切..或者 return 直接 App
..我选择了这种方式..更清洁和更快的实施。
这样你就不必在你的 index.html
文件中初始化 firebase,否则你会得到一个错误,因为它已经初始化了。在这里初始化 firebase 也让你的密钥不暴露..
import 'dart:async';
import 'package:firebase/firebase.dart';
class FirebaseWeb {
// Singleton instance
static final FirebaseWeb _singleton = FirebaseWeb._();
// Singleton accessor
static FirebaseWeb get instance => _singleton;
// A private constructor. Allows us to create instances of AppDatabase
// only from within the AppDatabase class itself.
FirebaseWeb._();
static App _app;
// Database object accessor
App get app {
print('firebase get app called ');
print('_app is $_app');
if (_app != null) {
return _app;
} else {
print('initialize app');
_app = initializeApp(
apiKey: "your key",
authDomain: "your key",
databaseURL: "your key",
projectId: "your key",
storageBucket: "your key",
messagingSenderId: "your key",
appId: "your key");
print('initialized app is $_app'); // await _initializeApp();
return _app;
}
}
}
网络实施:
在这里你只是使用单例实例化Firebase,并实现抽象class方法,使用它的服务和方法..我在这里使用auth()
。
您可以看到(注释掉的部分)如果 return a Future<App>
在单身人士中,实施会更加冗长..
这里存根 getter 方法将 return 这个 class ..(检查底部)
import 'dart:async';
import 'package:firebase/firebase.dart';
import 'package:firebaseblocwebstub/authentication_bloc/app_user.dart';
import 'package:firebaseblocwebstub/firebase_singleton.dart';
import 'package:firebaseblocwebstub/platform_user_repository/platform_user_repository_switcher.dart';
import 'package:google_sign_in/google_sign_in.dart';
class UserRepositoryWeb implements UserRepositorySwitcher {
App firebase = FirebaseWeb.instance.app;
final GoogleSignIn _googleSignIn = GoogleSignIn();
Future<User> signInWithGoogle() async {
print('signInWithGoogle() started');
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
print('GoogleUser is : $googleUser');
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final OAuthCredential credential = await GoogleAuthProvider.credential(
googleAuth.idToken, googleAuth.accessToken);
// singleton retunrning Future<App>
// await firebase.then((firebase) {
// firebase.auth().signInWithCredential(credential);
// return;
// });
// return firebase.then((firebase) {
// return firebase.auth().currentUser;
// });
await firebase.auth().signInWithCredential(credential);
return firebase.auth().currentUser;
}
Future<void> signInWithCredential({String email, String password}) {
return firebase.auth().signInWithEmailAndPassword(email, password);
// singleton retunrning Future<App>
// return firebase.then((firebase) {
// return firebase.auth().signInWithEmailAndPassword(email, password);
// });
}
Future<void> signUp({String email, String password}) {
return firebase.auth().createUserWithEmailAndPassword(email, password);
// singleton retunrning Future<App>
// return firebase.then((firebase) {
// return firebase.auth().createUserWithEmailAndPassword(email, password);
// });
}
Future<void> signOut() async {
return Future.wait([
firebase.auth().signOut(),
// singleton retunrning Future<App>
// firebase.then((firebase) {
// firebase.auth().signOut();
// }),
_googleSignIn.signOut(),
]);
}
Future<bool> isSignedIn() async {
final currentUser = firebase.auth().currentUser;
return currentUser != null;
// singleton retunrning Future<App>
// User firebaseUser = firebase.then((firebase) {
// return firebase.auth().currentUser;
// }) as User;
// return firebaseUser != null;
}
Future<FixitUser> getUser() async {
// singleton retunrning Future<App>
// User firebaseUser = firebase.then((firebase) {
// return firebase.auth().currentUser;
// }) as User;
//
// FixitUser user = FixitUser(
// name: firebaseUser.displayName ?? '',
// email: firebaseUser.email,
// phoneNumber: firebaseUser.phoneNumber ?? '',
// uid: firebaseUser.uid,
// photoUrl: firebaseUser.photoURL ?? '');
// return (user);
// }
String displayName = (firebase.auth().currentUser).displayName;
String email = (firebase.auth().currentUser).email;
String uid = (firebase.auth().currentUser).uid;
String photoUrl = (firebase.auth().currentUser).photoURL;
String phoneNumber = (firebase.auth().currentUser).phoneNumber;
FixitUser user = FixitUser(
name: displayName ?? '',
email: email,
phoneNumber: phoneNumber ?? '',
uid: uid,
photoUrl: photoUrl ?? '');
return (user);
}
}
UserRepositorySwitcher getUserRepository() => UserRepositoryWeb();
我遇到了同样的问题,并决定采取一些措施。所以我继续做了 https://pub.dev/packages/firebase_db_web_unofficial 。它很容易设置并集成到您的代码中。
万一有人还在寻找 flutter web 实时数据库问题的另一种解决方法,我有一个简单而直接的解决方案...
我做了一些挖掘,if(kIsWeb) 似乎有效。
第一
为 android|ios 添加 firebase package that supports Realtime database for web and firebase_databe package。
第二
初始化 firebase
void main() async {
await Firebase.initializeApp();
}
第三
导入如下
import 'package:firebase_database/firebase_database.dart';
import 'package:firebase/firebase.dart' as fb;
第四
关于如何读取 android-ios/web 的实时数据库数据的示例。 在这里,我将图像添加到轮播滑块。
List<SliderImage> sliderList = [];
void getSliderData() async {
FirebaseDatabase firebaseDatabaseference = FirebaseDatabase.instance;
firebaseDatabaseference.setPersistenceEnabled(true);
firebaseDatabaseference.setPersistenceCacheSizeBytes(10000000);
//for web
if (kIsWeb) {
fb.DatabaseReference databaseRef = fb.database().ref("Slider");
await databaseRef.onValue.listen((event) {
fb.DataSnapshot dataSnapshot = event.snapshot;
sliderList.clear();
this.setState(() {
for (var value in dataSnapshot.val()) {
sliderList.add(new SliderImage.fromJson(value));
}
});
});
// for android and ios
} else {
DatabaseReference databaseReference = firebaseDatabaseference.reference();
databaseReference.keepSynced(true);
await databaseReference
.child("Slider")
.once()
.then((DataSnapshot dataSnapshot) {
sliderList.clear();
this.setState(() {
for (var value in dataSnapshot.value) {
sliderList.add(new SliderImage.fromJson(value));
}
});
});
}
}
轮播滑块
CarouselSlider.builder(
itemCount: sliderList.length,
options: CarouselOptions(
autoPlay: true,
aspectRatio: 16 / 9,
viewportFraction: 1,
enlargeCenterPage: false,
enlargeStrategy: CenterPageEnlargeStrategy.height,
),
itemBuilder: (context, index, realIdx) {
return Container(
child: Center(
child: Image.network(sliderList[index].image, loadingBuilder:
(BuildContext context, Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
valueColor:
new AlwaysStoppedAnimation<Color>(Colors.black54),
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes
: null,
),
);
}, fit: BoxFit.cover, width: 1000)),
);
},
));
SliderImage 模型class
class SliderImage {
String image;
SliderImage(this.image);
SliderImage.fromJson(var value) {
this.image = value['image'];
}
}
类似的方法可以应用于 Listview.builder。 干杯
存在一个包https://pub.dev/packages/firebase_db_web_unofficial/install(非官方 Firebase 数据库集成) 这对我有用。以下是底部的 index.html 脚本(我也必须从 firebasedbunofficial 插入脚本),如 index.html
所示index.html bottom script
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-database.js"></script>
<script src="https://api.daytonsquareroots.org/firebasedatabaseweb/v0.0.2/app.js" defer></script>
<!-- TODO: Add SDKs for Firebase products that you want to use
https://firebase.google.com/docs/web/setup#available-libraries -->
<!-- Initialize Firebase -->
<script>
var firebaseConfig = {
apiKey: "...",
authDomain: "...",
databaseURL: "...",
projected: "...",
storageBucket: "...",
messagingSenderId: "...",
appId: "...",
measurementId: "G-...",
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
</script>
</body>
</html>
在 flutter 方面,您需要添加以下包。
flutter pub add firebase_db_web_unofficial
并执行以下代码
.
.
.
.
import 'package:firebase_db_web_unofficial/firebasedbwebunofficial.dart';
.
.
.
FirebaseApp app = await Firebase.initializeApp();
.
.
.
FirebaseDatabaseWeb.instance
.reference()
.child("Users")
.child("userid")
.set({
"name": "shahid",
"email": "shahid@gmail.com",
"password": "this will work"
});
.
.
.
.
.
今天刚刚合并到 master 中:
好消息!官方包 firebase_database 现在原生支持 flutter web,我们不需要再经历这些麻烦了:D