iOS 集成 Cronet 方法和测试

一、如何得到 Cronet 编译包

源码编译

可以参考 google 官方的指南 来编译。但编译过程非常坎坷,一路下来会遇到非常多的错误。不建议使用这种方式

使用编译好的

Google Cloud

谷歌在 Google Cloud 提供了编译好的包,编译周期非常短,基本上每天都有新包。选取指定的版本号下载即可。

gsutil

下载需要 gsutil 工具,可通过下面的方法来安装

复制代码
pip3 install gsutil

选择合适的版本

通过浏览版本记录,最新的版本是 2023.6.8 编译的 116.0.5820.0

Debug的就不用说了,肯定不能用到线上。

  • Release-iphonesimultor:intel芯片x86_64模拟器包

  • Release-m1 simulator:M1芯片模拟器+真机包

    不建议使用此包,目前公司还有同学在使用 intel 芯片开发,如果使用包含M1芯片的包,会导致项目编译不通过。

继续往前寻找,我们发现 2023.6.16 编译的 114.0.5735.140

  • Release-iphonesimultor:intel芯片x86_64模拟器包
  • Release-iphoneos:真机包

上面两个Release版本包,正是我们需要的。

下载包

我们使用 gsutil 工具来下载 114.0.5735.140 版本包。在终端执行如下命令即可

bash 复制代码
gsutil -m cp -r \
  "gs://chromium-cronet/ios/114.0.5735.140/Debug-iphonesimulator" \
  "gs://chromium-cronet/ios/114.0.5735.140/Debug-m1simulator" \
  "gs://chromium-cronet/ios/114.0.5735.140/Release-iphoneos" \
  "gs://chromium-cronet/ios/114.0.5735.140/Release-iphonesimulator" \
  "gs://chromium-cronet/ios/114.0.5735.140/Release-m1simulator" \
  .

合并包

通过 lipo 命令 来合并 Release-iphonesimulator 和 Release-iphoneos 两个包,打包成一个同时包含 arm64x86_64的包。可以使用静态包,也可以使用动态包。

lua 复制代码
lipo -create xxxx yyy -output Cronet

合并完之后,通过 file或者lipo -info命令查看包的架构

二、如何集成

新建好项目,将 Cronet.framework 添加到项目中,为什么能成功编译云清起来,还需要将一些依赖的系统库添加到项目中。

Github开源demo:github.com/lyandy/ios_...

三、API实践

Cronet采用NSURLProtocol切面编程的方式拦截了iOS系统的网络请求,集成起来相对容易。

设置Cronet

objectivec 复制代码
// 设置 支持 HTTP2, 如果设置为 NO,如果协议不支持H3,会降级到H1.1
    [Cronet setHttp2Enabled:YES];
    // 设置支持 QUIC
    [Cronet setQuicEnabled:YES];
    // 设置支持 Br 压缩算法,并列的有gzip算法
    [Cronet setBrotliEnabled:YES];
    // 设置 AcceptLanguages,AFN会自动补全设置,建议不单独设置
//    [Cronet setAcceptLanguages:@"en-US,en"];

    // 设置 请求的 UserAgent, AFN会自动补全设置,建议不单独设置
    // 这是设置生效顺序 URLRequest > Cronet > 默认
    // [Cronet setUserAgent:@"Dummy/1.0" partial:NO];

    // 设置 HTTP Cache 类型,建议不手动指定
//    [Cronet setHttpCacheType:CRNHttpCacheTypeDisabled];
    
    // 开启 metric 性能统计
    [Cronet setMetricsEnabled:YES];
    
    // 预先告诉 Cronet,支持 H3 的域名,以便尽快链接H3协议
    [Cronet addQuicHint:@"h2o.examp1e.net" port:443 altPort:443];

    // 开始cronet
    [Cronet start];

    // 建议不开启,开启后也会拦截所有的 NSURLConnection
    // 开启后,也会对webkit加载进行拦截。
//    [Cronet registerHttpProtocolHandler];

    // 是否要使用 Cronet 拦截指定请求
    // 不写的话,会拦截所有请求。最好是根据自己的条件来拦截
    [Cronet setRequestFilterBlock:^BOOL(NSURLRequest* request) {
        return YES;
    }];

hook 网络请求

下面是一个最简单的例子

ini 复制代码
- (void)startNSURLSession {
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    [Cronet installIntoSessionConfiguration:config]; // hook Protocol
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[@"https://h2o.examp1e.net?t=" stringByAppendingString:@([[NSDate date] timeIntervalSince1970]).stringValue]]];
    request.assumesHTTP3Capable = NO; // 关闭Apple QUIC
    NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *resp, __unused NSError *err) {
        NSLog(@"");
    }];
    
    [task resume];
}

四、测试

通过Charles抓包和Wireshark网络层转包来检测Cronet是否生效。

(以下演示结果均是使用 Github开源demo:github.com/lyandy/ios_... 的实验结果)

观察链接:h2o.examp1e.net?t=xxx (此链接支持H3,xxx是时间戳,防止出现LocalNetwork,H3自动降级为H2)

Charles

为了观察效果,我们故意设置Cronet的User-AgentDummy/1.0

观察到 User-AgentDummy/1.0,说明 Cronet 拦截请求成功

Wireshare

为了避开 Apple 自身 QUIC 的干扰,我们故意把 Apple QUIC 关闭

ini 复制代码
request.assumesHTTP3Capable = NO;

通过 Wireshark 的过滤规则,我们过滤出 本机Mac 和 h2o.examp1e.net 的ip

ini 复制代码
(ip.src==132.226.1.140 and ip.dst==10.6.0.107 ) or (ip.src==10.6.0.107 and ip.dst== 132.226.1.140)

可以看到 Protocol 是 QUIC, 在demo中也将识别出的 Protocol显示出来是 H3

稍等片刻,再次发起同样的请求,我们也能很轻易观察到 0-RTT现象,这对网络传输提速是非常有用的

通过以上测试可以得到结论,集成的Cronet工作正常,对支持H3的请求使用的是QUIC协议。

五、其他讨论

Apple 的 NSURLSession 自身有很多好处,不用开发者参与即可自动支持,Cronet 是否也是呢?如下

NSURLSession Cronet
QUIC
IPv6
TCP Fast Open
TLS 1.3
Multipath TCP

Cronet 使用还在探索之中,如有错误之处,欢迎指出一起讨论。

相关推荐
I烟雨云渊T7 小时前
iOS 门店营收表格功能的实现
ios
明月看潮生13 小时前
青少年编程与数学 01-011 系统软件简介 07 iOS操作系统
ios·青少年编程·操作系统·系统软件
90后的晨仔15 小时前
RxSwift 框架解析
前端·ios
可爱小仙子19 小时前
ios苹果系统,js 滑动屏幕、锚定无效
前端·javascript·ios
未来猫咪花20 小时前
# Flutter状态管理对比:view_model vs Riverpod
flutter·ios·android studio
咕噜企业签名分发-淼淼1 天前
开发源码搭建一码双端应用分发平台教程:逐步分析注意事项
android·ios
键盘敲没电1 天前
【IOS】GCD学习
学习·ios·objective-c·xcode
SY.ZHOU1 天前
Significant Location Change
macos·ios·cocoa
吴Wu涛涛涛涛涛Tao2 天前
深入理解 Swift Codable:从基础到进阶
ios
Jouzzy2 天前
【iOS安全】iPhone X iOS 16.7.11 (20H360) WinRa1n 越狱教程
安全·ios·iphone