预flutter 2.0解决方案。
在这个主题上挣扎了几天之后,由于 cmets 中几乎没有未回答的问题,我决定发布一个完整的、很长的答案,以帮助像我一样刚起步的人们。
这就是我实现两个不同包的方式。
当我使用flutter_bloc 进行状态管理时,我基本上必须像对用户位置所做的那样使存储库平台依赖。
为了实现它,我使用了存根/抽象类/Web 实现/设备实现模式。因此,在我的 bloc 存储库中,我只需调用抽象类方法,这些方法将使用适当的包映射到适当的平台实现类。一开始看起来有点混乱,但是一旦掌握了这个概念就很容易了,但是 Thera 是一个在开始使用该模式时可能会落入的陷阱。
对于设备实现使用flutter_auth 包,而对于Web 实现使用flutter 包,为了方便起见,我做了一个单例。现在单例返回初始化的 firebase App,让您可以访问所有服务。auth()、database()、firestore()`、remoteconfig()...
无论您需要在何处访问任何 Firebase 服务,只需实例化 Firebase 并使用这些服务。
App firebase = FirebaseWeb.instance.app;
...
await firebase.auth().signInWithCredential(credential);
return firebase.auth().currentUser;
这是我用于授权的所有代码,但很容易适应不同的 firebase 服务:
存根:
这只是为了保存在抽象类工厂方法(我称之为 switcher)中返回的(getter)方法,并允许在抽象类中将条件导入到正确的实现类中。
import 'package:firebaseblocwebstub/platform_user_repository/platform_user_repository_switcher.dart';
UserRepositorySwitcher getUserRepository() {
print('user_repository_stub called');
}
抽象类(切换器):
在这里您导入存根以便能够有条件地导入正确的实现类。类工厂方法中返回的存根(getter)方法。
在这个类中,您需要声明您需要使用的所有方法。这里的返回是动态的,因为包特定的返回将在平台实现类中。
注意条件导入中的拼写错误和正确的文件路径,因为没有自动检查..花了我很多钱才找到它哈哈..
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();
}
设备实现类:
必须实现抽象类以获取并使用特定(在本例中为flutter_auth)方法和类型来实现它的方法。在这里,您还必须在类范围之外声明存根中的相同方法,该方法返回设备实现类(见底部代码)。
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 包,我决定将其设为单例。
在这里,您可以返回 Future<App> 实例,但您必须返回 .then 一切......或者直接返回 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,并实现抽象类方法,使用它的服务和方法。我在这里使用auth()。
如果在单例中返回Future<App>,您可以看到(注释掉的部分)实现的详细程度。
这里的存根 getter 方法将返回这个类..(检查底部)
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();