[Huawei Developers] Freemind R:
Let's take a look at the Huawei hQUIC Kit features so we can easily put these features to our apps.

The most applications today operate with internet connectivity to serve data to end-users that means we interact with a backend, web services, or APIs.This mobile content is served over the trusted TCP protocol so you know as HTTP/2 when dealing with web technology.When we consider performance and speed, TCP technology has some shortcomings.

Based on the idea of a faster internet, Google announced a new protocol draft called QUIC (Quick UDP Internet Connections) in 2013. This draft was made a standard by the Internet Engineering Task Force (IETF) in 2015, and a working group was established in 2016 and the protocol continued to be developed. In 2018, this protocol was now called HTTP/3 by the IETF, and became the new HTTP standard worldwide.QUIC promises to perform better than TCP.

Here, in this article, we will examine the hQUIC kit that covers gQUIC and Cronet.We will see the effects of the hQUIC kit on performance, especially in the poor network.

I created a sample app which I’ve open-sourced on GitHub for enthusiasts who want to use this kit.

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/025/494/656/5190090000025494656.20201022072447.96207195579265212060386961407001:50511105012228:2800:B47F9AD9D79D30B1466556A0433F43771D4BEDAD40E55BB99B9D5DC7BEED4392.jpeg"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/025/494/656/5190090000025494656.20201022072447.96207195579265212060386961407001:50511105012228:2800:B47F9AD9D79D30B1466556A0433F43771D4BEDAD40E55BB99B9D5DC7BEED4392.jpeg[/IMG]

What is hQUIC Kit?

hQUIC Kit provides the ability to fulfill our needs for lower packet loss in our applications, high performance in our network operations and reliable fast connection.It supports the gQUIC protocol and provides intelligent congestion control algorithms to avoid congestions in different network environments.

https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/introduction-0000001050440045

Advantages

Ease of use: Streamlines APIs and shields low-level network details.

High compatibility: Supports gQUIC and Cronet.

Better experience: Outperforms other protocols in poor network conditions.

If the server does not support QUIC, your app with the hQUIC SDK integrated will communicate with the server through HTTP/1.1 or HTTP/2.

Setting up the hQUIC Kit

You’ll need to do setup before you can use the hQUIC Kit.You can follow the official documentation on how to prepare app on App Gallery Connect.

Also you can follow this blog post to integrate your apps with Huawei HMS Core:

https://medium.com/huawei-developers/android-integrating-your-apps-with-huawei-hms-core-1f1e2a090e98

Add the required dependencies to the build.gradle file under app folder.We need some dependencies.

implementation 'com.huawei.hms:hquic-provider:5.0.0.300'
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
implementation"com.squareup.okhttp3:okhttp:4.9.0"

In addition to the hQUIC dependency we have added extra dependencies.

Glide : For showing images on the screen

OkHttp : To demonstrate hQUIC’s usage with OkHttp

Add the required permissions to the AndroidManifest.xml file under app/src/main folder.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Integration Steps

We will basically build our application with 4 steps.

We will initialize the hQUIC module to load the Cronet network repository in advance.

We create a Cronet engine and set whether to enable the QUIC protocol.

We construct a request and set the HTTP method for the request.We will test Http/2, hQUIC and OkHtpp with hQUIC separately in our example.

We will send download request for 16 images and compute time cost between start and end times.

Initializing the hQUIC Module

We can use asyncInit function of HQUICManager class to initialize hQUIC before creating Cronet engine.Asynchronous initialization is optional. To load the Cronet service in advance, you can use the asynchronous initialization API to preload the service.

HQUICManager.asyncInit(context, object : HQUICInitCallback {
override fun onSuccess() {
Log.i(TAG, "HQUICManager asyncInit success")
}
override fun onFail(e: Exception) {
Log.w(TAG, "HQUICManager asyncInit fail")
}
})

Creating a Cronet Engine

We will use this engine before building our request.So you can see that we need to set true in enableQuic function to perform quic.

CronetEngine.Builder(context.applicationContext)
.enableQuic(true)
.build()

Constructing and Sending a Download Request

Firstly, We will create download request for hQUIC test.We used openConnection method from Cronet engine as while passing URL parameter.After downloading process , we wrote our image to dummy file.Also we computed time cost between open connection and close connection times.

