Flutter自帶的網(wǎng)絡(luò)請(qǐng)求引擎HttpClient功能庆捺,但HttpClient本身功能較弱啊研,很多常用功能都不支持者祖。Dio是Flutter的一個(gè)第三方網(wǎng)絡(luò)庫(kù)眶痰,它是一個(gè)強(qiáng)大易用的dart http請(qǐng)求庫(kù)恍飘,支持Restful API榨崩、FormData谴垫、攔截器、請(qǐng)求取消母蛛、Cookie管理翩剪、文件上傳/下載、超時(shí)等彩郊。
Dio使用方法
1.添加依賴:
dependencies:
dio: ^x.x.x // 請(qǐng)使用pub上的最新版本
2.在調(diào)用的文件導(dǎo)入:
import 'package:dio/dio.dart';
3.發(fā)起一個(gè)Post網(wǎng)絡(luò)請(qǐng)求:
Response response = await dio.post(
url ,
data: paramters,
options: opt,
);
url 表示請(qǐng)求的地址前弯;
data:Post提交的參數(shù),key-value的Map類型秫逝;
options參數(shù):網(wǎng)絡(luò)請(qǐng)求頭設(shè)置恕出、其他自定義配置等。
其中Options是一個(gè)配置類:
Options({
String method,
int connectTimeout,
int sendTimeout,
int receiveTimeout,
Iterable<Cookie> cookies,
Map<String, dynamic> extra,
Map<String, dynamic> headers,
ResponseType responseType,
ContentType contentType,
ValidateStatus validateStatus,
bool receiveDataWhenStatusError,
bool followRedirects,
int maxRedirects,
})
通過其內(nèi)部的屬性可以看到违帆,可以設(shè)置
method:Get/Post方式浙巫;
connectTimeout超時(shí)時(shí)間(毫秒單位);
headers就是設(shè)置請(qǐng)求頭刷后。
contentType和responseType可設(shè)置返回的內(nèi)容是xml/json/text-plain等格式的畴。
followRedirects可設(shè)置是否允許重定向。
cookies可以設(shè)置cookies尝胆。
Dart Future
網(wǎng)絡(luò)請(qǐng)求離不開異步機(jī)制丧裁,Dart語(yǔ)法特性對(duì)異步機(jī)制使用了Future機(jī)制。這套機(jī)制和ES6的Promise原理是一樣的含衔。
如果你對(duì)Js的ES6熟悉煎娇,那么你將很容易理解和使用。他們都是協(xié)程抱慌,大致都是采用async/await 機(jī)制逊桦,將一個(gè)異步請(qǐng)求的過程放入一個(gè)協(xié)程里面,將結(jié)果以“同步”的方式返回抑进,注意:不是真正的同步請(qǐng)求强经,實(shí)際上任何異步請(qǐng)求都是天然存在的客觀事實(shí),你無法真正將一個(gè)異步請(qǐng)求改成一個(gè)同步請(qǐng)求寺渗。
回到我們Dart語(yǔ)法中:
像上面的post請(qǐng)求方法匿情,如果一個(gè)方法是異步的,那么該方法在沒有返回結(jié)果前需要等待信殊,dart語(yǔ)法要求在方法前加上“await”標(biāo)識(shí):
await xxxxxx()
那么炬称,響應(yīng)的該語(yǔ)句執(zhí)行的方法返回也必須在結(jié)尾添加異步標(biāo)識(shí)async:
Future xxxxxxx(paramters) async {
await xxxxxx()
}
該方法的放回類型一般為Future類型,以便調(diào)用方使用then()取得結(jié)果涡拘。(注意:返回類型不必一定為Future玲躯,可也是void,那么調(diào)用方就不能使用then()取結(jié)果而已)。
可能很多人不知道Future標(biāo)識(shí)有什么意思跷车,標(biāo)識(shí)Future標(biāo)識(shí)該方法的返回是一個(gè)then()-catchError(e)結(jié)果體棘利,其中then({閉包})里是正確的返回結(jié)果,catchError({閉包})就是異步異常的結(jié)果朽缴。
當(dāng)然善玫,異步的請(qǐng)求也可以不以Future形式返回,我們可以通過自定義閉包結(jié)構(gòu)體返回密强,比如我的網(wǎng)絡(luò)請(qǐng)求返回是2個(gè)callback:
void request (String url,
Map paramters,
Function completeCallback,
Function errorCallback) async {
if (!url.startsWith("http")) {
String baseUrl = "https://www.wowoshenghuo.com";
url = baseUrl + url;
}
String errorMsg = "";
try {
Options opt = await wowoLifeHeaders();
Response response = await dio.post(
url ,
data: paramters,
options: opt,
);
print("網(wǎng)絡(luò)請(qǐng)求狀態(tài)碼:" + response.statusCode.toString());
//處理錯(cuò)誤部分
if (response.statusCode < 200 || response.statusCode > 400) {
errorMsg = "網(wǎng)絡(luò)請(qǐng)求錯(cuò)誤,狀態(tài)碼:" + response.statusCode.toString();
_handError(errorCallback, errorMsg);
return;
}
//網(wǎng)絡(luò)connected
Map<String, dynamic> json;
if (response.data is Map) {
json = response.data;
}else {
json = jsonDecode(response.data);
}
print(json);
//轉(zhuǎn)模型
YWResponse resp = YWResponse.fromJson(json);
if (completeCallback != null) {
completeCallback(resp);
}
} catch(exception) {
_handError(errorCallback, exception.toString());
}
}
void _handError(Function errorCallback, String errorMsg) {
if (errorCallback != null) {
errorCallback(errorMsg);
}
}
}
我的網(wǎng)絡(luò)返回是通過兩個(gè)Function返回的:
completeCallback:網(wǎng)絡(luò)正常的回調(diào)(當(dāng)然業(yè)務(wù)錯(cuò)誤也屬于這種)
errorCallback:網(wǎng)絡(luò)異常茅郎、不通的回調(diào)。
雖然我的網(wǎng)絡(luò)請(qǐng)求是async標(biāo)識(shí)的或渤,由于我自定義了網(wǎng)絡(luò)回調(diào)系冗,所以我僅僅申明void返回即可。
獲取設(shè)備信息和APP包信息
我們經(jīng)常需要獲取手機(jī)設(shè)備諸如系統(tǒng)版本劳坑,平臺(tái)信息以及APP包名稱毕谴,APP版本等信息成畦。這些Flutter有一些第三方插件提供了這方面的api.
device_info
device_info 插件同樣需要安裝然后import
初始化:
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
deviceInfo為我們提供了iosInfo和androidInfo;
那么我們首先需要自己判斷當(dāng)前設(shè)備是哪個(gè)平臺(tái):
if (Platform.isIOS) {
IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
device["sysVersion"] = iosInfo.systemVersion;
device["model"] = iosInfo.localizedModel;
device["imei"] = iosInfo.identifierForVendor;
device["brand"] = "iPhone";
}else {
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
device["sysVersion"] = androidInfo.version.baseOS;
device["model"] = androidInfo.model;
device["imei"] = androidInfo.id;
device["brand"] = androidInfo.brand;
}
然后通過iosInfo或者AndroidInfo即可獲取system距芬、model等設(shè)備信息。
需要注意的是:deviceInfo獲取設(shè)備信息的方法是個(gè)異步的
需要await/async循帐。
package_info
package_info是讀取APP工程的信息的框仔,如APP名稱、APP唯一標(biāo)識(shí)拄养、APP迭代版本號(hào)等离斩。
同樣,和device_info一樣瘪匿,這個(gè)方法也是異步獲取pakage信息:
Future<PackageInfo> pakageInfo() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
return packageInfo;
}
最后根據(jù)我們公司需要將設(shè)備信息作為header的獲取方法全部完成了跛梗,貼一下我的header代碼:
Future<Options> wowoLifeHeaders() async {
if (store == null) {
store = await storage();
}
if (deviceMap == null) {
deviceMap = await deviceSystemVersion();
}
if (pakage == null) {
pakage = await pakageInfo();
}
String uToken = "-1";
if (store != null && store.getString("user_token") != null) {
uToken = store.getString("user_token");
}
Options options = Options(
headers: {
HttpHeaders.contentTypeHeader:"application/json;charset=UTF-8",
"source" : Platform.isIOS ? "2" : "1",
"sys_version" : deviceMap["sysVersion"],
"model" : deviceMap["model"],
"imei" : deviceMap["imei"],
"app_version" : pakage.version,
"user_token" : uToken,
"userToken" : uToken,
},
connectTimeout: 30000,
receiveTimeout: 25000,
contentType: ContentType.json,
responseType: ResponseType.json,
);
return options;
}
以上。