Flutter http請(qǐng)求庫(kù)dio穩(wěn)定版發(fā)布

dioFlutter中文網(wǎng)開(kāi)源的一個(gè)強(qiáng)大的Dart Http請(qǐng)求庫(kù)撼港,支持Restful API坪它、FormData、攔截器帝牡、請(qǐng)求取消哟楷、Cookie管理、文件上傳/下載否灾、超時(shí)等...

dio開(kāi)源至今卖擅,收到了大量國(guó)內(nèi)外開(kāi)發(fā)者的反饋,到目前為止墨技,dio在pub倉(cāng)庫(kù)得分96分惩阶,github dart語(yǔ)言下開(kāi)源項(xiàng)目排名已上升到前20,dio現(xiàn)在也是flutter第三方package中star數(shù)最多的扣汪。在dio開(kāi)源的兩個(gè)月中断楷,已迭代了18個(gè)小版本,國(guó)內(nèi)外有多家公司的Flutter APP正在使用dio崭别,已通過(guò)了大量的實(shí)戰(zhàn)驗(yàn)證冬筒,已經(jīng)在AppStore上架的APP典型代表是gitme

Gitme是一個(gè)強(qiáng)大的github客戶端APP,它使用dio作為http client茅主,除了正常的http請(qǐng)求之外舞痰,有一個(gè)最大的特點(diǎn)是gitme通過(guò)dio攔截器,實(shí)現(xiàn)了APP內(nèi)統(tǒng)一诀姚、隔離的緩存層响牛,完全和上層ui解耦。您可以下載體驗(yàn)一下Gitme赫段。如有必要呀打,我會(huì)單獨(dú)出一篇文章詳細(xì)介紹一下如何使用dio攔截器實(shí)現(xiàn)離線緩存,大家如果有興趣可以在評(píng)論中反饋糯笙。

所以贬丛,今天,我們正式發(fā)布dio的第一個(gè)穩(wěn)定版本1.0给涕。下面豺憔,我們?nèi)娴慕榻B一下dio 1.0的功能及使用。

建議dio的老用戶都升級(jí)到1.0正式版稠炬,并同時(shí)感謝你們?cè)赿io項(xiàng)目初期的支持焕阿,沒(méi)有你們的反饋與建議咪啡,dio穩(wěn)定版不會(huì)這么快發(fā)布首启。

文檔語(yǔ)言: English | 中文簡(jiǎn)體

dio

dio是一個(gè)強(qiáng)大的Dart Http請(qǐng)求庫(kù),支持Restful API撤摸、FormData毅桃、攔截器褒纲、請(qǐng)求取消、Cookie管理钥飞、文件上傳/下載莺掠、超時(shí)等...

添加依賴

dependencies:
  dio: ^x.x.x  // 請(qǐng)使用pub上的最新版本

一個(gè)極簡(jiǎn)的示例

import 'package:dio/dio.dart';
Dio dio = new Dio();
Response response=await dio.get("https://www.google.com/");
print(response.data);

最近更新

  1. 文件上傳支持?jǐn)?shù)組。
  2. 支持http狀態(tài)碼被認(rèn)為對(duì)應(yīng)成功或失敗的自定義判斷读宙。
  3. 添加清空攔截器隊(duì)列API Clear()彻秆。

內(nèi)容列表

示例

發(fā)起一個(gè) GET 請(qǐng)求 :

Response response;
response=await dio.get("/test?id=12&name=wendu")
print(response.data.toString());
// 請(qǐng)求參數(shù)也可以通過(guò)對(duì)象傳遞,上面的代碼等同于:
response=await dio.get("/test",data:{"id":12,"name":"wendu"})
print(response.data.toString());

發(fā)起一個(gè) POST 請(qǐng)求:

response=await dio.post("/test",data:{"id":12,"name":"wendu"})

發(fā)起多個(gè)并發(fā)請(qǐng)求:

response= await Future.wait([dio.post("/info"),dio.get("/token")]);

下載文件:

response=await dio.download("https://www.google.com/","./xx.html")

發(fā)送 FormData:

FormData formData = new FormData.from({
   "name": "wendux",
   "age": 25,
});
response = await dio.post("/info", data: formData)

