This document describes how to integrate HTTPDNS with OkHttp on Android clients.
1. Background
If you use OkHttp as the network framework on Android, you can elegantly integrate HTTPDNS services by calling the custom DNS service interface provided by OkHttp.
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 has matured.
OkHttp uses the system DNS service InetAddress
for domain name resolution by default. It also provides the Dns API for developers to customize DNS resolution based on business requirements.
This practice also applies to Retrofit+OkHttp. You can pass the configured OkHttpClient as a parameter to Retrofit.Builder::client(OkHttpClient)
.
2. Custom DNS interface
OkHttp provides the Dns API for developers to customize DNS resolution:
class OkHttpDns constructor(context: Context): Dns {
private var mContext: Context
init {
mContext = context
}
@Throws(UnknownHostException::class)
override fun lookup(host: String): List<InetAddress> {
val httpdnsResult: HTTPDNSResult = HttpDns.getService(accountID)
.getHttpDnsResultForHostSync(host, RequestIpType.both)
val inetAddresses: MutableList<InetAddress> = ArrayList()
var address: InetAddress
try {
if (httpdnsResult.ips != null) {
// Process IPv4 addresses
for (ipv4 in httpdnsResult.ips) {
address = InetAddress.getByName(ipv4)
inetAddresses.add(address)
}
}
if (httpdnsResult.ipv6s != null) {
// Process IPv6 addresses
for (ipv6 in httpdnsResult.ipv6s) {
address = InetAddress.getByName(ipv6)
inetAddresses.add(address)
}
}
} catch (e: UnknownHostException) {
}
return if (!inetAddresses.isEmpty()) {
inetAddresses
} else Dns.SYSTEM.lookup(host)
}
}
public class OkHttpDns implements Dns {
private Context mContext;
public OkHttpDns(Context context) {
mContext = context;
}
@Override
public List<InetAddress> lookup(String host) throws UnknownHostException {
HTTPDNSResult httpdnsResult = HttpDns.getService(accountID).getHttpDnsResultForHostSync(host, RequestIpType.both);
List<InetAddress> inetAddresses = new ArrayList<>();
InetAddress address;
try {
if (httpdnsResult.getIps() != null) {
// Process IPv4 addresses
for (String ipv4 : httpdnsResult.getIps()) {
address = InetAddress.getByName(ipv4);
inetAddresses.add(address);
}
}
if (httpdnsResult.getIpv6s() != null) {
// Process IPv6 addresses
for (String ipv6 : httpdnsResult.getIpv6s()) {
address = InetAddress.getByName(ipv6);
inetAddresses.add(address);
}
}
} catch (UnknownHostException e) {
}
if (!inetAddresses.isEmpty()) {
return inetAddresses;
}
return okhttp3.Dns.SYSTEM.lookup(host);
}
}
Because okhttp
has an internal retry mechanism that might select different IP addresses to establish connections during retries, the lookup()
method in the Dns
interface can return a List<InetAddress>
containing multiple IP addresses. This effectively prevents request failures that might occur when a single IP address is returned but is unavailable.
3. Configure OkHttpClient
Create an OkHttpClient object and pass in the OkHttpDns object instead of the default DNS service:
private fun initOkHttp(context: Context) {
val client = OkHttpClient.Builder()
// Configure other initialization settings of OkHttp as required
.dns(OkHttpDns(context))
.build()
}
private void initOkHttp(Context context) {
OkHttpClient client = new OkHttpClient.Builder()
// Configure other initialization settings of OkHttp as required
.dns(new OkHttpDns(context))
.build();
}
The preceding code provides an example of how to use HTTPDNS and OkHttp to connect an Android app to an IP address.
4. Summary
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 applies 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.