firebase - 在 Flutter 中使用电话身份验证时无法更新 firebase 数据库中的数据
问题描述
我正在尝试将用户注册表单数据添加到 firebase 数据库。但是很难有效地做到这一点。我是新来的。我通过电话号码成功注册了用户,但无法添加相应的详细信息。我尝试使用 getter 和 setter,但它显然不起作用。我不知道这样做的理想方法是什么。我试着用谷歌搜索它,但没有得到任何帮助。我只是卡住了。我会很感激的。
这是我的代码
import 'package:firebase_auth/firebase_auth.dart';
import 'package:home_crisp/models/user.dart';
import 'package:home_crisp/services/auth.dart';
import 'package:provider/provider.dart';
class ChefRegisterScreen extends StatefulWidget {
ChefRegisterScreen();
@override
_ChefRegisterScreenState createState() => _ChefRegisterScreenState();
}
class _ChefRegisterScreenState extends State<ChefRegisterScreen> {
final AuthService _auth = AuthService();
bool loading = false;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
String chefName = "", phoneNo = "";
String smsCode, verificationID;
String phnCode = "+92";
DateTime dateOfBirth;
bool codeSent = false;
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
final deviceSize = MediaQuery.of(context).size;
return loading
? Loading()
: Material(
type: MaterialType.card,
color: Color(0xffD4EBD3),
child: Stack(
children: <Widget>[
// --> Here is the code of getting "chefname, phone and dateOfBirth" and setting them using setState() method
//
// >>>>>>>>> Textfeild for getting OTP code
//
codeSent
? // Here is the code for textfeild which get OTP code
: Container(),
// ------------------------------------------------------ F I N I S H B U T T O N
FlatButton(
onPressed: () async {
if (user != null) {
print(
"TheRe IS uSer already logging in so signing out logging in new user");
AuthService().signOut();
}
if (codeSent) {
AuthService().signInWithOTP(smsCode, verificationID);
} else {
verifyPhone(phoneNo);
}
// ----> Here I tried to several methods to sent register form data to the seperate class named
// ----> "user.dart" from where I tried to extract that info in "auth" signinWithPhoneNumber method.
// ----> I first tried to send the info via constructor
ChefData(chefName: chefName,
chefPhNo: phoneNo,
chefDateOfBirth: dateOfBirth);
});
// ----> Then I tried "setter" but in vain
// ChefData().setChefName(chefName);
// ChefData().setChefPhNo(phoneNo);
// ChefData().setChefDateOfBirth(dateOfBirth);
child: ClipRRect(
child: Text(
"FINISH",
style: TextStyle(
color: Colors.white,
fontFamily: 'Montserrat',
fontSize: 20,
),
),
),
),
],
),
),
)
],
),
),
],
),
);
}
//
// >>>>>>>>> S I G N I N W I T H P H O M E N U M B E R P R O C E S S
//
Future<void> verifyPhone(phoneNo) async {
final PhoneVerificationCompleted verificationComplete =
(AuthCredential authResult) {
print('1. Auto retrieving verification code');
}
};
final PhoneCodeAutoRetrievalTimeout autoRetrieve = (String verID) {
verificationID = verID;
print("\n2. Auto retrieval time out");
};
final PhoneCodeSent smsCodeSent =
(String verID, [int forceCodeResend]) async {
verificationID = verID;
setState(() {
this.codeSent = true;
});
print("\n 3. Code Sent to " + phoneNo);
};
final PhoneVerificationFailed verificationFailed =
(AuthException authException) {
print('${AuthException(smsCode, "message")}');
if (authException.message.contains('not authorized'))
print('App not authroized');
else if (authException.message.contains('Network'))
print('Please check your internet connection and try again');
else
print('Something has gone wrong, please try later ' +
authException.message);
};
await FirebaseAuth.instance
.verifyPhoneNumber(
phoneNumber: phoneNo,
timeout: Duration(seconds: 50),
verificationCompleted: verificationComplete,
verificationFailed: verificationFailed,
codeSent: smsCodeSent,
codeAutoRetrievalTimeout: autoRetrieve,
)
.then((value) {})
.catchError((error) {
print(error.toString());
});
}
}
这是“auth.dart”类
import 'package:firebase_auth/firebase_auth.dart';
import 'package:home_crisp/models/user.dart';
import 'package:home_crisp/services/database.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// create user obj based on FirebaseUser
User _userFormFirebaseUser(FirebaseUser user) {
return user != null ? User(uid: user.uid) : null;
}
// auth change user stream
Stream<User> get user {
return _auth.onAuthStateChanged.map(_userFormFirebaseUser);
}
// ------------------------------------------------------ S I G N I N W I T H P H O M E N U M B E R
signInWithPhoneNumber(AuthCredential authCreds) async {
try {
AuthResult result = await _auth.signInWithCredential(authCreds);
FirebaseUser user = result.user;
if (user != null) {
print('AUTHENTICATONI SUCCESSFULL. Id: ' + user.uid);
// ---->> Now here I tried create a new document for the chef with the uid by extracting the chef data // // ---->> from "user.dart" class
// ---->> I used getter method. I know there is going to be some better way to get that data
await DatabaseService(uid: user.uid).updateChefData(
ChefData().getChefName(),
ChefData().getChefPhNo(),
ChefData().getChefDateOfBirth());
return _userFormFirebaseUser(user);
} else {
print('Invalid code/invalid authentication');
}
} catch (e) {
print(e.toString());
return null;
}
}
signInWithOTP(smsCode, verId) {
AuthCredential authCreds = PhoneAuthProvider.getCredential(
verificationId: verId, smsCode: smsCode);
signInWithPhoneNumber(authCreds);
}
}
这是包含“ChefData”类的“user.dart”文件,充当“auth.dart”和“chefRegisterScreen.dart”之间的中介
class User {
final String uid;
User({this.uid});
}
class ChefData {
String chefId;
String chefName;
String chefPhNo;
DateTime chefDateOfBirth;
ChefData({this.chefId, this.chefName, this.chefPhNo, this.chefDateOfBirth});
// void setChefId(String _chefId) {
// this.chefId = _chefId;
// }
// void setChefName(String _chefName) {
// this.chefName = _chefName;
// }
// void setChefPhNo(String _chefPhNo) {
// this.chefPhNo = chefPhNo;
// }
// DateTime setChefDateOfBirth(DateTime _chefDateOfBirth) {
// this.chefDateOfBirth = _chefDateOfBirth;
// }
String getChefId() {
return chefId;
}
String getChefName() {
return chefName;
}
String getChefPhNo() {
return chefPhNo;
}
DateTime getChefDateOfBirth() {
return chefDateOfBirth;
}
}
解决方案
我遇到了类似的问题,我在注册期间使用共享首选项存储用户详细信息,然后在电话身份验证成功后上传详细信息。Shared preferences 是一个 Flutter 插件,可以让你以键值对的形式存储简单的数据。这是有关共享首选项及其使用方法的更详细的文章。
在您的情况下,我建议您为共享偏好创建一个类。
class SharedPreference{
static Future<String> storeChefData(ChefData chefData) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String storeUser = userToJson(chefData);
await prefs.setString('user', storeUser);
return storeUser;
}
static Future<ChefData> getChefData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
if (prefs.getString('user') != null) {
ChefData chefData = userFromJson(prefs.getString('user'));
return chefData;
} else {
return null;
}
}
}
该storeChefData()
功能用于在注册期间存储用户详细信息。该getChefData()
功能用于检索用户详细信息,以便在身份验证后上传到数据库。
在您的 user.dart 文件中,您将需要添加将 chefData 转换为 jsonData 以进行存储和从 jsonData 转换为 ChefData 以进行检索的函数,如上述函数所示。
ChefData userFromJson(String str) {
final jsonData = json.decode(str);
return ChefData.fromJson(jsonData);
}
String userToJson(ChefData data) {
final dyn = data.toJson();
return json.encode(dyn);
}
class ChefData{
final String chefName;
final String chefPhNo;
final DateTime chefDateOfBirth;
ChefData({this.chefName,this.chefPhNo,this.chefDateOfBirth});
factory ChefData.fromJson(Map<String, dynamic> json) => ChefData(
chefName: json["chefName"],
chefPhNo: json["chefPhNo"]
chefDateOfBirth: json["chefDateOfBirth"]
);
Map<String, dynamic> toJson() => {
"chefName": chefName,
"chefPhNo": chefPhNo
"chefDateOfBirth": chefDateOfBirth
};
}
在你的ChefRegistrationScreen
你将添加:
await SharedPreference.storeChefData(ChefData(chefName: chefName,chefPhNo: phoneNo,chefDateOfBirth: dateOfBirth));
在您想要插入 chefData 的位置。
然后在您的auth.dart
文件中添加:
ChefData getChefData = await SharedPreference.getChefData();
await DatabaseService(uid: user.uid).updateUserData(getChefData);
为了更新您的数据库。
推荐阅读
- laravel - When moving a Laravel repo to a new development environment, how can I get the tests running again?
- angular - 检测角循环中的最后两个元素
- javascript - 如何在 html 和 Javascript 中为给定的下拉字段组从其余下拉列表中禁用选定的下拉列表项
- javascript - 为什么 Angular 在下面的简单代码中生成 3 而不是 1?
- python - 无法使用 dict 类型作为字段条目将数据添加到 InfluxDB
- python - Python字符串替换截断新字符串
- ruby-on-rails - 如果表单本身从未持久化,您能否使表单对象适用于新操作和编辑操作?
- eclipse - 将 ECore UML 转换为 XText
- html - 如何使弹性容器的元素向左溢出?
- sql-server - 在常规 SQL 视图中使用的 SQL Server 表上创建强制执行