通過(guò)FormData上傳多個(gè)文件:

FormData formData = new FormData.from({
   "name": "wendux",
   "age": 25,
   "file1": new UploadFileInfo(new File("./upload.txt"), "upload1.txt"),
   "file2": new UploadFileInfo(new File("./upload.txt"), "upload2.txt"),
     // 支持文件數(shù)組上傳
   "files": [
      new UploadFileInfo(new File("./example/upload.txt"), "upload.txt"),
      new UploadFileInfo(new File("./example/upload.txt"), "upload.txt")
    ]
});
response = await dio.post("/info", data: formData)

…你可以在這里獲取所有示例代碼.

Dio APIs

創(chuàng)建一個(gè)Dio實(shí)例结闸,并配置它

你可以使用默認(rèn)配置或傳遞一個(gè)可選 Options參數(shù)來(lái)創(chuàng)建一個(gè)Dio實(shí)例 :

Dio dio = new Dio; // 使用默認(rèn)配置

// 配置dio實(shí)例
dio.options.baseUrl="https://www.xx.com/api"
dio.options.connectTimeout = 5000; //5s
dio.options.receiveTimeout=3000;

// 或者通過(guò)傳遞一個(gè) `options`來(lái)創(chuàng)建dio實(shí)例
Options options= new Options(
    baseUrl:"https://www.xx.com/api",
    connectTimeout:5000,
    receiveTimeout:3000
);
Dio dio = new Dio(options);

Dio實(shí)例的核心API是 :

Future<Response> request(String path, {data, Options options,CancelToken cancelToken})

response=await request("/test", data: {"id":12,"name":"xx"}, new Options(method:"GET"));

請(qǐng)求方法別名

為了方便使用唇兑,Dio提供了一些其它的Restful API, 這些API都是request的別名。

Future<Response> get(path, {data, Options options,CancelToken cancelToken})

Future<Response> post(path, {data, Options options,CancelToken cancelToken})

Future<Response> put(path, {data, Options options,CancelToken cancelToken})

Future<Response> delete(path, {data, Options options,CancelToken cancelToken})

Future<Response> head(path, {data, Options options,CancelToken cancelToken})

Future<Response> put(path, {data, Options options,CancelToken cancelToken})

Future<Response> path(path, {data, Options options,CancelToken cancelToken})

Future<Response> download(String urlPath, savePath,
{OnDownloadProgress onProgress, data, bool flush: false, Options options,CancelToken cancelToken})

請(qǐng)求配置

下面是所有的請(qǐng)求配置選項(xiàng)桦锄。 如果請(qǐng)求method沒(méi)有指定扎附,則默認(rèn)為GET :

