HarmonyOS SDK Developer Guide

更新时间:
复制 MD 格式

Integrate and use the HTTPDNS HarmonyOS SDK for domain resolution, DNS acceleration, and anti-hijacking.

Install the SDK

Import the SDK into your DevEco Studio project by automatic import or manual import. For a complete example, download the Demo sample project source code.

  • Automatic import: Install by using ohpm

    You can get the SDK from the OpenHarmony third-party library repository.

    Run the following command in your project root:

    ohpm install @alidns/httpdns

    The Instructions for the OpenHarmony Third-Party Library Repository covers ohpm usage and third-party SDK installation.

  • Manual import: Reference the local HAR package

    Download the HarmonyOS SDK from the SDK Download page and integrate it into your app project.

    In your project's oh-package.json5 file, set the dependency. The following example shows the configuration if the HAR package is in the root directory of the project. Use the actual path to your HAR package.

    "dependencies": {
        "@alidns/httpdns": "file:alidns-harmony-sdk-2.0.4.har"
     }

    After configuring the dependency, run ohpm install. The package is stored in the oh_modules directory.

    ohpm install

Use the SDK

Import the module

import { Alipdns,schemaType,DNSDomainInfo, DNSLogger } from '@alidns/httpdns'

Set up authentication

Add the following code in your ability's onCreate callback to enable authentication:

Important

Create an AccessKey ID and AccessKey Secret on the console by following Create a key.

import { Alipdns,schemaType,DNSDomainInfo, DNSLogger } from '@alidns/httpdns'

const AccountID = 'TODO: Replace with your Account ID from the console.';
const AccessKeyID = 'TODO: Replace with the AccessKey ID of the key you created in the "Access Configuration" section of the console.';
const AccessKeySecret = 'TODO: Replace with the AccessKey Secret of the key you created in the "Access Configuration" section of the console.';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // ************* Alibaba Cloud HTTPDNS SDK configuration - START *************
    DNSLogger.getInstance().setEnableLogger = true;
    let alipdns = Alipdns.getInstance();
    alipdns.Init(this.context,AccountID,AccessKeyID,AccessKeySecret);
    alipdns.setKeepAliveDomains(['your-domain-1.com','your-domain-2.com']);
    alipdns.setSchemaType(schemaType.https);
    alipdns.preLoadDomains(alipdns.QTYPE_V4,['your-domain-1.com','your-domain-2.com','your-domain-3.com']);
    // ************* Alibaba Cloud HTTPDNS SDK configuration - END *************
  }

  // Other code omitted
}

API

1. Account ID and authentication

The Account ID is required. After you register your application on the console, a unique Account ID is generated. Create an AccessKey ID and AccessKey Secret by following Create a key, and set them in your app:

Alipdns.getInstance().Init(this.context,AccountID,AccessKeyID,AccessKeySecret);
Warning
  • Disable SDK debug logs in production to prevent credentials and runtime data from leaking into logs.

  • Account ID, AccessKey ID, and AccessKey Secret are tied to metering and billing. To prevent credential theft through decompilation, avoid passing them as plaintext in production. Encode or encrypt the credentials and decrypt them only when passing them to the SDK. We also recommend code obfuscation and hardening to prevent third parties from extracting these credentials.

2. Resolution protocol

Set the resolution protocol (HTTP or HTTPS) with the scheme property.

The SDK defaults to HTTPS, recommended for security. HTTPDNS bills by resolution request count, with HTTPS requests billed at 5x the HTTP rate. Choose a scheme based on your requirements:

Alipdns.getInstance().setSchemaType(schemaType.https);

3. Automatic cache refresh

Automatic cache refresh keeps cached entries current for specified domains. When enabled, the SDK proactively updates expired entries, which may increase resolution requests and traffic. When disabled, cache updates occur only when your app calls a resolution method.

Alipdns.getInstance().setKeepAliveDomains(['your-domain-1.com','your-domain-2.com']);
Note
  • Pros:

    • Updates records before the TTL expires.

    • Reduces first-resolution latency to 0 ms when combined with pre-resolution.

  • Cons: If a cached entry's age exceeds 75% of its TTL, the SDK sends a new request, which incurs additional costs.

4. Pre-resolution

After the first resolution populates the cache, subsequent lookups have zero latency. Pre-resolve domains your app needs at startup.

Example:

Alipdns.getInstance().preLoadDomains(alipdns.QTYPE_V4,['your-domain-1.com','your-domain-2.com','your-domain-3.com']);

5. SDK debug logs

