All Products
Search
Document Center

HTTPDNS:Best practices for HTTPDNS and gRPC on Android

Last Updated:Dec 03, 2025

The Android SDK integration process document describes the complete process of importing and configuring the Android SDK, parsing IP addresses, applying the SDK to a network library, and verifying the integration. This topic describes the specific procedure for using HTTPDNS with gRPC.

1. Background

gRPC is a high-performance, open-source Remote Procedure Call (RPC) framework from Google. It is based on the HTTP/2 protocol and is widely used in the microservices model. By default, gRPC uses the system DNS for domain name resolution. However, it also provides a NameResolver extension mechanism that allows developers to customize the resolution logic.
On Android, if your application uses gRPC, you can implement a custom NameResolver to integrate HTTPDNS into gRPC. This replaces the system DNS for domain name resolution.

Note: This solution applies to gRPC clients that use grpc-okhttp as the transport layer, which is the recommended method for Android.

2. How it works

The gRPC domain name resolution flow is as follows:

ManagedChannel
    ↓
NameResolver (custom endpoint)
    ↓
LoadBalancer
    ↓
Transport (grpc-okhttp)
    ↓
TCP connection

By creating a custom NameResolver, you can integrate HTTPDNS at the domain name resolution stage. The custom NameResolver returns a list of resolved IP addresses to gRPC, and the gRPC LoadBalancer then handles load balancing and failover.

3. Integration steps

3.1 Add dependencies

Add the gRPC dependencies to your build.gradle file:

dependencies {
    // EMAS HTTPDNS
    implementation 'com.aliyun.ams:alicloud-android-httpdns:x.x.x'
    // gRPC Android
    implementation 'io.grpc:grpc-okhttp:x.x.x'
    implementation 'io.grpc:grpc-stub:x.x.x'
    implementation 'io.grpc:grpc-protobuf-lite:x.x.x'
}

3.2 Initialize HTTPDNS

Initialize the HTTPDNS service in your Application class:

public class MyApplication extends Application {
    @Overridepublic void onCreate() {
        super.onCreate();
        
        // Initialize HTTPDNS
        InitConfig config = new InitConfig.Builder()
                .setContext(this)
                .setSecretKey("your_secret_key")  // Optional
                .setEnableCacheIp(true, 24 * 60 * 60 * 1000)  // Enable cache
                .setEnableExpiredIp(true)  // Allow use of expired IPs
                .setTimeoutMillis(2000)
                .build();
        
        HttpDns.init("your_account_id", config);
    }
}

3.3 Implement a custom NameResolver

Create the EmasHttpDnsNameResolver class:

import io.grpc.EquivalentAddressGroup;
import io.grpc.NameResolver;
import io.grpc.Status;
import com.alibaba.sdk.android.httpdns.HttpDns;
import com.alibaba.sdk.android.httpdns.HttpDnsService;
import com.alibaba.sdk.android.httpdns.HTTPDNSResult;
import com.alibaba.sdk.android.httpdns.RequestIpType;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;

public class EmasHttpDnsNameResolver extends NameResolver {

    private final String host;
    private final int port;
    private Listener2 listener;

    public EmasHttpDnsNameResolver(String host, int port) {
        this.host = host;
        this.port = port;
    }

    @Overridepublic String getServiceAuthority() {
        return host;
    }

    @Overridepublic void start(Listener2 listener) {
        this.listener = listener;
        resolve();
    }

    @Overridepublic void refresh() {
        resolve();
    }