{
  /// Http method.
  String method;

  /// 請(qǐng)求基地址,可以包含子路徑,如: "https://www.google.com/api/".
  String baseUrl;

  /// Http請(qǐng)求頭.
  Map<String, dynamic> headers;

  /// 連接服務(wù)器超時(shí)時(shí)間结耀,單位是毫秒.
  int connectTimeout;

  ///  響應(yīng)流上前后兩次接受到數(shù)據(jù)的間隔留夜,單位為毫秒。如果兩次間隔超過(guò)[receiveTimeout]图甜,
  ///  [Dio] 將會(huì)拋出一個(gè)[DioErrorType.RECEIVE_TIMEOUT]的異常.
  ///  注意: 這并不是接收數(shù)據(jù)的總時(shí)限.
  int receiveTimeout;

  /// 請(qǐng)求數(shù)據(jù),可以是任意類型.
  var data;

  /// 請(qǐng)求路徑碍粥,如果 `path` 以 "http(s)"開(kāi)始, 則 `baseURL` 會(huì)被忽略; 否則,
  /// 將會(huì)和baseUrl拼接出完整的的url.
  String path="";

  /// 請(qǐng)求的Content-Type黑毅,默認(rèn)值是[ContentType.JSON].
  /// 如果您想以"application/x-www-form-urlencoded"格式編碼請(qǐng)求數(shù)據(jù),
  /// 可以設(shè)置此選項(xiàng)為 `ContentType.parse("application/x-www-form-urlencoded")`,  這樣[Dio]
  /// 就會(huì)自動(dòng)編碼請(qǐng)求體.
  ContentType contentType;

  /// [responseType] 表示期望以那種格式(方式)接受響應(yīng)數(shù)據(jù)即纲。
  /// 目前 [ResponseType] 接受三種類型 `JSON`, `STREAM`, `PLAIN`.
  ///
  /// 默認(rèn)值是 `JSON`, 當(dāng)響應(yīng)頭中content-type為"application/json"時(shí),dio 會(huì)自動(dòng)將響應(yīng)內(nèi)容轉(zhuǎn)化為json對(duì)象博肋。
  /// 如果想以二進(jìn)制方式接受響應(yīng)數(shù)據(jù)低斋,如下載一個(gè)二進(jìn)制文件,那么可以使用 `STREAM`.
  ///
  /// 如果想以文本(字符串)格式接收響應(yīng)數(shù)據(jù)匪凡,請(qǐng)使用 `PLAIN`.
  ResponseType responseType;

  /// `validateStatus` 決定http響應(yīng)狀態(tài)碼是否被dio視為請(qǐng)求成功膊畴, 返回`validateStatus`
  ///  返回`true` , 請(qǐng)求結(jié)果就會(huì)按成功處理,否則會(huì)按失敗處理.
  ValidateStatus validateStatus;

  /// 用戶自定義字段病游,可以在 [Interceptor]唇跨、[Transformer] 和 [Response] 中取到.
  Map<String, dynamic> extra;
}

這里有一個(gè)完成的示例.

響應(yīng)數(shù)據(jù)

當(dāng)請(qǐng)求成功時(shí)會(huì)返回一個(gè)Response對(duì)象,它包含如下字段:

{
  /// 響應(yīng)數(shù)據(jù)衬衬,可能已經(jīng)被轉(zhuǎn)換了類型, 詳情請(qǐng)參考Options中的[ResponseType].
  var data;
  /// 響應(yīng)頭
  HttpHeaders headers;
  /// 本次請(qǐng)求信息
  Options request;
  /// Http status code.
  int statusCode;
  /// 響應(yīng)對(duì)象的自定義字段(可以在攔截器中設(shè)置它)买猖,調(diào)用方可以在`then`中獲取.
  Map<String, dynamic> extra;
}

示例如下:

Response response=await dio.get("https://www.google.com");
print(response.data);
print(response.headers);
print(response.request);
print(statusCode);

攔截器

每一個(gè) Dio 實(shí)例都有一個(gè)請(qǐng)求攔截器 RequestInterceptor 和一個(gè)響應(yīng)攔截器 ResponseInterceptor, 通過(guò)攔截器你可以在請(qǐng)求之前或響應(yīng)之后(但還沒(méi)有被 thencatchError處理)做一些統(tǒng)一的預(yù)處理操作。

 dio.interceptor.request.onSend = (Options options){
     // 在請(qǐng)求被發(fā)送之前做一些事情
     return options; //continue
     // 如果你想完成請(qǐng)求并返回一些自定義數(shù)據(jù)滋尉,可以返回一個(gè)`Response`對(duì)象或返回`dio.resolve(data)`玉控。
     // 這樣請(qǐng)求將會(huì)被終止,上層then會(huì)被調(diào)用狮惜,then中返回的數(shù)據(jù)將是你的自定義數(shù)據(jù)data.
     //
     // 如果你想終止請(qǐng)求并觸發(fā)一個(gè)錯(cuò)誤,你可以返回一個(gè)`DioError`對(duì)象高诺,或返回`dio.reject(errMsg)`碌识,
     // 這樣請(qǐng)求將被中止并觸發(fā)異常,上層catchError會(huì)被調(diào)用虱而。
 }
 dio.interceptor.response.onSuccess = (Response response) {
     // 在返回響應(yīng)數(shù)據(jù)之前做一些預(yù)處理
     return response; // continue
 };
 dio.interceptor.response.onError = (DioError e){
     // 當(dāng)請(qǐng)求失敗時(shí)做一些預(yù)處理
     return e;//continue
 }