Enable or disable SDK debug logs by setting the value to true or false. Call this method before SDK initialization.

DNSLogger.getInstance().setEnableLogger = true;

6. HTTPDNS to local DNS

By default, the SDK falls back to local DNS when HTTPDNS resolution fails.

Alipdns.getInstance().setEnableLocalDns(true);// By default, fallback to local DNS is enabled if HTTPDNS resolution fails.

7. Resolution timeout

The timeout property sets the domain resolution timeout. Default: 3 seconds. Recommended range: 2–5 seconds.

Alipdns.getInstance().setTimeout(3);// The default timeout is 3 seconds.

8. Immutable cache

Alipdns.getInstance().setImmutableCacheEnable(false);// By default, immutable cache is disabled.
Important

The SDK provides three cache update mechanisms:

  • Immutable cache: The cache stays valid for the app's entire runtime with no expiration checks or updates, minimizing resolution requests.

    To enable: Alipdns.getInstance().setImmutableCacheEnable(true)

  • Proactive cache refresh: Keeps cached records fresh with low latency when authoritative records change. Supports up to 10 domains.

    To configure: Alipdns.getInstance().setKeepAliveDomains(['your-domain-1.com','your-domain-2.com']);

  • Passive cache update: The cache is passively updated when you call the following resolution methods:

    • Alipdns.getInstance().getIpsByHostAsync(Alipdns.getInstance().QTYPE_V4, host,(ips:string[]) => {});: This method gets an array of resolved IPv4 addresses for a domain. If a valid, non-expired entry exists in the cache, the method returns the cached result. Otherwise, it requests the latest result, returns it, and updates the cache.

    • const result = Alipdns.getInstance().getIpsByHostFromCache(Alipdns.getInstance().QTYPE_V4,host,true);: This method gets the IPv4 resolution result from the cache. Its behavior depends on the enable parameter.

      If enable is set to YES, a stale record is returned even if the cache is expired (if the cache is empty, null is returned), and the cache is updated by an asynchronous request. If it is set to NO, null is returned if the cache is expired or empty, and the cache is updated by an asynchronous request.

9. Resolution methods

The SDK provides the following resolution methods:

/**
   * Asynchronously resolves a domain name.
   * If a valid, non-expired entry exists in the cache, this method returns the cached result.
   * If the cache is empty or the entry is expired, it sends a network request to the server, returns the new result to the user, and updates the cache.
   * @param qType The query type. QTYPE_V4 for IPv4, QTYPE_V6 for IPv6, or QTYPE_Auto for both.
   * @param domain The host to resolve, for example, www.example.com.
   * @param callback A callback function that receives an array of resolved IP addresses.
   */
Alipdns.getInstance().getIpsByHostAsync(Alipdns.getInstance().QTYPE_V4, host,(ips:string[]) => {});

/**
   * Synchronously retrieves resolution data from the cache.
   * If the cache is empty, this method immediately returns null and triggers an asynchronous query to populate the cache.
   * If the cache contains a result and expired results are allowed, it returns the stale IP addresses and triggers an asynchronous update.
   * If expired results are not allowed and the cache is expired, it returns null and triggers an asynchronous update.
   * @param qType The query type. QTYPE_V4 for IPv4, QTYPE_V6 for IPv6, or QTYPE_Auto for both.
   * @param domain The host to resolve, for example, www.example.com.
   * @param isAllowExp Specifies whether to allow the method to return expired resolution data.
   * @returns An array of IP addresses from the cache for the specified host.
   */
const result = Alipdns.getInstance().getIpsByHostFromCache(Alipdns.getInstance().QTYPE_V4,host,true);

Integrate with network requests

Use addCustomDnsRule

Resolve the domain with the SDK, then apply the result with the connection.addCustomDnsRule API to set a custom host-to-IP mapping. Example HTTP request:

import { http } from '@kit.NetworkKit';
import connection from '@ohos.net.connection';
import { Alipdns,schemaType,DNSDomainInfo } from '@alidns/httpdns'
import Url from '@ohos.url';

