Exploring QUIC on iOS: Basics, Implementation, and Performance
This article introduces the QUIC transport protocol, explains its design goals and key features, details a practical iOS implementation using Chromium and Stellite libraries, presents code examples, and compares QUIC’s download latency against HTTP/2 on Wi‑Fi and 4G networks.
1. QUIC Introduction
(1) QUIC (Quick UDP Internet Connections) Protocol
QUIC is a new UDP‑based web transport protocol. It can be roughly expressed as: TCP + TLS + HTTP2 = UDP + QUIC + HTTP2’s API Although built on UDP, QUIC provides TCP‑level reliability, congestion control, and flow control, while eliminating head‑of‑line blocking. It also inherits TLS security, establishing encrypted sessions with fewer RTTs.
(2) Main Purpose of QUIC
The protocol aims to combine TCP’s reliability with UDP’s speed and efficiency.
QUIC (Quick UDP Internet Connections) is an experimental transport‑layer network protocol developed by Google in 2013. It creates connections over UDP, supports multiplexing, and provides TLS‑level security while reducing latency and avoiding congestion. Google intends to submit QUIC to the IETF as a next‑generation standard.
(3) Key Features of QUIC
1) Low‑latency connection establishment
QUIC can start a connection in a single RTT, avoiding the three‑way handshake of TCP and the additional TLS negotiation.
QUIC 1‑RTT
For a new server, the client lacks server information and cannot perform a 0‑RTT handshake, so at least one RTT is required.
QUIC uses a static server configuration with an expiration time, allowing a single signature to be reused across multiple connections.
It employs a two‑level key mechanism (initial and session keys). The initial key is negotiated via Diffie‑Hellman; after that, the server provides a temporary random value to negotiate the session key, ensuring forward secrecy.
QUIC 0‑RTT
If the client caches the ServerConfig, it can send a full ClientHello with the chosen public key, allowing the server to respond without an extra round‑trip.
2) Improved Congestion Control
QUIC uses TCP’s Cubic algorithm as a baseline but adds several improvements:
Pluggable : Different congestion control algorithms can be selected at the application level without kernel changes.
Monotonically increasing Packet Number : QUIC uses packet numbers instead of byte offsets, simplifying retransmission handling.
More ACK blocks : Up to 256 ACK blocks are supported, compared with TCP’s limited SACK.
Precise RTT measurement : ACK frames carry the time from packet receipt to ACK transmission, enabling accurate RTT calculation.
3) Multiplexing without Head‑of‑Line Blocking
Unlike HTTP/2, which suffers from head‑of‑line blocking on a single TCP connection, QUIC’s streams are independent; loss on one stream does not block others.
4) Forward Error Correction (FEC)
QUIC can use simple XOR‑based FEC to recover lost packets without retransmission, at the cost of additional payload and CPU overhead.
5) Connection Migration
QUIC identifies connections with a 64‑bit Connection ID, allowing the logical connection to persist even if the client’s IP address or port changes.
2. Feasibility Study of QUIC on iOS
While QUIC is widely used on desktop browsers (e.g., Chromium), mobile support is still limited, making its feasibility on iOS uncertain.
(1) Exploring Chromium Projects
The Chromium source can be obtained via depot_tools:
$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.gitAfter adding it to PATH: $ export PATH="$PATH:/path/to/depot_tools" Fetch the iOS source:
$ mkdir chromium && cd chromium
$ fetch ios
$ cd srcCompiling generates several directories and an Xcode project. The directory structure includes base , build , net , ui , etc.
The module dependency graph is shown below:
(2) Stellite Library
Line’s open‑source Stellite library wraps Chromium’s net layer and provides a C++ API. Tencent Cloud’s live streaming SDK is built on Stellite.
Compile the client with:
./tools/build.py --target-platform=ios --target stellite_http_client buildThe build takes several hours because it first clones the Chromium source. After a successful build, the static library libstellite_http_client.a appears in the out directory.
(3) Cronet Library
Google’s Cronet SDK provides Java and Objective‑C bindings for Chromium’s net stack. Building Cronet for iOS requires linking cr_cronet.py and running GN and Ninja commands similar to the Stellite build.
~/chromium/src $ ln -s components/cronet/tools/cr_cronet.py somewhere/in/your/path
~/chromium/src $ python cr_cronet.py gn
~/chromium/src $ cr_cronet.py build -d out/Debug-iphonesimulator3. QUIC Practice on iOS
Using Stellite, the Chromium net layer was ported to iOS and a demo app was built to compare QUIC and HTTP/2 performance.
Key Objective‑C code for sending a request:
- (void)requestUrl:(NSString*)url useQuic:(BOOL)useQuic {
if (url.length == 0) return;
// Set header
stellite::HttpRequestHeader *header = new stellite::HttpRequestHeader;
header->SetHeader("Q-UA", "V1_IPH_SQ_7.3.0_0_HDBM_T");
stellite::HttpRequest *request = new stellite::HttpRequest;
request->url = [url UTF8String];
request->request_type = stellite::HttpRequest::GET;
stellite::HttpClientContext::Params *stParams = new stellite::HttpClientContext::Params;
if (useQuic) {
stParams->using_quic = true;
stParams->using_disk_cache = true;
std::vector<std::string> strings;
strings.push_back("https://stellite.io:443");
stParams->origins_to_force_quic_on = strings;
} else {
stParams->using_http2 = true;
stParams->using_disk_cache = true;
}
stellite::HttpClientContext *context = new stellite::HttpClientContext(*stParams);
context->Initialize();
downloadDuration = CFAbsoluteTimeGetCurrent();
MyHttpResponseDelegate *delegate = new MyHttpResponseDelegate;
stellite::HttpClient *client = context->CreateHttpClient(delegate);
client->Request(*request);
}Response delegate (simplified):
class MyHttpResponseDelegate:public stellite::HttpResponseDelegate {
public:
void OnHttpResponse(int request_id, const stellite::HttpResponse& response,
const char* body, size_t body_len) {
if (response.response_code == 200) {
downloadDuration = CFAbsoluteTimeGetCurrent() - downloadDuration;
NSData *data = [NSData dataWithBytes:body length:body_len];
BOOL useQuic = (response.connection_info == stellite::HttpResponse::CONNECTION_INFO_QUIC1_SDPY3);
[[libTest instance] saveImage:[UIImage imageWithData:data] downloadDuration:downloadDuration useQuic:useQuic];
NSLog(@"OnHttpResponse success downloadDuration=%lf", downloadDuration);
}
}
void OnHttpError(int request_id, int error_code, const std::string& error_message) {}
void OnHttpHeader(int request_id, const stellite::HttpResponse& response) {}
};Packet captures confirmed that the QUIC path was used.
4. QUIC vs. HTTP/2 Performance Data
Both protocols were used to download a 33 KB image over Wi‑Fi and 4G, with ten runs each.
Wi‑Fi results:
4G results:
The measurements show that QUIC reduces total download time by roughly 14 % on Wi‑Fi and 18 % on 4G compared with HTTP/2, indicating a latency advantage for this simple use case.
Further work will continue to explore Chromium source code and reduce the binary size of the iOS package.
Tencent TDS Service
TDS Service offers client and web front‑end developers and operators an intelligent low‑code platform, cross‑platform development framework, universal release platform, runtime container engine, monitoring and analysis platform, and a security‑privacy compliance suite.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
