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 使用还在探索之中,如有错误之处,欢迎指出一起讨论。

相关推荐
茶底世界之下2 天前
为什么预览、录制、离线导出不能共享同一个背压策略?
ios·swift
2501_916007472 天前
苹果商店iOS应用上架费用全面解析:开发者计划与审核费用计算
android·ios·小程序·https·uni-app·iphone·webview
2501_916008892 天前
如何实现iOS App代码混淆:SwiftShield使用指南
android·ios·小程序·https·uni-app·iphone·webview
2501_915909062 天前
移动端开发工具链怎么组合比较好,iOS、Android、跨端三套配置方案
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
2501_916008892 天前
怎么用 Godot 导出 iOS 应用并上架 App Store?签名字段该填什么?
android·ios·小程序·https·uni-app·iphone·webview
2501_915918412 天前
iOS编程用什么软件好?主流工具Xcode、AppCode、CodeRunner与新兴快蝎对比
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
终端安全笔记3 天前
iOS 27 之后「策略空转」:设备升级不报错,但旧策略不再管它
android·网络·安全·ios·智能手机
9765033353 天前
iOS 上架 4.3a 被拒【uniapp专讲】
flutter·ios·objective-c·uniapp·swift
黑化旺仔3 天前
【OC】KVO
macos·ios·objective-c·cocoa
HouWan3 天前
SwiftUI 小技巧:如何读取 SwiftUI Font 的详细信息
ios·swiftui·apple