export async function requestWithHttpDns(url: string, options: http.HttpRequestOptions): Promise<http.HttpResponse> {
  let urlObject = Url.URL.parseURL(url);
  const host = urlObject.hostname;
  // ************* Use HTTPDNS to resolve the domain name - START *************
  const result = Alipdns.getInstance().getIpsByHostFromCache(Alipdns.getInstance().QTYPE_V4,host,true);
  // ************* Use HTTPDNS to resolve the domain name - END *************
  // ************* Set DNS rules by using the system API - START *************
  try {
    await connection.removeCustomDnsRule(host);
  } catch (ignored) {
  }
  if (result.length ?? 0 > 0) {
    await connection.addCustomDnsRule(host, result);
  } else {
    console.log(`HTTPDNS resolution returned no result. DNS rule is not set.`);
  }
  // ************* Set DNS rules by using the system API - END *************
  // ************* Initiate a network request by using the system API - START *************
  const httpRequest = http.createHttp();
  return httpRequest.request(url, options);
  // ************* Initiate a network request by using the system API - END *************
}
Important

Custom DNS rules in HarmonyOS

HarmonyOS provides these APIs to customize DNS resolution rules: addCustomDnsRule, removeCustomDnsRule, and clearCustomDnsRules.

addCustomDnsRule adds a custom host-to-IP mapping.

removeCustomDnsRule deletes the rule for a specified host.

clearCustomDnsRules deletes all custom DNS rules.

Set these rules before you initiate network requests.

dnsRules with Remote Communication Kit

To use HTTPDNS with the Remote Communication Kit, resolve the domain first, then configure the dnsRules field. Example fetch request:

import { Alipdns,schemaType,DNSDomainInfo } from '@alidns/httpdns'
import { rcp } from '@kit.RemoteCommunicationKit';
import Url from '@ohos.url';

export async function rcpWithHttpDns(url: string): Promise<rcp.Response> {
  let urlObject = Url.URL.parseURL(url);
  const host = urlObject.hostname;
  // ************* Use HTTPDNS to resolve the domain and get the IP addresses - START *************
  const result = Alipdns.getInstance().getIpsByHostFromCache(Alipdns.getInstance().QTYPE_V4,host,true);
  // ************* Use HTTPDNS to resolve the domain and get the IP addresses - END *************
  const request = new rcp.Request(url, "GET");
  if (result.length ?? 0 > 0) {
      request.configuration = {
        dns: {
          // ************* Set IP addresses by using dnsRules - START *************
          dnsRules: [{ host, port: 443, ipAddresses: result },{ host, port: 80, ipAddresses: result }]
          // ************* Set IP addresses by using dnsRules - END *************
        }
      }
    }
  // ************* Initiate a network request by using the system API - START *************
  const session = rcp.createSession();
  return session.fetch(request);
  // ************* Initiate a network request by using the system API - END *************
}

Domain resolution best practices

Combine pre-resolution with expired responses for optimal performance.

Combining pre-resolution with expired cache entries achieves near-zero-latency resolution. Cached results serve subsequent requests without network round-trips.

1. Pre-resolution

Pre-resolve critical domains at app startup.

In the onCreate() method of EntryAbility, resolve your service domains and cache them in memory.

1. IPv4 only

// For IPv4-only scenarios
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');

    let alipdns = Alipdns.getInstance();
    alipdns.Init(this.context,AccountID,AccessKeyID,AccessKeySecret);
    // Pre-resolve A records (IPv4). 
    alipdns.preLoadDomains(alipdns.QTYPE_V4,['your-domain-to-preload-1.com','your-domain-to-preload-2.com']);
}

2. IPv4 and IPv6

// For scenarios that require IPv6 support
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');

    let alipdns = Alipdns.getInstance();
    alipdns.Init(this.context,AccountID,AccessKeyID,AccessKeySecret);
    // Pre-resolve A and AAAA records (IPv4 and IPv6).  
    alipdns.preLoadDomains(alipdns.QTYPE_Auto,['your-domain-to-preload-1.com','your-domain-to-preload-2.com']);
}

2. Allow expired responses

Prioritize the cache and allow expired records. Even after TTL expiration, cached results return immediately, achieving zero-wait resolution.

