This document describes how to integrate and use the HTTPDNS iOS SDK.
Overview
The iOS SDK encapsulates the DoH JSON API for HTTPDNS, providing functions for domain name resolution and an efficient domain name caching feature based on Time-to-Live (TTL) and Least Recently Used (LRU) policies. Using this SDK, you can easily integrate HTTPDNS into your iOS apps to resolve domain name resolution exceptions and implement precise, low-cost scheduling for domain name resolution.
Starting from iOS 14, the system natively supports two standard encrypted DNS protocols: DNS over TLS (DoT) and DNS over HTTPS (DoH). For more information about how to set Mobile Resolution HTTPDNS as the default encrypted DNS resolver, see iOS14 native encrypted DNS solution.
The SDK has the following advantages:
Simple and easy to use:
You only need to integrate the SDK to access the HTTPDNS service. The integration method is simple and provides a more convenient resolution service.
Zero latency:
The SDK internally implements an LRU caching mechanism, caching the IP addresses from each domain name resolution to the local storage. It also actively updates expired cache to ensure the cache is timely and effective, helping users achieve zero latency for domain name resolution.
For more information about how to use this SDK, see the alidns_ios_demo sample project source code.
SDK integration
Import the SDK
Integrate using CocoaPods
In the Podfile, specify the repository location. Do not omit the Master repository.
source 'https://github.com/CocoaPods/Specs.git' source 'https://github.com/aliyun/aliyun-specs.git'Add a dependency for the project target.
pod 'AlicloudPDNS'
Integrate manually
For more information, see SDK download to obtain the iOS SDK.
After obtaining the SDK's
pdns-sdk-ios.framework, manually integrate it into your project.Import system libraries:
Foundation.framework
SystemConfiguration.framework
CoreFoundation.framework
CoreTelephony.framework
Add the -ObjC flag in the Other linker flags section of the project's Build Settings.
SDK initialization
You need to first register your application in the console, obtain the unique identifier and authentication parameters for the application, and then initialize the SDK after integration.
To better use the SDK and avoid situations where IP addresses cannot be resolved, please initialize the SDK as early as possible.
Initialize the SDK in application:didFinishLaunchingWithOptions:.
DNSResolver *resolver = [DNSResolver share]; //setAccountId:@"******": Fill in the Account ID displayed on the "Access Configuration" page in the console //andAccessKeyId:@"********": Fill in the AccessKey ID of the key you created in the console's "Access Configuration" //andAccesskeySecret:@"********": Fill in the AccessKey Secret of the key you created in the console's "Access Configuration" [resolver setAccountId:@"******" andAccessKeyId:@"********" andAccesskeySecret:@"********"]; //Specify domains for automatic expired cache updates, currently limited to a maximum of 10 domains in the array [resolver setKeepAliveDomains:@[@"user-specified domain 1",@"user-specified domain 2"]]; //Preload domains that may need to be resolved later [resolver preloadDomains:@[@"domain 1", @"domain 2", @"domain 3"] complete:^{ //All domains preloading completed }];API introduction
Common settings
1. Account ID and authentication
Required parameters. After you register your application in the console, the console will generate a unique identifier Account ID for this application. The authentication function ensures user identity security and prevents unauthorized third-party use. Users should refer to Create key to create an AccessKey in the console, and set it in the app using the following code:
//setAccountId:@"******": Fill in the Account ID displayed on the "Access Configuration" page in the console //andAccessKeyId:@"********": Fill in the AccessKey ID of the key you created in the console's "Access Configuration" //andAccesskeySecret:@"********": Fill in the AccessKey Secret of the key you created in the console's "Access Configuration" [[DNSResolver share] setAccountId:@"******" andAccessKeyId:@"********" andAccesskeySecret:@"********"];To avoid leaking parameters such as Account ID/AccessKey ID/AccessKey Secret in logs or data generated during app operation, it is recommended to disable SDK debugging logs in the release version.
The sample code directly passes Account ID, AccessKey ID, and AccessKey Secret in properties for demonstration purposes. Since these parameters are closely related to metering and billing, to prevent information leakage due to malicious decompilation, you should avoid passing plaintext directly in production environments. For example, you can pre-encode or encrypt the plaintext, and then decode or decrypt the encoded or encrypted plaintext when passing values. At the same time, it is recommended that you obfuscate and reinforce your app code. Otherwise, your Account ID, AccessKey ID, and AccessKey Secret may be obtained by third parties through decompilation.
2. Resolution protocol settings
The SDK supports setting the DNS resolution request protocol type. You can choose to resolve through HTTP or HTTPS protocol, which can be set through the scheme property.
By default, the SDK uses and recommends the HTTPS protocol for resolution because HTTPS provides better security. HTTPDNS is billed based on the number of HTTP resolution requests. HTTPS resolution requests are billed at five times the rate of HTTP resolution requests. You can select a scheme type based on your requirements. You can set the property as follows:
[DNSResolver share].scheme = DNSResolverSchemeHttps;3. Set whether to enable caching
The SDK can be set to enable caching functionality. If caching is enabled, after resolving a domain name for the first time, subsequent resolutions will prioritize getting data from the cache, which can greatly improve resolution speed.
The SDK enables caching by default. To disable caching, you need to set it using the following code:
[DNSResolver share].cacheEnable=NO;4. Set domain name cache retention
When caching is enabled in the SDK, you can set cache retention for certain domains. If this feature is enabled, the SDK will automatically update the expired cache for these domains, ensuring that user cache data is updated in a timely manner. However, this may lead to an increase in the number of domain resolutions and client traffic consumption. If this feature is not set, the SDK will not automatically update expired caches, and will only update the cache when the user calls the resolution method again. To set cache retention for certain domains, use the following code:
//Currently limited to a maximum of 10 domains in the array [[DNSResolver share] setKeepAliveDomains:@[@"www.taobao.com",@"www.aliyun.com"]];Advantages:
Can update records in a timely manner (before TTL expires).
Combined with preloading, it can reduce the first resolution delay (0ms).
Disadvantages: Using TTL *75% as the timing for re-requests will incur additional costs.
5. Pre-resolution
Since the SDK can be set to enable caching, after the first resolution of a domain name generates a cache, subsequent resolutions of this domain name can achieve 0 latency. Therefore, it is recommended to pre-resolve domains that may need to be resolved in the app after the app starts.
Code example:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. DNSResolver *resolver = [DNSResolver share]; //setAccountId:@"******": Fill in the Account ID displayed on the "Access Configuration" page in the console //andAccessKeyId:@"********": Fill in the AccessKey ID of the key you created in the console's "Access Configuration" //andAccesskeySecret:@"********": Fill in the AccessKey Secret of the key you created in the console's "Access Configuration" [resolver setAccountId:@"******" andAccessKeyId:@"********" andAccesskeySecret:@"********"]; resolver.cacheEnable = YES; //Preload domains that may need to be resolved later [resolver preloadDomains:@[@"domain 1", @"domain 2", @"domain 3"] complete:^{ //All domains preloading completed }]; return YES; }Other advanced settings
1. Set whether to use a server-side IPv6 address
The HTTPDNS service supports IPv4 and IPv6 dual-stack access. By default, the SDK uses an IPv4 address to access a DNS server for resolution.
To access DNS servers for resolution through IPv6 address (the current network needs to support IPv6), you need to set it using the following code:
[DNSResolver share].ipv6Enable = YES;2. Short mode
The DoH JSON API of HTTPDNS returns data in either the full JSON format or a brief IP address array format. By default, the SDK uses the full JSON format.
To set it to brief IP array format, you need to use the following code:
[DNSResolver share].shortEnable = YES;3. Set the cache size
If the SDK has enabled caching, you can customize the cache quantity (supported range between 100 and 500).
The default cache quantity of the SDK is 100 domain names. To customize the cache quantity, you can set it through the cacheCountLimit property:
[DNSResolver share].cacheCountLimit = 200;4. Set whether to enable IP address probing
The SDK can be set to enable IP speed testing. If IP speed testing is enabled, the resolution result will prioritize returning the fastest IP address, and the array will be sorted from fastest to slowest based on the speed test results.
The SDK does not enable IP speed testing by default. To enable IP speed testing, you need to set it using the following code:
[DNSResolver share].speedTestEnable=YES;5. Set the IP address probing method
The SDK can set the method for IP speed testing. If IP speed testing is enabled and this parameter is set to 0, ICMP detection will be used. If this parameter is set to 80, 443, or other supported port numbers, socket-specific port detection will be used.
The default value for this parameter is 0. To set socket-specific port detection, you need to use the following code:
[DNSResolver share].speedPort = 80;6. Configuring ISP-specific domain name caching
The SDK can be set to enable ISP network-based domain cache differentiation. If enabled, domain cache data will be stored separately in different network environments without affecting each other. If not enabled, the same domain cache data will be used across different networks.
The SDK does not enable ISP network-based domain cache differentiation by default. To enable this feature, you need to set it using the following code:
[DNSResolver share].ispEnable = YES;7. Setting maximum TTL for negative cache
The SDK can set the maximum TTL time for negative cache (invalid cache where the domain name does not have a configured IP address, resulting in no IP returned in the resolution result). If this time is set, it will limit the maximum TTL of negative cache to not exceed the set time.
The default value for this parameter is 30s. To set the maximum TTL time for negative cache, you need to use the following code:
[DNSResolver share].maxNegativeCache = 30;8. Setting maximum cache TTL
The SDK can set the maximum TTL time for cache. If this time is set, it will limit the maximum TTL of cache to not exceed the set time.
The default value for this parameter is 3600s. To set the maximum TTL time for cache, you need to use the following code:
[DNSResolver share].maxCacheTTL= 3600;9. Setting whether to enable immutable cache
[DNSResolver share].immutableCacheEnable = NO;// Immutable cache is disabled by defaultThe SDK internally has three cache update mechanisms:
Immutable cache: Once this feature is enabled, the cache will always be considered valid during the app's runtime, and cache expiration checks and updates will no longer be performed. This can minimize the number of user resolutions to the greatest extent.
Setting method:
[DNSResolver share].immutableCacheEnable = YESActive cache update: Active updating ensures that resolution hits the latest resolution record value in the cache. When the authoritative resolution of a domain name changes, this mechanism ensures that resolution requests hit the cache, thereby reducing DNS latency, while also ensuring that the cached resolution records are usually the latest record values. Currently limited to a maximum of 10 domains in the array.
Setting method:
[[DNSResolver share] setKeepAliveDomains:@[@"user-specified domain 1",@"user-specified domain 2"]]Passive cache update: When calling the following two methods to obtain resolution results, the cache will be passively updated:
- (void)getIpv4DataWithDomain:(NSString *)domain complete:(void(^)(NSArray<NSString *> *dataArray))completemethod: Obtains the IPv4 address array after domain name resolution. If the cache is non-empty and within the TTL validity period, it will directly return the cached result. Otherwise, it will first obtain the latest resolution result through a network request, then return that result and update the cache. This method is often used in scenarios with high accuracy requirements for resolution results.- (NSArray<NSString *> *)getIpv4ByCacheWithDomain:(NSString *)domain andExpiredIPEnabled:(BOOL)enablemethod: Obtains IPv4 resolution results from the cache. This method will decide whether to return expired resolution results from the cache based on the value of theenableparameter.Parameter description: If
enableisYES, it will return old records even if the cache has expired (returnsnilif the cache is empty), and update the cache through an asynchronous request. If it isNO, it will returnnilwhen the cache has expired or is empty, and update the cache through an asynchronous request.
10. timeout
The timeout property is the timeout for domain name resolution. The default timeout is 3s. Users can customize the timeout, and it is recommended to set it between 2 and 5 seconds.
Service API
Code example:
/// Pre-resolves domain information, can be called when the program starts, resolution results will be stored in cache to speed up subsequent domain name resolution /// Automatically detects network environment (ipv4-only, ipv6-only, ipv4 and ipv6 dual-stack) to resolve IPs suitable for the current network environment /// @param domainArray Domain array /// @param complete Callback after resolution is complete - (void)preloadDomains:(NSArray<NSString *> *)domainArray complete:(void(^)(void))complete; /// Gets the IP array after domain name resolution, automatically detects network environment (ipv4-only, ipv6-only, ipv4 and ipv6 dual-stack) to get IPs suitable for the current network environment, /// If caching is enabled, it will prioritize returning data from the cache. If there is no cache or the cache has expired, it will obtain the corresponding IP through a network request. If caching is not enabled, it will directly obtain the corresponding IP through a network request. /// @param domain Domain name /// @param complete Callback (all IP addresses) - (void)getIpsDataWithDomain:(NSString *)domain complete:(void(^)(NSArray<NSString *> *dataArray))complete; /// Automatically detects network environment (ipv4-only, ipv6-only, ipv4 and ipv6 dual-stack) to directly get IP arrays suitable for the current network environment from the cache, without waiting. /// If there is no cache, returns nil; if there is a cache and enable is set to YES, it will return cache data to the user, and if the cache data has expired, it will asynchronously resolve the domain name to update the cache data; if there is a cache and enable is set to NO, it will return nil to the user when the cache has expired and asynchronously resolve the domain name to update the cache data. /// @param domain Domain name /// @param enable Whether to allow returning expired IPs - (NSArray<NSString *> *)getIpsByCacheWithDomain:(NSString *)domain andExpiredIPEnabled:(BOOL)enable; /// Gets the IPv4 information array after domain name resolution /// If caching is enabled, it will prioritize returning data from the cache. If there is no cache or the cache has expired, it will obtain the corresponding IP through a network request. If caching is not enabled, it will directly obtain the corresponding IP through a network request. /// @param domain Domain name /// @param complete Callback (all domain information) - (void)getIpv4InfoWithDomain:(NSString *)domain complete:(void(^)(NSArray<DNSDomainInfo *> *domainInfoArray))complete; /// Gets the IPv6 information array after domain name resolution /// If caching is enabled, it will prioritize returning data from the cache. If there is no cache or the cache has expired, it will obtain the corresponding IP through a network request. If caching is not enabled, it will directly obtain the corresponding IP through a network request. /// @param domain Domain name /// @param complete Callback (all domain information) - (void)getIpv6InfoWithDomain:(NSString *)domain complete:(void(^)(NSArray<DNSDomainInfo *> *domainInfoArray))complete; /// Gets the IPv4 information after domain name resolution /// If caching is enabled, it will prioritize returning data from the cache. If there is no cache or the cache has expired, it will obtain the corresponding IP through a network request. If caching is not enabled, it will directly obtain the corresponding IP through a network request. /// @param domain Domain name /// @param complete Callback (a random one from all domain information) - (void)getRandomIpv4InfoWithDomain:(NSString *)domain complete:(void(^)(DNSDomainInfo *domainInfo))complete; /// Gets the IPv6 information after domain name resolution /// If caching is enabled, it will prioritize returning data from the cache. If there is no cache or the cache has expired, it will obtain the corresponding IP through a network request. If caching is not enabled, it will directly obtain the corresponding IP through a network request. /// @param domain Domain name /// @param complete Callback (a random one from all domain information) - (void)getRandomIpv6InfoWithDomain:(NSString *)domain complete:(void(^)(DNSDomainInfo *domainInfo))complete; /// Gets the IPv4 address array after domain name resolution /// If caching is enabled, it will prioritize returning data from the cache. If there is no cache or the cache has expired, it will obtain the corresponding IP through a network request. If caching is not enabled, it will directly obtain the corresponding IP through a network request. /// @param domain Domain name /// @param complete Callback (all IP addresses) - (void)getIpv4DataWithDomain:(NSString *)domain complete:(void(^)(NSArray<NSString *> *dataArray))complete; /// Gets the IPv6 address array after domain name resolution /// If caching is enabled, it will prioritize returning data from the cache. If there is no cache or the cache has expired, it will obtain the corresponding IP through a network request. If caching is not enabled, it will directly obtain the corresponding IP through a network request. /// @param domain Domain name /// @param complete Callback (all IP addresses) - (void)getIpv6DataWithDomain:(NSString *)domain complete:(void(^)(NSArray<NSString *> *dataArray))complete; /// Gets the IPv4 address after domain name resolution /// If caching is enabled, it will prioritize returning data from the cache. If there is no cache or the cache has expired, it will obtain the corresponding IP through a network request. If caching is not enabled, it will directly obtain the corresponding IP through a network request. /// @param domain Domain name /// @param complete Callback (a random one from all IP addresses) - (void)getRandomIpv4DataWithDomain:(NSString *)domain complete:(void(^)(NSString *data))complete; /// Gets the IPv6 address after domain name resolution /// If caching is enabled, it will prioritize returning data from the cache. If there is no cache or the cache has expired, it will obtain the corresponding IP through a network request. If caching is not enabled, it will directly obtain the corresponding IP through a network request. /// @param domain Domain name /// @param complete Callback (a random one from all IP addresses) - (void)getRandomIpv6DataWithDomain:(NSString *)domain complete:(void(^)(NSString *data))complete; /// Pre-resolves domain IPv4 information, can be called when the program starts, stores resolution results in cache to speed up subsequent domain name resolution /// @param domainArray Domain array /// @param complete Callback after resolution is complete - (void)preloadIpv4Domains:(NSArray<NSString *> *)domainArray complete:(void(^)(void))complete; /// Pre-resolves domain IPv6 information, can be called when the program starts, stores resolution results in cache to speed up subsequent domain name resolution /// @param domainArray Domain array /// @param complete Callback after resolution is complete - (void)preloadIpv6Domains:(NSArray<NSString *> *)domainArray complete:(void(^)(void))complete; /// Directly gets IPv4 resolution results from the cache, without waiting. /// If there is no cache, returns nil; if there is a cache and enable is set to YES, it will return cache data to the user, and if the cache data has expired, it will asynchronously resolve the domain name to update the cache data; if there is a cache and enable is set to NO, it will return nil to the user when the cache has expired and asynchronously resolve the domain name to update the cache data. /// @param domain Domain name /// @param enable Whether to allow returning expired IPs - (NSArray<NSString *> *)getIpv4ByCacheWithDomain:(NSString *)domain andExpiredIPEnabled:(BOOL)enable; /// Directly gets IPv6 resolution results from the cache, without waiting. /// If there is no cache, returns nil; if there is a cache and enable is set to YES, it will return cache data to the user, and if the cache data has expired, it will asynchronously resolve the domain name to update the cache data; if there is a cache and enable is set to NO, it will return nil to the user when the cache has expired and asynchronously resolve the domain name to update the cache data. /// @param domain Domain name /// @param enable Whether to allow returning expired IPs - (NSArray<NSString *> *)getIpv6ByCacheWithDomain:(NSString *)domain andExpiredIPEnabled:(BOOL)enable; ///Statistics information collection -(NSArray *)getRequestReportInfo;API usage examples
1. Configure basic information
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. //Unique initialization method DNSResolver *resolver = [DNSResolver share]; //setAccountId:@"******": Fill in the Account ID displayed on the "Access Configuration" page in the console //andAccessKeyId:@"********": Fill in the AccessKey ID of the key you created in the console's "Access Configuration" //andAccesskeySecret:@"********": Fill in the AccessKey Secret of the key you created in the console's "Access Configuration" [resolver setAccountId:@"******" andAccessKeyId:@"********" andAccesskeySecret:@"********"]; //Specify domains for automatic expired cache updates, currently limited to a maximum of 10 domains in the array [resolver setKeepAliveDomains:@[@"user-specified domain 1",@"user-specified domain 2"]]; //Preload domains that may need to be resolved later, can obtain resolution results in advance and store them in cache [resolver preloadDomains:@[@"domain 1", @"domain 2", @"domain 3"] complete:^{ //All domains preloading completed }]; return YES; }2. Domain Name Resolution Interface
The SDK provides multiple domain resolution methods for users to choose and use, which can be viewed in the DNSResolver.h header file. Below is an example of one of the resolution methods that automatically distinguishes network environments (IPv4-only, IPv6-only, IPv4 and IPv6 dual-stack).
Interface declaration:
/// Gets the IP array after domain name resolution, automatically distinguishes network environment (ipv4-only, ipv6-only, ipv4 and ipv6 dual-stack) to get IPs suitable for the current network environment /// If caching is enabled, it will prioritize returning data from the cache. If there is no cache or the cache has expired, it will obtain the corresponding IP through a network request. If caching is not enabled, it will directly obtain the corresponding IP through a network request. /// @param domain Domain name /// @param complete Callback (all IP addresses) - (void)getIpsDataWithDomain:(NSString *)domain complete:(void(^)(NSArray<NSString *> *dataArray))complete;Interface call example:
[[DNSResolver share] getIpsDataWithDomain:@"www.taobao.com" complete:^(NSArray<NSString *> *dataArray) { //dataArray is the IP address array corresponding to the domain name www.taobao.com if (dataArray.count > 0) { //TODO: Use IP address for URL connection } }];3. Retrieving resolution results directly from the cache
Interface declaration:
/// Automatically distinguishes network environment (ipv4-only, ipv6-only, ipv4 and ipv6 dual-stack) to directly get IP arrays suitable for the current network environment from the cache, without waiting. /// If there is no cache, returns nil; if there is a cache and enable is set to YES, it will return cache data to the user, and if the cache data has expired, it will asynchronously resolve the domain name to update the cache data; if there is a cache and enable is set to NO, it will return nil to the user when the cache has expired and asynchronously resolve the domain name to update the cache data. /// @param domain Domain name /// @param enable Whether to allow returning expired IPs - (NSArray<NSString *> *)getIpsByCacheWithDomain:(NSString *)domain andExpiredIPEnabled:(BOOL)enable;Call example:
NSArray *result = [[DNSResolver share] getIpsByCacheWithDomain:@"domain name" andExpiredIPEnabled:YES]; //Get cache result if (result.count > 0) { //TODO: Use IP address for URL connection }Note: Directly obtaining cache results from the cache is faster, but the result will be nil if there is no cache, or if there is a cache but the cached resolution result has expired and enable is NO.
4. Delete the Cache
Interface declaration:
///hostArray is the array of host domain names that need to be cleared. To clear all data, pass nil or an empty array -(void)clearHostCache:(NSArray <NSString *>*)hostArray;Call example:
[[DNSResolver share] clearHostCache:@[@"domain 1", @"domain 2"]];5. Collect statistics
Interface declaration:
///Statistics information collection -(NSArray *)getRequestReportInfo;Call example:
NSArray *array = [[DNSResolver share] getRequestReportInfo];Data format:
( { avgRtt = "1"; // Average domain resolution time in ms cacheDnsNum = 0; // Number of cache hits domain = "www.taobao.com"; // Domain name being resolved gobackLocaldnsNum = 0; // Number of times downgraded to LocalDNS localErro = 0; // Number of LocalDNS resolution failures maxRtt = "60"; // Maximum domain resolution time in ms noPermissionErro = 0; // Number of user authentication failures noResponseErro = 0; // Number of request timeouts with no response requestPDnsNum = 1; // Number of recursive queries sp = "China Mobile"; // ISP name successNum = 1; // Number of successful resolutions timeoutErro = 0; // Number of network timeout errors type = 28; // IP type, 1 represents IPv4, 28 represents IPv6 urlParameterErro = 0; // Number of request parameter format errors urlPathErro = 0; // Number of URL errors } ...... );Notes
pdns-sdk-ios.frameworksupports a minimum version of iOS 9.0.When using HTTP protocol for requests, you need to set
App Transport Security Settings->Allow Arbitrary LoadstoYESinInfo.plist.After you obtain the IP address of a domain name through HTTPDNS, the client can use this IP address to send service requests. The Host field in the HTTP request header must be set to the original domain name.
For example:
//ip is the IP address resolved from the original domain name NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@", ip]]; NSMutableURLRequest *mutableReq = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval: 10]; //Set host [mutableReq setValue:@"original domain name" forHTTPHeaderField:@"host"];To ensure normal business operations, when no IP is obtained for a domain name through the SDK, developers need to use the original domain name address for requests as a fallback. Example code is as follows:
NSArray *array = [[DNSResolver share] getIpsByCacheWithDomain:@"original domain name" andExpiredIPEnabled:YES]; NSString *ip = array.firstObject; if (ip.length > 0) { //Replace the host in the URL with IP for interface requests }else{ //Add fallback handling (use the original URL for interface requests) }If an intermediate HTTP proxy exists, the request line in client-initiated requests uses an absolute path URL. If you enable HTTPDNS and use an IP-based URL for access, the intermediate proxy identifies your IP information and passes it as the real host information to the target server. In this case, the target server cannot process HTTP requests that do not contain the real host information. We recommend that you check whether a network proxy is enabled on the current device. If a proxy is enabled, do not use HTTPDNS for domain name resolution.