如果你想移除攔截器筏餐,你可以將它們置為null:

dio.interceptor.request.onSend=null;
dio.interceptor.response.onSuccess=null;
dio.interceptor.response.onError=null;

完成和終止請(qǐng)求/響應(yīng)

在所有攔截器中,你都可以改變請(qǐng)求執(zhí)行流牡拇, 如果你想完成請(qǐng)求/響應(yīng)并返回自定義數(shù)據(jù)魁瞪,你可以返回一個(gè) Response 對(duì)象或返回 dio.resolve(data)的結(jié)果。 如果你想終止(觸發(fā)一個(gè)錯(cuò)誤惠呼,上層catchError會(huì)被調(diào)用)一個(gè)請(qǐng)求/響應(yīng)佩番,那么可以返回一個(gè)DioError 對(duì)象或返回 dio.reject(errMsg) 的結(jié)果.

 dio.interceptor.request.onSend = (Options options){
     return dio.resolve("fake data")
 }
 Response response= await dio.get("/test");
 print(response.data);//"fake data"

攔截器中支持異步任務(wù)

攔截器中不僅支持同步任務(wù),而且也支持異步任務(wù), 下面是在請(qǐng)求攔截器中發(fā)起異步任務(wù)的一個(gè)實(shí)例:

  dio.interceptor.request.onSend = (Options options) async{
     //...If no token, request token firstly.
     Response response = await dio.get("/token");
     //Set the token to headers
     options.headers["token"] = response.data["data"]["token"];
     return options; //continue
 }

Lock/unlock 攔截器

你可以通過(guò)調(diào)用攔截器的 lock()/unlock 方法來(lái)鎖定/解鎖攔截器罢杉。一旦請(qǐng)求/響應(yīng)攔截器被鎖定趟畏,接下來(lái)的請(qǐng)求/響應(yīng)將會(huì)在進(jìn)入請(qǐng)求/響應(yīng)攔截器之前排隊(duì)等待,直到解鎖后滩租,這些入隊(duì)的請(qǐng)求才會(huì)繼續(xù)執(zhí)行(進(jìn)入攔截器)赋秀。這在一些需要串行化請(qǐng)求/響應(yīng)的場(chǎng)景中非常實(shí)用,后面我們將給出一個(gè)示例律想。

tokenDio=new Dio(); //Create a new instance to request the token.
tokenDio.options=dio;
dio.interceptor.request.onSend = (Options options) async{
     // If no token, request token firstly and lock this interceptor
     // to prevent other request enter this interceptor.
     dio.interceptor.request.lock();
     // We use a new Dio(to avoid dead lock) instance to request token.
     Response response = await tokenDio.get("/token");
     //Set the token to headers
     options.headers["token"] = response.data["data"]["token"];
     dio.interceptor.request.unlock()
     return options; //continue
 }

Clear()

你也可以調(diào)用攔截器的clear()方法來(lái)清空等待隊(duì)列猎莲。

別名

當(dāng)請(qǐng)求攔截器被鎖定時(shí),接下來(lái)的請(qǐng)求將會(huì)暫停技即,這等價(jià)于鎖住了dio實(shí)例著洼,因此,Dio示例上提供了請(qǐng)求攔截器lock/unlock的別名方法:

dio.lock() == dio.interceptor.request.lock()

dio.unlock() == dio.interceptor.request.unlock()

dio.clear() == dio.interceptor.request.clear()

示例

假設(shè)這么一個(gè)場(chǎng)景:出于安全原因而叼,我們需要給所有的請(qǐng)求頭中添加一個(gè)csrfToken身笤,如果csrfToken不存在,我們先去請(qǐng)求csrfToken葵陵,獲取到csrfToken后液荸,再發(fā)起后續(xù)請(qǐng)求。 由于請(qǐng)求csrfToken的過(guò)程是異步的脱篙,我們需要在請(qǐng)求過(guò)程中鎖定后續(xù)請(qǐng)求(因?yàn)樗鼈冃枰猚srfToken), 直到csrfToken請(qǐng)求成功后娇钱,再解鎖,代碼如下:

