前言
很久很久之前,就看到某某公司说提取了Chromium的网络栈做App的网络库,当时自己还年少不懂事,一直觉得不明觉厉,最近一周利用下班时间,学习了下GN构建工具和ninja构建工具,参考:
感觉是时候自己编译一个Chromium的网络栈出来了。
编译
编译过程极其复杂,这篇文章不打算详细描述,目前,Chromium还不支持Mac上编译,因此为了编译它,特定用了沉睡了1年之久的Windows机,装了个Windows+Ubuntu双系统,就这样开始尝试编译。
编译过程中遇到了很多问题,总之,需要感谢以下几篇文章:
编译过程中的其他细节问题,请自行Google,也欢迎与我交流。
项目地址
目前我编译的Chromium网络栈已经发布成了aar,项目地址见
例子
我提供了一个示例代码的工程,你可以从 sample on Github 看到代码。
你只需要将其clone到本地,然后使用最新版本的andorid studio去编译,将其安装到你的设备上即可。
Chromium Net 源码
我从chromium/src/net上复制了一份和本库相关的Java源码,你可以从源码 on Github看到 。
当然,这份源码只是为了更方便的阅读一些Java层相关的代码,它并不能被直接编译。
特性
全平台支持最新版TLS。不像OkHttp这样依赖系统提供SSL/TLS加解密功能的网络库,chromium网络栈自身包含SSL库,因而可以全平台支持安全性更高的最新版TLS。
全平台支持HTTP/2及QUIC等最新的网络协议。HTTP/2本身对TLS的版本有要求,同样由于内含SSL库,而可以全平台支持HTTP/2。
为了尽可能的缩减so的大小,当前编译的版本并不支持FTP,WebSocket等协议,如果你需要使用它们,请自行编译它们。
使用
Maven
1 | <dependency> |
Gradle
1 | compile 'io.github.lizhangqu:cronet:0.0.1' |
Proguard
如果你进行了混淆,请在混淆文件中加入以下配置
1 | -keep class org.chromium.** {*;} |
NDK abi过滤
默认,此库包含了所有CPU结构的so,当然这带来的后果就是大小特别大,如果你只需要添加其中一个cpu结构的so,你可以使用abiFilters进行过滤,当然我建议只添加armeabi-v7a,毕竟它可以兼容目前市面上大多数的cpu,而armeabi的cpu目前市面上已基本看不见。
1 | android { |
创建Chromium 网络引擎
1 | CronetEngine.Builder builder = new CronetEngine.Builder(context); |
此时,你可以进行各种配置,比如自定义dns解析,在这里,你可以使用httpdns,以及可以设置支持http/2.0等特性,更多配置信息,请详见代码。
HttpUrlConnection的无缝使用
在OkHttp中,我们可以设置URL的URLStreamHandlerFactory为OkUrlFactory,这样,就可以在HttpUrlConnection中使用OkHttp的所有特性,就像这样:
1 | URL.setURLStreamHandlerFactory(new OkUrlFactory(new OkHttpClient())); |
Chromium的网络栈当然也支持这个:
1 | CronetURLStreamHandlerFactory cronetURLStreamHandlerFactory = new CronetURLStreamHandlerFactory(cronetEngine); |
然后,我们并不需要修改任何我们现有的代码,只需要像这样发送一个网络请求即可。
1 | try { |
发送一个GET请求
通过UrlRequest.Builder构建一个UrlRequest对象,然后调用start方法开始请求。
UrlRequest对象的构建需要若干个参数,其中必不可少的是前文创建的CronetEngine引擎对象,以及当前网络请求执行的线程池,当然请求的url和请求回调就更不用说了。示例代码如下:
1 | UrlRequest.Builder builder = new UrlRequest.Builder(mEditTextUrl.getText().toString(), new UrlRequest.Callback() { |
发送一个POST请求
POST请求和上面的GET请求相比,就是多了一个request body,这里将上面的方法简单封装一下,以同时支持GET请求和POST请求。
1 | public void startWithURL(String url, UrlRequest.Callback callback, Executor executor, String postData) { |
之后,我们复用前文发送GET请求的回调即可。
值得注意的是post请求需要提供一个UploadDataProvider,该对象用于提供发送的数据包,这么做的好处是一定程度上对body的数据格式进行扩展,默认Chromium的网络栈中并没有表单和Multipart的实现,因此我们可以通过UploadDataProvider对象,自行实现。