val time = System.currentTimeMillis()
val connection = mEngine.openConnection(URL(img)) as HttpURLConnection
connection.requestMethod = "GET"
connection.connect()
val source = connection.inputStream.source().buffer()
val downloadedFile = File(this.externalCacheDir, "aaa.jpg")
val sink = downloadedFile.sink().buffer()
sink.writeAll(source)
sink.close()
source.close()
val cost = System.currentTimeMillis() - time
Log.i(TAG, "download complete $img cost = ${System.currentTimeMillis() - time}")

For now, let’s build our pure http request while using OkHttp.We need to create OkHttpClient object to send request.

mOkhttpClent = OkHttpClient.Builder()
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.connectTimeout(30, TimeUnit.SECONDS)
.cache(null)
.build()

After creating OkHttpClient object , we passed this value as parameter to our request method.We used newCall method from OkHttp to send downloading request.

val time = System.currentTimeMillis()
val req = Request.Builder()
.url(img)
.build()
val resp = client.newCall(req).execute()
val source = resp.body!!.source()
val downloadedFile = File(this.externalCacheDir, "bbb.jpg")
val sink = downloadedFile.sink().buffer()
sink.writeAll(source)
sink.close()
source.close()
val cost = System.currentTimeMillis() - time
Log.i(TAG, "download complete $img cost = ${System.currentTimeMillis() - time}")

Finally, we will build our http request with quic while using OkHttp.We need to create again OkHttpClient object to send request.As extra , we will need addInterceptor method.We will pass QUICInterceptor object value to this method for our quic example.

mOkhttpClentWithQUIC = OkHttpClient.Builder()
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.connectTimeout(30, TimeUnit.SECONDS)
.cache(null)
.addInterceptor(QUICInterceptor())
.build()

Let’s look at our QUICInterceptor class:

If our HQuicService is enabled , we will use Cronet engine connection as our connection.

Also we set Protocol.QUIC value to protocol method in Response class when building object.

class QUICInterceptor: Interceptor {
private val TAG = QUICInterceptor::class.java.simpleName
override fun intercept(chain: Interceptor.Chain): Response {
if (!HQuicService.enable) {
return chain.proceed(chain.request())
}
val req = chain.request()
val url = req.url.toUrl()
val connection = HQuicService.engine.openConnection(url) as HttpURLConnection
req.headers.names().forEach {
connection.addRequestProperty(it, req.headers[it])
}
connection.requestMethod = req.method
req.body?.let {
it.contentType()?.let {
connection.setRequestProperty("Content-Type", it.toString())
}
connection.doOutput = true
val os = connection.outputStream
val sink = os.sink().buffer()
it.writeTo(sink)
sink.flush()
os.close()
}
val statusCode = connection.responseCode
if (statusCode in 300..310) {
return chain.proceed(req)
}
val respBuilder = Response.Builder()
respBuilder
.request(req)
.protocol(Protocol.QUIC)
.code(statusCode)
.message(connection.responseMessage ?: "")
val respHeaders = connection.headerFields
respHeaders.entries.forEach {
it.value.forEach {
value ->
respBuilder.addHeader(it.key, value)
}
}
val bodySource = (if (statusCode in 200..399) connection.inputStream else connection.errorStream).source().buffer()
respBuilder.body(
RealResponseBody(respHeaders["Content-Type"]?.last(),
respHeaders["Content-Length"]?.last()?.toLong() ?: 0,
bodySource)
)
val resp = respBuilder.build()
return resp
}
}

After creating OkHttpClient object by using QUICInterceptor, we passed this value as parameter to our request method.We used newCall method from OkHttp with quic to send downloading request.We can test quic perform with OkHttp.

val time = System.currentTimeMillis()
val req = Request.Builder()
.url(img)
.build()
val resp = client.newCall(req).execute()
val source = resp.body!!.source()
val downloadedFile = File(this.externalCacheDir, "bbb.jpg")
val sink = downloadedFile.sink().buffer()
sink.writeAll(source)
sink.close()
source.close()
val cost = System.currentTimeMillis() - time
Log.i(TAG, "download complete $img cost = ${System.currentTimeMillis() - time}")

More information like this, you can check https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0202387367223820479&fid=0101246461018590361