直接開始幹,沒有為什麼~
基於上一篇實現一個登陸頁,使用 connectivity 、 shared_preferences 、 Dio 實現一個完整的登入操作,包含網路連線檢測、請求、資料儲存等~
當然,登入介面並不是我實現,是由玩Android友情提供。首先看效果:
外掛簡介
connectivity
用於發現網路連線並進行相應配置。它可以區分蜂窩連線和WiFi連線,iOS和Android適用。
注意 在Android上,這不保證可以連線到Internet
shared_preferences
包裝NSUserDefaults(在iOS上)和SharedPreferences(在Android上),為簡單資料提供持久儲存。
Dio
dio是一個強大的Dart Http請求庫,支援Restful API、FormData、攔截器、請求取消、Cookie管理、檔案上傳/下載、超時、自定義介面卡等。
依賴配置
在 pubspec.yaml 中新增外掛依賴,下面外掛版本是文章編寫時的最新版。
dependencies:
# https://github.com/flutterchina/dio
dio: ^3.0.3
# https://github.com/flutter/plugins/tree/master/packages/connectivity
connectivity: ^0.4.4
# https://github.com/flutter/plugins/tree/master/packages/shared_preferences
shared_preferences: ^0.5.3+4
複製程式碼
登入操作
今天的所有操作都基於上一篇實現一個登陸頁,有必要的可以先跳轉過去檢視。
使用 Dio 構建登入請求
登入按鈕的 onPressed 回撥中,替換為 _doLogin() ,實現如下:
Future _doLogin() async {
Dio dio = Dio();
dio.options..baseUrl = 'https://www.wanandroid.com/';
// 新增攔截器
dio.interceptors
..add(LogInterceptor(
requestHeader: true,
requestBody: true,
responseHeader: true,
responseBody: true,
));
// 發起請求
Response response = await dio.post('user/login',
data: FormData.fromMap({
"username": _accountController.text.trim(),
"password": _pwdController.text.trim(),
}));
if (response.statusCode == 200) {
UserEntity user = UserEntity.fromJson(response.data);
if (user.errorCode == 0) {
_showInfoDialog('登入成功');
} else {
_showInfoDialog('登入失敗:${user.errorMsg}');
}
} else {
_showInfoDialog('網路請求異常:${response.statusMessage}');
}
}
複製程式碼
點選登入,賬號密碼正確的情況下,你將看到登入成功!
發起請求前檢測網路
在發起網路請求前,我們一般會檢測網路,有網路就發起,沒網路就算逑... 需要注意這個庫在 Android 上還有個注意事項。
所在在 post 發起之前加上如下程式碼,校驗網路連線檢測:
// 檢測網路連線
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
_showInfoDialog('網路連線異常');
return;
}
複製程式碼
儲存登入結果
一般登入成功後,我們會儲存使用者資訊,以便在後續操作使用到時方便獲取。
所以在確認真正登入成功後,新增如下程式碼儲存使用者資訊:
//登入成功後 儲存資訊
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('user', jsonEncode(user.data));
複製程式碼
connectivity 、shared_preferences 外掛使用相對簡單,就不再廢話了。到這一步如果網路連線正常,且賬號密碼正確,將看到上面第一張圖示效果。否則:
攔截器新增請求頭
登入成功後,接下來需要在所有的請求中加上 token ,當然可能還有一些硬體資訊什麼的。這裡通過新增 Dio 攔截器實現:
// 新增攔截器
dio.interceptors
..add(InterceptorsWrapper(
onRequest: (RequestOptions options) async {
var prefs = await SharedPreferences.getInstance();
var userJson = prefs.getString('user');
if (userJson != null && userJson.isNotEmpty) {
UserData user = UserData.fromJson(jsonDecode(userJson));
options.headers
..addAll({
'userId': user.id ?? '',
'token': user.token ?? '',
});
}
return options;
},
))
複製程式碼
這樣網路請求就會被攔截,新增 userId 和 token ...
請求提示
一般進行網路請求或者耗時操作時,會給使用者一個友好的提示,表示我們沒有卡死。我這裡的處理是封裝了一個 LoadingDialog 的 Widget,使用 showDialog() 彈出,效果如下,具體實現請看程式碼。
結尾
這個登入實踐比較簡單,沒有對請求做統一的封裝,也沒有對異常進行處理。一般都是封裝後統一處理,呼叫的地方簡單很多。
最終 _doLogin 方法中的全部程式碼,
Future _doLogin() async {
Dio dio = Dio();
dio.options..baseUrl = 'https://www.wanandroid.com/';
// 新增攔截器
dio.interceptors
..add(InterceptorsWrapper(
onRequest: (RequestOptions options) async {
var prefs = await SharedPreferences.getInstance();
var userJson = prefs.getString('user');
if (userJson != null && userJson.isNotEmpty) {
UserData user = UserData.fromJson(jsonDecode(userJson));
options.headers
..addAll({
'userId': user.id ?? '',
'token': user.token ?? '',
});
}
return options;
},
))
..add(LogInterceptor(
requestHeader: true,
requestBody: true,
responseHeader: true,
responseBody: true,
));
// 檢測網路連線
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
_showInfoDialog('網路連線異常');
return;
}
LoadingDialog.show(context);
// 發起請求
Response response = await dio.post('user/login',
data: FormData.fromMap({
"username": _accountController.text.trim(),
"password": _pwdController.text.trim(),
}));
if (response.statusCode == 200) {
UserEntity user = UserEntity.fromJson(response.data);
if (user.errorCode == 0) {
//登入成功後 儲存資訊
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('user', jsonEncode(user.data));
_showInfoDialog('登入成功');
} else {
_showInfoDialog('登入失敗:${user.errorMsg}');
}
} else {
_showInfoDialog('網路請求異常:${response.statusMessage}');
}
LoadingDialog.hide(context);
}
複製程式碼