【flutter初尝ffi】 基于frb开发属于自己的shine_http组件
由于dart的ffi更新日渐成熟,我决定用它做点东西。
于是做些什么就成了我思考的事情,大致思考了平时在flutter开发遇到的一些问题。
最终决定制作一套满足自己需求的组件进行尝试。
我把它叫做shine系列,可能包括但不限于:
- http组件
- - listview组件
- - image组件
- - video和直播之类的
在这里就是简单的实现了下http相关的逻辑
本次我们使用rust+dart ffi进行尝试,使用rust单纯是因为我喜欢这门语言并且pub上也有frb这个开发套件。
如果你是实际商业应用的开发者,考虑到生态的成熟度和官方的支持,ffi交叉编译的开发,还是建议优先使用c++。
为什么要开发一个http组件
一方面是我使用的dio已经很长时间没有维护了
另一方面我希望这类基础功能要有好的跨平台支持
我的话是选择了rust的reqwest进行http的开发,reqwest是一个依赖于tokio的http异步请求包,它能很容易的进行配置并将数据反序列化为rust的struct。
然后我们通过frb就可以将struct直接返回为dart的model class,给flutter使用,这个过程会比较舒服。
为了进行比较我们还会使用dart的http制作一个同样的请求,展示两者之间的过程和效率。
让我们准备一个http请求,并用apipost测试下结果:
首先我们制作一个dart版本的http请求:
var c1 = DateTime.now().millisecondsSinceEpoch;
Map<String, String> header = {
HttpHeaders.contentTypeHeader: "application/json",
};
var _httpClient = http.Client();
try {
var uri = Uri.parse("http://httpbin.org/ip");
var response = await _httpClient.get(uri, headers: header);
if (response.statusCode == 200) {
var jsonResponse =
convert.jsonDecode(response.body) as Map<String, dynamic>;
var bb = BaseIp.from(jsonResponse);
var c2 = DateTime.now().millisecondsSinceEpoch;
print(
'bb变量返回的结果: ${bb.toString()},具体的值为:${bb.origin},耗费的时间为:${c2 - c1}');
} else {
print('Request failed with status: ${response.statusCode}.');
}
} finally {
_httpClient.close();
}
}
根据返回的数据,我们可以知道,dart耗时919ms
然后我们准备一个rust版本的http请求
pub struct Ip {
pub origin: String,
}
#[tokio::main(flavor = "current_thread")]
pub async fn get_item() -> anyhow::Result<Ip> {
let retry_policy = ExponentialBackoff::builder().build_with_max_retries(1);
let api = ClientBuilder::new(reqwest::Client::new())
.with(RetryTransientMiddleware::new_with_policy(retry_policy))
.build();
let url = "http://httpbin.org/ip";
let mut headers = HeaderMap::new();
headers.insert("Content-Type", "application/json".parse().unwrap());
let res = api.get(url).headers(headers).timeout(Duration::from_secs(6)).send().await?.json::<Ip>().await?;
Ok(res)
}
交叉编译后,在dart中我们这样来调用它
var d1 = DateTime.now().millisecondsSinceEpoch;
try {
var aa = await api.getItem();
var d2 = DateTime.now().millisecondsSinceEpoch;
print('aa变量返回的结果: ${aa.toString()},具体的值为:${aa.origin},耗费的时间为:${d2 - d1}');
} catch (e) {
print(e);
}
}
简单的重启后,我们得到基本一致的结果,在不需要手动编写dart的model class的同时,通信耗时大幅降低(个人猜测应该是反序列化的差距,毕竟rust的serde真的性能很好):
基本上,这个http的组件是跑通了,由于我个人不是很喜欢写dart的model class,所以应该不会将response返回出来,而是选择直接返回class使用(毕竟写struct确实比类更简单)。
虽然http组件实现的代码不多,但是也花费了我挺长的时间,在此记录一下。
第一次接触,估计大部分时间耗在交叉编译环境,frb配置,以及各种各样奇奇怪怪的坑上。
所以如果大家需要使用交叉编译来增强flutter的应用性能和跨平台性。最好提前适应一下,免得什么时候要用的时候,开始抓耳挠腮的去谷歌找解决问题的答案,就很烦。
呜呜呜!
希望大家能积极通过ffi开发让flutter的功能,性能,以及体验变得更好。
什么?不想积极,不想开发!?
无所谓,皮神会出手的!!!
转载自:https://juejin.cn/post/7165922213776850975