dio.interceptor.request.onSend = (Options options) {
    print('send request:path:${options.path}绊困,baseURL:${options.baseUrl}');
    if (csrfToken == null) {
      print("no token文搂,request token firstly...");
      //lock the dio.
      dio.lock();
      return tokenDio.get("/token").then((d) {
        options.headers["csrfToken"] = csrfToken = d.data['data']['token'];
        print("request token succeed, value: " + d.data['data']['token']);
        print('continue to perform request:path:${options.path},baseURL:${options.path}');
        return options;
      }).whenComplete(() => dio.unlock()); // unlock the dio
    } else {
      options.headers["csrfToken"] = csrfToken;
      return options;
    }
  };

完整的示例代碼請(qǐng)點(diǎn)擊 這里.

錯(cuò)誤處理

當(dāng)請(qǐng)求過(guò)程中發(fā)生錯(cuò)誤時(shí), Dio 會(huì)包裝 Error/Exception 為一個(gè) DioError:

  try {
    //404
    await dio.get("https://wendux.github.io/xsddddd");
   } on DioError catch(e) {
      // The request was made and the server responded with a status code
      // that falls out of the range of 2xx and is also not 304.
      if(e.response) {
        print(e.response.data)
        print(e.response.headers)
        print(e.response.request)
      } else{
        // Something happened in setting up or sending the request that triggered an Error
        print(e.request)
        print(e.message)
      }
  }

DioError 字段

 {
  /// 響應(yīng)信息, 如果錯(cuò)誤發(fā)生在在服務(wù)器返回?cái)?shù)據(jù)之前秤朗,它為 `null`
  Response response;

  /// 錯(cuò)誤描述.
  String message;

  /// 錯(cuò)誤類型煤蹭,見(jiàn)下文
  DioErrorType type;

  /// 錯(cuò)誤棧信息,可能為null
  StackTrace stackTrace;
}

DioErrorType

enum DioErrorType {
  /// Default error type, usually occurs before connecting the server.
  DEFAULT,

  /// When opening  url timeout, it occurs.
  CONNECT_TIMEOUT,

  ///  Whenever more than [receiveTimeout] (in milliseconds) passes between two events from response stream,
  ///  [Dio] will throw the [DioError] with [DioErrorType.RECEIVE_TIMEOUT].
  ///
  ///  Note: This is not the receiving time limitation.
  RECEIVE_TIMEOUT,

  /// When the server response, but with a incorrect status, such as 404, 503...
  RESPONSE,

  /// When the request is cancelled, dio will throw a error with this type.
  CANCEL
}

使用application/x-www-form-urlencoded編碼

默認(rèn)情況下, Dio 會(huì)將請(qǐng)求數(shù)據(jù)(除過(guò)String類型)序列化為 JSON. 如果想要以 application/x-www-form-urlencoded格式編碼, 你可以顯式設(shè)置contentType :

//Instance level
dio.options.contentType=ContentType.parse("application/x-www-form-urlencoded");
//or works once
dio.post("/info",data:{"id":5}, options: new Options(contentType:ContentType.parse("application/x-www-form-urlencoded")))

這里有一個(gè)示例.

FormData

Dio支持發(fā)送 FormData, 請(qǐng)求數(shù)據(jù)將會(huì)以 multipart/form-data方式編碼, FormData中可以一個(gè)或多個(gè)包含文件 .

FormData formData = new FormData.from({
    "name": "wendux",
    "age": 25,
    "file": new UploadFileInfo(new File("./example/upload.txt"), "upload.txt")
});
response = await dio.post("/info", data: formData)

注意: 只有 post 方法支持發(fā)送 FormData.

這里有一個(gè)完整的示例.

轉(zhuǎn)換器

轉(zhuǎn)換器Transformer 用于對(duì)請(qǐng)求數(shù)據(jù)和響應(yīng)數(shù)據(jù)進(jìn)行編解碼處理。Dio實(shí)現(xiàn)了一個(gè)默認(rèn)轉(zhuǎn)換器DefaultTransformer作為默認(rèn)的 Transformer. 如果你想對(duì)請(qǐng)求/響應(yīng)數(shù)據(jù)進(jìn)行自定義編解碼處理疯兼,可以提供自定義轉(zhuǎn)換器,通過(guò) dio.transformer設(shè)置贫途。

