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);
}
最后附上Github地址: github.com/joker-fu/fl…
如果你看到了这里,觉得文章写得不错就给个赞呗!欢迎大家评论讨论!如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足,定期免费分享技术干货。喜欢的小伙伴可以关注一下哦。谢谢!