1. IPv4 only

    // For IPv4-only scenarios
    
    // ************* Use HTTPDNS to resolve the domain name - START *************
    // Resolve A records (IPv4).
    let finalIps = await this.resolverHost(Alipdns.getInstance().QTYPE_V4,host);
    // ************* Use HTTPDNS to resolve the domain name - END *************
    
  /**
   * HTTPDNS domain resolution (cache-first with network fallback)
   * @param qtype - The DNS query type, such as Alipdns.getInstance().QTYPE_V4 for A records.
   * @param host - The destination domain.
   * @returns An array of successfully resolved IP addresses.
   */
  async resolverHost(qtype: string, host: string): Promise<string[]> {
    // ************* HTTPDNS resolution: Cache with network fallback *************
    let finalIps: string[] = [];

    // 1. Prioritize retrieving the IP address from the cache. The third parameter is set to true to allow returning expired but available records.
    try {
      const cacheResult = Alipdns.getInstance().getIpsByHostFromCache(qtype, host, true);
      // Validate the cache result.
      if (Array.isArray(cacheResult) && cacheResult.length > 0) {
        finalIps = cacheResult;
        console.log(`pdns: [Cache hit] Domain ${host} resolved to: ${finalIps.join(', ')}`);
      } else {
        console.log(`pdns: [Cache miss/invalid] Domain ${host}. Initiating network request.`);
      }
    } catch (e) {
      console.warn(`pdns: Cache query exception: ${e?.message || e}`);
    }

    // 2. If the cache is invalid, initiate a network request.
    if (finalIps.length === 0) {
      try {
        finalIps = await this.getIpsFromNetwork(qtype, host);
        if (finalIps.length > 0) {
          console.log(`pdns: [Network request successful] Domain ${host} resolved to: ${finalIps.join(', ')}`);
        } else {
          console.warn(`pdns: [Network request] Domain ${host} returned an empty result.`);
        }
      } catch (err) {
        console.error(`pdns: [Network request failed] Domain ${host}: ${err?.message || JSON.stringify(err)}`);
        // Keep finalIps as an empty array and fall back to the system DNS.
      }
    }
    return finalIps;
  }

  // If no cache is available, send a network request to resolve the domain and get the IP address.
  getIpsFromNetwork(qtype: string, domain: string): Promise<string[]> {
    return new Promise((resolve) => {
      Alipdns.getInstance().getIpsByHostAsync(qtype, domain, (ips: string[]) => {
        if (Array.isArray(ips)) {
          resolve(ips);
        } else {
          resolve([]);
        }
      });
    });
  }

2. IPv4 and IPv6

    // For scenarios that require IPv6 support
    
    // ************* Use HTTPDNS to resolve the domain name - START *************
    // Resolve A and AAAA records (IPv4 and IPv6).
    let finalIps = await this.resolverHost(Alipdns.getInstance().QTYPE_Auto,host);
    // ************* Use HTTPDNS to resolve the domain name - END *************
    
  /**
   * HTTPDNS domain resolution (cache-first with network fallback)
   * @param qtype - The DNS query type, such as Alipdns.getInstance().QTYPE_Auto for A and AAAA records.
   * @param host - The destination domain.
   * @returns An array of successfully resolved IP addresses.
   */
  async resolverHost(qtype: string, host: string): Promise<string[]> {
    // ************* HTTPDNS resolution: Cache with network fallback *************
    let finalIps: string[] = [];

    // 1. Prioritize retrieving the IP address from the cache. The third parameter is set to true to allow returning expired but available records.
    try {
      const cacheResult = Alipdns.getInstance().getIpsByHostFromCache(qtype, host, true);
      // Validate the cache result.
      if (Array.isArray(cacheResult) && cacheResult.length > 0) {
        finalIps = cacheResult;
        console.log(`pdns: [Cache hit] Domain ${host} resolved to: ${finalIps.join(', ')}`);
      } else {
        console.log(`pdns: [Cache miss/invalid] Domain ${host}. Initiating network request.`);
      }
    } catch (e) {
      console.warn(`pdns: Cache query exception: ${e?.message || e}`);
    }

    // 2. If the cache is invalid, initiate a network request.
    if (finalIps.length === 0) {
      try {
        finalIps = await this.getIpsFromNetwork(qtype, host);
        if (finalIps.length > 0) {
          console.log(`pdns: [Network request successful] Domain ${host} resolved to: ${finalIps.join(', ')}`);
        } else {
          console.warn(`pdns: [Network request] Domain ${host} returned an empty result.`);
        }
      } catch (err) {
        console.error(`pdns: [Network request failed] Domain ${host}: ${err?.message || JSON.stringify(err)}`);
        // Keep finalIps as an empty array and fall back to the system DNS.
      }
    }
    return finalIps;
  }

  // If no cache is available, send a network request to resolve the domain and get the IP address.
  getIpsFromNetwork(qtype: string, domain: string): Promise<string[]> {
    return new Promise((resolve) => {
      Alipdns.getInstance().getIpsByHostAsync(qtype, domain, (ips: string[]) => {
        if (Array.isArray(ips)) {
          resolve(ips);
        } else {
          resolve([]);
        }
      });
    });
  }

On-premises DNS