請(qǐng)求轉(zhuǎn)換器 Transformer.transformRequest(...) 只會(huì)被用于 'PUT'吧彪、 'POST'、 'PATCH'方法丢早,因?yàn)橹挥羞@些方法才可以攜帶請(qǐng)求體(request body)姨裸。但是響應(yīng)轉(zhuǎn)換器 Transformer.transformResponse() 會(huì)被用于所有請(qǐng)求方法的返回?cái)?shù)據(jù)。

執(zhí)行流

雖然在攔截器中也可以對(duì)數(shù)據(jù)進(jìn)行預(yù)處理怨酝,但是轉(zhuǎn)換器主要職責(zé)是對(duì)請(qǐng)求/響應(yīng)數(shù)據(jù)進(jìn)行編解碼傀缩,之所以將轉(zhuǎn)化器單獨(dú)分離,一是為了和攔截器解耦农猬,二是為了不修改原始請(qǐng)求數(shù)據(jù)(如果你在攔截器中修改請(qǐng)求數(shù)據(jù)(options.data)赡艰,會(huì)覆蓋原始請(qǐng)求數(shù)據(jù),而在某些時(shí)候您可能需要原始請(qǐng)求數(shù)據(jù)). Dio的請(qǐng)求流是:

請(qǐng)求攔截器 >> 請(qǐng)求轉(zhuǎn)換器 >> 發(fā)起請(qǐng)求 >> 響應(yīng)轉(zhuǎn)換器 >> 響應(yīng)攔截器 >> 最終結(jié)果斤葱。

這是一個(gè)自定義轉(zhuǎn)換器的示例.

設(shè)置Http代理

Dio 是使用 HttpClient發(fā)起的http請(qǐng)求慷垮,所以你可以通過(guò)配置 httpClient來(lái)支持代理,示例如下:

  dio.onHttpClientCreate = (HttpClient client) {
    client.findProxy = (uri) {
      //proxy all request to localhost:8888
      return "PROXY localhost:8888";
    };
    // 你也可以自己創(chuàng)建一個(gè)新的HttpClient實(shí)例返回揍堕。
    // return new HttpClient(SecurityContext);
  };

完整的示例請(qǐng)查看這里.

請(qǐng)求取消

你可以通過(guò) cancel token 來(lái)取消發(fā)起的請(qǐng)求:

CancelToken token = new CancelToken();
dio.get(url, cancelToken: token)
    .catchError((DioError err){
        if (CancelToken.isCancel(err)) {
            print('Request canceled! '+ err.message)
        }else{
            // handle error.
        }
    })
// cancel the requests with "cancelled" message.
token.cancel("cancelled");

注意: 同一個(gè)cancel token 可以用于多個(gè)請(qǐng)求料身,當(dāng)一個(gè)cancel token取消時(shí),所有使用該cancel token的請(qǐng)求都會(huì)被取消衩茸。

完整的示例請(qǐng)參考取消示例.

Cookie管理

你可以通過(guò) cookieJar 來(lái)自動(dòng)管理請(qǐng)求/響應(yīng)cookie.

dio cookie 管理 API 是基于開(kāi)源庫(kù) cookie_jar.

你可以創(chuàng)建一個(gè)CookieJarPersistCookieJar 來(lái)幫您自動(dòng)管理cookie, dio 默認(rèn)使用 CookieJar , 它會(huì)將cookie保存在內(nèi)存中芹血。 如果您想對(duì)cookie進(jìn)行持久化, 請(qǐng)使用 PersistCookieJar , 示例代碼如下:

var dio = new Dio();
dio.cookieJar=new PersistCookieJar("./cookies");

PersistCookieJar 實(shí)現(xiàn)了RFC中標(biāo)準(zhǔn)的cookie策略. PersistCookieJar 會(huì)將cookie保存在文件中,所以 cookies 會(huì)一直存在除非顯式調(diào)用 delete 刪除.

更多關(guān)于 cookie_jar 請(qǐng)參考 : https://github.com/flutterchina/cookie_jar .

