Revert "Bug 1863744 - Update Gradle to version 8.4" This reverts commit 829795632954148709fbe945c78d55cc62053ac8. Revert "Bug 1821005 - Apply additional keep rules for missing classes detected while running R8." This reverts commit 8f3f246cc5ff571323f56d46963d8d176bec91e3. Revert "Bug 1821005 - Set UI_INJECTION_HOST mode for lint in test." This reverts commit 6962bf0b5df57781045f68417f76527bcdf521ab. Revert "Bug 1821005 - Include sourcesJar as an input of publishing." This reverts commit 41b2a48da577787c3189eec8c8af71c35cfecbfb. Revert "Bug 1821005 - Set compileOptions for android subprojects." This reverts commit fb21df9d0a9cd585e216733dc1bf929636df20f1. Revert "Bug 1821005 - Replace deprecated project.buildDir" This reverts commit 6f880de46ec73f7e5240a0279108bbb6aeb0f63b. Revert "Bug 1821005 - Exclude generated metrics docs from detekt." This reverts commit f17d2430bf1daabeed2724312354018050f3f52a. Revert "Bug 1821005 - Exclude build in extensions versioning from detekt." This reverts commit 34144c5ad1d62e2d85492f8d32341bbcd032690b. Revert "Bug 1821005 - Add uses-feature tag for camera permission." This reverts commit 13c80944bd1756cdcaa98eef783b6a23ad12cabd. Revert "Bug 1821005 - Set nonTransitiveRClass and nonFinalResIds build flags to false." This reverts commit 219fbc19c54134ad264edc79642fa1799c6f54d6. Revert "Bug 1821005 - Apply plugin: 'kotlin-android' for UI modules." This reverts commit ddbd5e18eb9d2b33b4de4a6df48d97ec4ab42963. Revert "Bug 1821005 - Enable generation of the BuildConfig class" This reverts commit 65c2b8c63790fbd2352f3f94b99c80d81d18dae1. Revert "Bug 1821005 - Add namespace to samples-glean-library module" This reverts commit 0239233efb1cc4e896e4aa0337e3da911eeb2f1c. Revert "Bug 1821005 - Replace deprecated toLowerCase with lowercase." This reverts commit 69f2c66aad3aa638a1bab31b2a1e6c597d1f3992. Revert "Bug 1821005 - Replace deprecated 'toInt' method with 'code' property." This reverts commit 7adb38a6fbe20de3fdb6723a10e574d183e7fcff. Revert "Bug 1821005 - Replace deprecated execResult." This reverts commit bfd02dd16d7e5c9dbcf34858fbbe4176d698f8cd. Revert "Bug 1849833 - Replace deprecated extractNativeLibs manifest attribute." This reverts commit a05bc9618457ab2d71a5d3d88d8d3b0318497a54. Revert "Bug 1821005 - Upgrade AGP to 8.0.2" This reverts commit fc0fadd63553e2144ce074454d502ecf307eb988. Revert "Bug 1821005 - Upgrade kotlin-dsl to 4.1.0." This reverts commit 14e8903e922fa22e28450520be3b6152be6a3a8f. Revert "Bug 1821005 - Upgrade Gradle to 8.3 version." This reverts commit f14f447a4d43588d24e4ca3efde0668ddcf7cf08.
Android Components > Concept > Fetch
The concept-fetch component contains interfaces for defining an abstract HTTP client for fetching resources.
The primary use of this component is to hide the actual implementation of the HTTP client from components required to make HTTP requests. This allows apps to configure a single app-wide used client without the components enforcing a particular dependency.
The API and name of the component is inspired by the Web Fetch API.
Usage
Setting up the dependency
Use Gradle to download the library from maven.mozilla.org (Setup repository):
implementation "org.mozilla.components:concept-fetch:{latest-version}"
Performing requests
Get a URL
val request = Request(url)
val response = client.fetch(request)
val body = response.string()
A Response may hold references to other resources (e.g. streams). Therefore it's important to always close the Response object or its Body. This can be done by either consuming the content of the Body with one of the available methods or by using Kotlin's extension methods for using Closeable implementations (e.g. use()):
client.fetch(Request(url)).use { response ->
val body = response.body.string()
}
Post to a URL
val request = Request(
url = "...",
method = Request.Method.POST,
body = Request.Body.fromStream(stream))
client.fetch(request).use { response ->
if (response.success) {
// ...
}
}
Github API example
val request = Request(
url = "https://api.github.com/repos/mozilla-mobile/android-components/issues",
headers = MutableHeaders(
"User-Agent" to "AwesomeBrowser/1.0",
"Accept" to "application/json; q=0.5",
"Accept" to "application/vnd.github.v3+json"))
client.fetch(request).use { response ->
val server = response.headers.get('Server')
val result = response.body.string()
}
Posting a file
val file = File("README.md")
val request = Request(
url = "https://api.github.com/markdown/raw",
headers = MutableHeaders(
"Content-Type", "text/x-markdown; charset=utf-8"
),
body = Request.Body.fromFile(file))
client.fetch(request).use { response ->
if (request.success) {
// Upload was successful!
}
}
Asynchronous requests
Client implementations are synchronous. For asynchronous requests it's recommended to wrap a client in a Coroutine with a scope the calling code is in control of:
val deferredResponse = async { client.fetch(request) }
val body = deferredResponse.await().body.string()
Interceptors
Interceptors are a powerful mechanism to monitor, modify, retry, redirect or record requests as well as responses going through a Client. Interceptors can be used with any concept-fetch implementation.
The withInterceptors() extension method can be used to create a wrapped Client that will use the provided interceptors for requests.
val response = HttpURLConnectionClient()
.withInterceptors(LoggingInterceptor(), RetryInterceptor())
.fetch(request)
The following example implements a simple Interceptor that logs requests and how long they took:
class LoggingInterceptor(
private val logger: Logger = Logger("Client")
): Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
logger.info("Request to ${chain.request.url}")
val startTime = System.currentTimeMillis()
val response = chain.proceed(chain.request)
val took = System.currentTimeMillis() - startTime
logger.info("[${response.status}] took $took ms")
return response
}
}
And the following example is a naive implementation of an interceptor that retries requests:
class NaiveRetryInterceptor(
private val maxRetries: Int = 3
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request)
if (response.isSuccess) {
return response
}
return retry(chain) ?: response
}
fun retry(chain: Interceptor.Chain): Response? {
var lastResponse: Response? = null
var retries = 0
while (retries < maxRetries) {
lastResponse = chain.proceed(chain.request)
if (lastResponse.isSuccess) {
return lastResponse
}
retries++
}
return lastResponse
}
}
License
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/