This topic describes how to use OkHttp to connect an Android app to an IP address that is resolved from HTTPDNS. For information about the resolution service provided by HTTPDNS, see the SDK for Android development manual.
Background information
Connect an Android app to an IP address over HTTPS describes how to connect an Android app to an IP address that is resolved from HTTPDNS over HTTPS. However, if the network framework you use in the Android app is OkHttp, you can call a DNS service customization API provided by OkHttp to elegantly use HTTPDNS.
OkHttp is an open source lightweight Android framework for processing network requests. It is developed by Square as an alternative to HttpURLConnection and Apache HttpClient. Since its release, OkHttp has gained popularity among Android developers as it matured.
By default, OkHttp uses the InetAddress
class of the system DNS service to resolve domain names. OkHttp also provides an API for DNS service customization. This API allows you to elegantly use HTTPDNS.
Implement an API for DNS service customization
OkHttp provides the Dns API for developers to customize DNS resolution based on business requirements.
public class OkHttpDns implements Dns {
private static final Dns SYSTEM = Dns.SYSTEM;
HttpDnsService httpdns;// Define httpdns as the resolution service.
private static OkHttpDns instance = null;
private OkHttpDns(Context context) {
this.httpdns = HttpDns.getService(context, "account id");
}
public static OkHttpDns getInstance(Context context) {
if(instance == null) {
instance = new OkHttpDns(context);
}
return instance;
}
@Override
public List<InetAddress> lookup(String hostname) throws UnknownHostException {
// Obtain IP addresses by calling the API operation for asynchronously resolving a domain name.
String ip = httpdns.getIpByHostAsync(hostname);
if(ip != null) {
// If the returned ip value is not null, send network requests directly to the IP addresses.
List<InetAddress> inetAddresses = Arrays.asList(InetAddress.getAllByName(ip));
Log.e("OkHttpDns", "inetAddresses:" + inetAddresses);
return inetAddresses;
}
// If null is returned, use the system DNS service to resolve the domain name.
return Dns.SYSTEM.lookup(hostname);
}
}
Additional information on the Dns
API:
The IP addresses returned by the Dns
API are affected by the connectTimeout()
method of OkHttpClient when network requests are made by using OkHttp.
For example, if connectTimeout
is set to 5 seconds and two connection attempts to an IP address are made and end up timing out, the total timeout period for connecting to the IP address is 10 seconds.
If multiple List<InetAddress>
IP addresses are returned by the lookup()
method of the Dns
API, connection to these IP addresses is attempted in sequence.
If connection to the first IP address succeeds, the request is fulfilled.
If the first IP address is still unavailable after two connection attempts, OkHttp retries the connection with the next IP address until one of the following scenarios occurs: a connection is established, the set of IP addresses is exhausted, or a limit is exceeded.
In conclusion, we recommend that you use the lookup()
method of the Dns
API to return multiple IP addresses in List<InetAddress>
to prevent request failures due to the unavailability of a single IP address. We also recommend that you set the timeout period to a small value.
Create an OkHttpClient object
Create an OkHttpClient object and pass in the OkHttpDns object instead of the default DNS service:
private void okhttpDnsRequest() {
OkHttpClient client = new OkHttpClient.Builder()
.dns(OkHttpDns.getInstance(getApplicationContext()))
.build();
Request request = new Request.Builder()
.url("http://www.aliyun.com")
.build();
Response response = null;
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
DataInputStream dis = new DataInputStream(response.body().byteStream());
int len;
byte[] buff = new byte[4096];
StringBuilder result = new StringBuilder();
while ((len = dis.read(buff)) != -1) {
result.append(new String(buff, 0, len));
}
Log.d("OkHttpDns", "Response: " + result.toString());
}
});
}
The preceding code provides an example on how to use HTTPDNS and OkHttp to connect an Android app to an IP address.
Summary
Compared with the general solution, the combination of OkHttp and HTTPDNS provides the following benefits:
You only need to implement an API for DNS service customization to access HTTPDNS.
This solution is applicable to scenarios where HTTPS, Server Name Indication (SNI), and cookies are configured. This solution eliminates the need to perform certificate verification and domain name check.
This practice is also applicable to the scenario where Retrofit and OkHttp are used. After you have configured OkHttpClient, use it as the argument for Retrofit.Builder::client(OkHttpClient)
.