Copyright & License

此開(kāi)源項(xiàng)目為Flutter中文網(wǎng)(https://flutterchina.club) 授權(quán) 楞慈,license 是 MIT. 如果您喜歡幔烛,歡迎star.

Flutter中文網(wǎng)開(kāi)源項(xiàng)目計(jì)劃

開(kāi)發(fā)一系列Flutter SDK之外常用(實(shí)用)的Package、插件囊蓝,豐富Flutter第三方庫(kù)说贝,為Flutter生態(tài)貢獻(xiàn)來(lái)自中國(guó)開(kāi)發(fā)者的力量。所有項(xiàng)目將發(fā)布在 Github Flutter中文網(wǎng) Organization 慎颗,所有源碼貢獻(xiàn)者將加入到我們的Organization乡恕,成為成員. 目前社區(qū)已有幾個(gè)開(kāi)源項(xiàng)目開(kāi)始公測(cè),歡迎您加入開(kāi)發(fā)或測(cè)試俯萎,詳情請(qǐng)查看: Flutter中文網(wǎng)開(kāi)源項(xiàng)目傲宜。 如果您想加入到“開(kāi)源項(xiàng)目計(jì)劃”, 請(qǐng)發(fā)郵件到824783146@qq.com夫啊, 并附上自我介紹(個(gè)人基本信息+擅長(zhǎng)/關(guān)注技術(shù))函卒。

Features and bugs

Please file feature requests and bugs at the issue tracker.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市撇眯,隨后出現(xiàn)的幾起案子报嵌,更是在濱河造成了極大的恐慌虱咧,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锚国,死亡現(xiàn)場(chǎng)離奇詭異腕巡,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)血筑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)绘沉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人豺总,你說(shuō)我怎么就攤上這事车伞。” “怎么了喻喳?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵另玖,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我表伦,道長(zhǎng)日矫,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任绑榴,我火速辦了婚禮哪轿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘翔怎。我一直安慰自己窃诉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布赤套。 她就那樣靜靜地躺著飘痛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪容握。 梳的紋絲不亂的頭發(fā)上宣脉,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音剔氏,去河邊找鬼塑猖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛谈跛,可吹牛的內(nèi)容都是我干的羊苟。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼感憾,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蜡励!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤凉倚,失蹤者是張志新(化名)和其女友劉穎兼都,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體稽寒,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扮碧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瓦胎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芬萍。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡尤揣,死狀恐怖搔啊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情北戏,我是刑警寧澤负芋,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站嗜愈,受9級(jí)特大地震影響旧蛾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蠕嫁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一锨天、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧剃毒,春花似錦病袄、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至基公,卻和暖如春幅慌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背轰豆。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工胰伍, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人酸休。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓喇辽,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親雨席。 傳聞我的和親對(duì)象是個(gè)殘疾皇子菩咨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • dio是Flutter中文網(wǎng)開(kāi)源的一個(gè)強(qiáng)大的Dart Http請(qǐng)求庫(kù),支持Restful API、FormData...
    lazydu閱讀 33,730評(píng)論 6 35
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理抽米,服務(wù)發(fā)現(xiàn)特占,斷路器,智...
    卡卡羅2017閱讀 134,599評(píng)論 18 139
  • 本文詳細(xì)介紹了 XMLHttpRequest 相關(guān)知識(shí)云茸,涉及內(nèi)容: AJAX是目、XMLHTTP、XMLHttpReq...
    semlinker閱讀 13,613評(píng)論 2 18
  • 2018.6.13 一标捺、肯定法(加油煜祺你能行0媚伞) 1、兒子:媽媽亡容,楊思敬今天給我吃一種小零食特別好吃嗤疯,我也想去買(mǎi)...
    文娜_閱讀 137評(píng)論 0 0
  • 我二階回來(lái)有點(diǎn)不太想見(jiàn)人,想一個(gè)人呆著闺兢,靜靜的茂缚,但總是要見(jiàn)人,總是有人屋谭,昨天分行來(lái)人服務(wù)培訓(xùn)脚囊,我有那么一點(diǎn)點(diǎn)...
    誼君閱讀 149評(píng)論 0 0