    private void resolve() {
        List<EquivalentAddressGroup> addressGroups = new ArrayList<>();

        try {
            // Call HTTPDNS to resolve the domain name
            HttpDnsService httpDnsService = HttpDns.getService("your_account_id");
            HTTPDNSResult result = httpDnsService.getHttpDnsResultForHostSyncNonBlocking(
                host, 
                RequestIpType.auto
            );

            // If HTTPDNS returns null, fall back to the system DNS
            if (result == null || 
                (result.getIps() == null || result.getIps().length == 0) &&
                (result.getIpv6s() == null || result.getIpv6s().length == 0)) {
                
                InetAddress[] systemAddrs = InetAddress.getAllByName(host);
                for (InetAddress addr : systemAddrs) {
                    addressGroups.add(new EquivalentAddressGroup(
                        new InetSocketAddress(addr, port)
                    ));
                }
            } else {
                // Add IPv4 addresses
                if (result.getIps() != null) {
                    for (String ip : result.getIps()) {
                        addressGroups.add(new EquivalentAddressGroup(
                            new InetSocketAddress(ip, port)
                        ));
                    }
                }
                
                // Add IPv6 addresses
                if (result.getIpv6s() != null) {
                    for (String ip : result.getIpv6s()) {
                        addressGroups.add(new EquivalentAddressGroup(
                            new InetSocketAddress(ip, port)
                        ));
                    }
                }
            }

            // Return the resolution result
            ResolutionResult resolutionResult = ResolutionResult.newBuilder()
                    .setAddresses(addressGroups)
                    .build();

            listener.onResult(resolutionResult);

        } catch (Exception e) {
            listener.onError(Status.UNAVAILABLE.withDescription(
                "HTTPDNS resolve failed: " + e.getMessage()
            ));
        }
    }

    @Overridepublic void shutdown() {
        // Clean up resources
    }
}

3.4 Implement NameResolverProvider

Create the EmasHttpDnsResolverProvider class:

import io.grpc.NameResolver;
import io.grpc.NameResolverProvider;
import java.net.URI;

public class EmasHttpDnsResolverProvider extends NameResolverProvider {

    private static final String SCHEME = "emashttpdns";

    @Overrideprotected boolean isAvailable() {
        return true;
    }

    @Overrideprotected int priority() {
        return 5;
    }

    @Overridepublic NameResolver newNameResolver(URI targetUri, NameResolver.Args args) {
        if (!SCHEME.equals(targetUri.getScheme())) {
            return null;
        }

        String host = targetUri.getHost();
        int port = targetUri.getPort() == -1 ? 443 : targetUri.getPort();

        return new EmasHttpDnsNameResolver(host, port);
    }

    @Overridepublic String getDefaultScheme() {
        return SCHEME;
    }
}

3.5 Register the NameResolver

Register the custom NameResolver in your Application class:

public class MyApplication extends Application {
    @Overridepublic void onCreate() {
        super.onCreate();
        
        // Initialize HTTPDNS (see step 3.2)
        // ...
        
        // Register the custom NameResolver
        NameResolverRegistry.getDefaultRegistry()
                .register(new EmasHttpDnsResolverProvider());
    }
}

3.6 Use the gRPC client

When creating the gRPC channel, use the custom scheme:

// Create the channel
ManagedChannel channel = OkHttpChannelBuilder
        .forTarget("emashttpdns://your-grpc-server.com:443")
        .overrideAuthority("your-grpc-server.com")  // Important: This ensures correct TLS SNI
        .useTransportSecurity()  // Enable TLS
        .build();

// Create the stub and make the call
YourServiceGrpc.YourServiceBlockingStub stub = 
    YourServiceGrpc.newBlockingStub(channel);

YourResponse response = stub.yourMethod(request);

4. Verify the integration

After the integration is complete, you can verify its success using methods such as hijacking impersonation or fault injection testing. For more information, see the Verify Successful Network Library Integration document.

5. Summary

By implementing the gRPC NameResolver interface, you can integrate HTTPDNS into your gRPC client. This approach provides the following advantages:

  • Simple implementation: You only need to implement the NameResolver interface to integrate the HTTPDNS service.

  • High versatility: This method works for various gRPC scenarios and is compatible with security mechanisms such as certificate validation and Server Name Indication (SNI).

  • High availability: It supports automatic load balancing and failover across multiple IP addresses. If HTTPDNS resolution fails, it automatically falls back to the system DNS.

  • Performance optimization: It helps prevent DNS hijacking and improves resolution speed and success rates.