Using HTTP3/QUIC with Cronet In Your Mobile App

Faster downloads, lower latencies, disconnect tolerance, now in your iOS/Android and react-native app!

Akshet Pandey
The React Native Log
5 min readAug 31, 2019

--

Wait, there is an HTTP3?

Currently in a draft stage, IETF and the QUIC working group are working on finishing HTTP3 and the QUIC specification.

In the simplest of terms, HTTP3 is HTTP2 over QUIC.

So what exactly is QUIC?

QUIC is a network layer protocol implemented over UDP. Simply put, QUIC is an improvement over TCP. It provides much of what TCP does, i.e. a reliable network channel that handles losses, reordering, retransmission, and congestion control/fairness. On top of that, QUIC also provides:

  • Dramatically reduced connection establishment time
  • Improved congestion control
  • Multiplexing without head of line blocking
  • Forward error correction
  • Connection migration

This results in high performance in high latency channels, such as those on mobile devices. You can learn more about the advantages of using QUIC here:

Here is my own test implemented in react-native to compare cronet performance on a high latency, low bandwidth channel.

Left:OkHttp in React Native, Right: OkHttp + Cronet in React Native, both on a slow network with a QUIC capable server

What is Cronet?

The best description comes from the Cronet README:

Cronet is the networking stack of Chromium put into a library for use on mobile. This is the same networking stack that is used in the Chrome browser by over a billion people. It offers an easy-to-use, high performance, standards-compliant, and secure way to perform HTTP requests. Cronet has support for both Android and iOS.

Cronet is a very well implemented and tested¹ network stack that provides almost everything that a standard app needs from a network layer library, things like DNS, Cookies, SSL/TLS, HTTP(S), HTTP2, Proxy/PAC, OSCP, Websockets, and F̶T̶P̶ (soon to be removed). It also supports HTTP over QUIC, soon to be called HTTP³². This makes it a very attractive library to use as the network layer for your mobile app.

Who is using it?

Cronet is used by Google Chrome, YouTube, Google App, Google Photos, and Maps — Navigation & Transit.

HTTP3/QUIC is already being used or is in development by facebook (mvfst), Uber, Cloudflare, Fastly, most of GCP Load Balancers and CDN and many more, including Apple, Microsoft, and Mozilla.

How do I use QUIC in my app?

The simplest way is to integrate cronet and have a backend server or CDN or a proxy like cloudflare that supports QUIC. Most google & GCP services including Youtube support QUIC by default. Cloudflare, Akamai, and Fastly support QUIC but needs to be manually enabled.

Using Cronet In Your App

Based on whether your app is a native Android app, native iOS app or a react-native app, jump to the appropriate section.

Using Cronet in Android

If you are starting from scratch, using cronet as the network layer is documented on the android developer docs. You can use it directly instead of using HttpUrlConnection or OkHttp.

It comes down to adding a library dependency in your build.gradle file.

dependencies {
implementation 'com.google.android.gms:play-services-cronet:16.0.0'
}

Then checking if cronet is available to use:

CronetProviderInstaller.installProvider(reactContext).addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
// Setup your code to use cronet here.
}
}
});

After that follow the instructions to create an instance of the engine and send a request.

Using Cronet in Android using OkHttp

If you already have an app, you are likely using OkHttp and very likely don’t want to rewrite every piece of code that interacts with the OkHttp API.

Fortunately, it is possible to use cronet with OkHttp. Follow the steps above and then, depending on what other libraries you use, follow one of the two steps below.

  1. If you are using Retrofit. You can use Retrofit.Builder.callFactory to pass in a custom call factory that you can write that works with cronet.

An example implementation is available here: RNCronetOkHttpCall.java

2. If you are NOT using Retrofit, you can use an OkHttp interceptor to make cronet work for you. This is a less ideal solution, but works mostly fine.

An example implementation is available here: RNCronetInterceptor.java

Note: Though the files says RN, the code doesn’t use anything react-native specific.

Using Cronet in iOS

Although cronet works perfectly fine on iOS, it lacks substantial documentation. You can get started by reading Cronet.h and cronet_consumer sample code. However, once built, using cronet is much easier on iOS than Android.

Cronet is not officially available as a framework or cocoapod, but you can build it from source following the build instructions. For your convenience, I have created a podspec that you can include:

pod 'Cronet', '78.0.3888.patch.0.pre'

After this you can initialize the engine and have NSURLSession and NSURLConnection use cronet internally. This is fairly straightforward to do:

#include <Cronet/Cronet.h>...[Cronet setHttp2Enabled:YES];
[Cronet setQuicEnabled:YES];
[Cronet setBrotliEnabled:YES];
[Cronet setHttpCacheType:CRNHttpCacheTypeDisk];
[Cronet addQuicHint:@"www.google.com" port:443 altPort:443];[Cronet start];[Cronet registerHttpProtocolHandler];

Sample code to get you started is here: AppDelegate.m

Using Cronet in React Native

I have made a react-native library that should make using cronet very simple. Just add it into your package.json

yarn add react-native-cronet

That is all you need to do for iOS.

On Android, you need to configure Fresco to also use it by adding the following in your MainApplication.java. This depends on a PR waiting to be merged in react-native-community/cli. In the meantime, you can use patch-package with that patch.

import com.akshetpandey.rncronet.RNCronetFrescoImagePipelineConfig;
import com.facebook.imagepipeline.core.ImagePipelineConfig;
import com.facebook.react.shell.MainPackageConfig;
public class MainApplication extends Application implements ReactApplication { private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
protected List<ReactPackage> getPackages() {
ImagePipelineConfig pipelineConfig = RNCronetFrescoImagePipelineConfig.build(getApplicationContext());
MainPackageConfig config = new MainPackageConfig.Builder().setFrescoConfig(pipelineConfig).build();
List<ReactPackage> packages = new PackageList(this, config).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new RNCronetNetworkingPackage());
return packages;
}
}
}

¹- What is a better way to test a network stack than in Chrome, whose primary job is to fetch assets and data over the network and display them to the user?

²- QUIC is a general purpose transport layer network protocol built on top of UDP with a user space congestion control and packet loss recovery algorithm that is still being improved. HTTP3 is an application layer protocol that speaks HTTP over QUIC.

Hire Me

I am looking for new opportunities, you can learn more about me on LinkedIn and see more of my work on GitHub

--

--