类似于 JavaScript 中的 localStorage API,Flutter 使用 shared_preferences 插件持久保存数据。
如果用户关闭 app, 再次打开时,自动通过 SharedPreferences 读取上次登录后保存的数据,如果认证 token 依然有效,则使用存储的数据重设相应的数据,从而跳过手动输入帐号密码进行登录这一步。
1. 修改 pubspec.yaml 并保存
增加 shared_preferences 这一项,版本一直在更新。 shared_preferences 网页:https://pub.dev/packages/shared_preferences , 不过 pub.dev经常打不开,原因不明。
dependencies:
flutter:
sdk: flutter
provider: ^4.0.0
intl: ^0.15.8
http: ^0.12.0+2
shared_preferences: ^0.5.3+1
2. 登录成功后,保存从服务器获取的认证相关数据
Future<void> _authenticate(
String email, String password, String urlSegment) async {
final url =
'https://identitytoolkit.googleapis.com/v1/accounts:${urlSegment}?key=somekey_from_firebase_xyz';
try {
final response = await http.post(
url,
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: json.encode(
{'email': email, 'password': password, 'returnSecureToken': true},
),
);
final responseData = json.decode(response.body);
if (responseData['error'] != null) {
throw HttpException(responseData['error']['message']);
}
_token = responseData['idToken'];
_userId = responseData['localId'];
_expiryDate = DateTime.now().add(Duration(
seconds: int.parse(responseData['expiresIn']),
));
_autoLogout();
notifyListeners();
// 持久保存数据
// =================================================
final prefs = await SharedPreferences.getInstance();
final userData = json.encode({
'token': _token,
'userId': _userId,
'expiryDate': _expiryDate.toIso8601String(),
});
prefs.setString('userData', userData);
// =================================================
} catch (error) {
throw error;
}
}
3. 自动登录函数 tryAutoLogin() 代码
Future<bool> tryAutoLogin() async {
final prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('userData')) {
return false;
}
final extractedUserData =
json.decode(prefs.getString('userData')) as Map<String, Object>;
final expiryDate = DateTime.parse(extractedUserData['expiryDate']);
if (expiryDate.isBefore(DateTime.now())) {
return false;
}
_token = extractedUserData['token'];
_userId = extractedUserData['userId'];
_expiryDate = expiryDate;
notifyListeners();
_autoLogout();
return true;
}
4. 在 main.dart 中调用自动登录函数
home: auth.isAuth
? ProductsOverviewScreen()
: FutureBuilder(
future: auth.tryAutoLogin(),
builder: (ctx, authResultSnapShot) =>
authResultSnapShot.connectionState ==
ConnectionState.waiting
? SplashScreen()
: AuthScreen(),
),
5. 在退出登录函数中增加清空数据这一步
退出登录时,步骤 2 中保存的数据要清除,有两种清除数据的方法:
prefs.remove('userData'); 删除当前app 写入的 userData key value 对prefs.clear(); // 全部删除,因为也可能包括别的app的数据,所以不要随意使用。
Future<void> logout() async {
_token = null;
_userId = null;
_expiryDate = null;
if (_authTimer != null) {
_authTimer.cancel();
_authTimer = null;
}
notifyListeners();
final prefs = await SharedPreferences.getInstance();
prefs.clear();
}
|