The HTTPDNS HarmonyOS SDK v2.0.0 and later supports on-premises DNS deployment.

On-premises DNS suits scenarios requiring data compliance and custom resolution policies, such as finance, government, and large-scale web services. The SDK supports four deployment modes: public cloud only, on-premises only, and two hybrid primary/standby configurations.

Core capabilities

  • Private deployment: Configure endpoints with IPv4, IPv6, or hostnames.

  • Mutual authentication: Requests are signed with customer-specific accessKeyId and accessKeySecret.

  • Circuit breaking and health check: After three consecutive failures, the SDK triggers circuit breaking and probes the node every minute using the healthCheckDomain. The node is re-enabled after recovery.

  • Intelligent fallback: The SDK switches to the standby DNS after the primary exceeds the failure threshold, ensuring high availability.

  • Seamless API compatibility: The resolution API is identical for public cloud and on-premises DNS. No business logic changes required.

Configuration

1. Public cloud DNS only

For standard SaaS users without on-premises DNS.

let alipdns = Alipdns.getInstance();
alipdns.Init(this.context,AccountID,AccessKeyID,AccessKeySecret);

2. On-premises DNS only

For customers who rely entirely on on-premises DNS.

let alipdns = Alipdns.getInstance();
alipdns.InitFusionDNS(this.context,['1.1.X.X','2.2.X.X'],null, null,'443','your-health-check-domain.com','your-private-accessKeyId','your-private-accessKeySecret');

3. Public cloud primary, on-premises standby

Falls back to on-premises DNS when Alibaba Cloud public cloud DNS resolution fails.

let alipdns = Alipdns.getInstance();

// Primary: public cloud DNS
alipdns.Init(this.context,AccountID,AccessKeyID,AccessKeySecret);
    
// Standby: on-premises DNS
alipdns.InitFusionDNS(this.context,['1.1.X.X','2.2.X.X'],null, null,'443','your-health-check-domain.com','your-private-accessKeyId','your-private-accessKeySecret');

4. On-premises primary, public cloud standby

Falls back to Alibaba Cloud public cloud DNS when on-premises DNS resolution fails.

let alipdns = Alipdns.getInstance();
    
// Primary: on-premises DNS
alipdns.InitFusionDNS(this.context,['1.1.X.X','2.2.X.X'],null, null,'443','your-health-check-domain.com','your-private-accessKeyId','your-private-accessKeySecret');

// Standby: public cloud DNS
alipdns.Init(this.context,AccountID,AccessKeyID,AccessKeySecret);

New service APIs

The SDK provides these APIs for on-premises DNS configuration, security, and automatic primary/standby fallback.

1. On-premises DNS endpoints and credentials

/** This method is for private deployments that use on-premises DNS. You do not need to call this method if you use only public DNS.
     *
     * Sets the server addresses and authentication credentials for the on-premises DNS.
     * You pass the addresses and credentials of your on-premises DNS servers through this API.
     * The SDK uses this information to initiate requests.
     * @param ctx The context.
     * @param serverIpv4Arr An array of IPv4 addresses. This can be null.
     * @param serverIpv6Arr An array of IPv6 addresses. This can be null.
     * @param serverHostArr An array of hostnames. This can be null.
     * @param port The service port, such as "443". If you pass null, the default port "443" is used.
     * @param healthCheckDomain The domain for health checks after circuit breaking. When a resolution service fails more than three consecutive times, circuit breaking is triggered, and the service's IP address enters the healthCheck state. Subsequent requests are not routed to this service.
     *                          A timer then probes the service every minute by resolving the healthCheckDomain. If a probe succeeds, the IP address is marked as available and can receive requests again.
     * @param accessKeyId The private AccessKey ID for authentication.
     * @param accessKeySecret The private AccessKey Secret for authentication.
     */
InitFusionDNS(
    ctx:Context,
    ipv4: string[] | null,
    ipv6: string[] | null,
    host: string[] | null,
    port: string | null,
    healthCheckDomain: string,
    accessKeyId: string,
    accessKeySecret: string
  )

2. Automatic fallback threshold

/** Use this method to set the failure threshold that triggers an automatic fallback from the primary to the standby DNS. This method is only needed if you have configured both public cloud and on-premises DNS.
   *
   * @param fallbackThreshold The number of failures. The default is 4 if the primary is a public cloud DNS, and 2 if the primary is an on-premises DNS.
   *  Valid values: 0 to 4. A value of 0 indicates an immediate fallback.
   */
   
setFallbackThreshold(fallbackThreshold:number);