全部产品
云市场

iOS SDK 开发手册

更新时间:2020-02-18 11:59:06

1. 前言

本文档介绍了HTTPDNS iOS SDK的使用方式。

HTTPDNS是阿里云面向移动开发者提供的移动端DNS解析服务。通过该SDK,开发者可以在自己的iOS APP中获得可靠、实时、精准的DNS解析服务,彻底解决传统DNS面临的域名劫持、解析时延长、调度不精准等问题。

您可以通过获取 alicloud-ios-demo 工程源码获得HTTPDNS服务的使用例程。

1.1 手动集成SDK

  • 您可以通过上述 GitHub demo获取 HTTPDNS SDK
  • 您可以通过访问移动服务APP列表页(https://emas.console.aliyun.com/ 若您第一次访问,请创建 APP),勾选下图红框中的 HTTPDNS 组件获取 SDK。

ams

1.2 Pod集成

  • 指定Master仓库和阿里云仓库:
  1. source 'https://github.com/CocoaPods/Specs.git'
  2. source 'https://github.com/aliyun/aliyun-specs.git'
  • 添加依赖:
  1. pod 'AlicloudHTTPDNS', '~> 1.7.1'

(~>为模糊指定版本号方式,~> 1.7.1表明引用版本位于1.7.1 <= version < 1.8.0之间的最新版本SDK,用户可参考Podfile Syntax Reference,根据项目需要指定SDK版本。)

1.3 修改编译选项

Target->Linking->Other Linker Flags中添加 -ObjC-lz 选项。

不知道如何修改编译选项?请参考:

如何修改编译选项

注意:请注意 -ObjC 的大小写。


2. 应用程序配置与初始化

HTTPDNS iOS SDK,自v1.1.0版本已全面支持苹果ATS要求,无需在Info.plist中配置ATS。

2.1 依赖

系统公共库:

  • libsqlite3.0.tbd
  • libresolv.tbd
  • CoreTelephony.framework
  • SystemConfiguration.framework

AMS组件包

  • AlicloudHttpDNS.framework
  • UTDID.framework
  • AlicloudUtils.framework
  • UTMini.framework

如果遇到 UTDID 冲突可参考:《阿里云-移动云产品SDK UTDID冲突解决方案》

2.2 获取服务实例

一、建议使用 SDK 自动初始化接口, 结合 AliyunEmasServices-Info.plist 配置文件使用 。AliyunEmasServices-Info.plist 配置文件,包含 SDK 初始化所需的配置信息,用户只需要调用 autoInit 初始化接口即可完成 SDK 初始化 ,无需手动输入配置信息
  1. - (instancetype)autoInit ;
  2. 示例:
  3. HttpDnsService *httpdns = [[HttpDnsService alloc] autoInit];
二、或者也可以通过以下方式获取实例 :
  1. // 设置 HTTPDNS AccoutID ,当您开通 HTTPDNS 服务时,您可以在控制台获取到您对应的 Accout ID 信息
  2. HttpDnsService *httpdns = [[HttpDnsService alloc] initWithAccountID::*****];

accountidimage


下载 SDK 统一 配置文件 AliyunEmasServices-Info.plist
  • 在控制台产品概览页面,下载 App 的 配置文件 AliyunEmasServices-Info.plist,如下图所示:unit_config_pic

  • Xcode 中,把下载的 AliyunEmasServices-Info.plist 文件拖入对应 App Target 下即可,在弹出框勾选 Copy items if needed

2.3 设置预解析域名

在您初始化程序时,可以选择性地预先向HTTPDNS SDK中注册您后续可能会使用到的域名,以便SDK提前解析,减少后续解析域名时请求的时延。您只需调用以下接口:

  1. NSArray * hosts = [[NSArray alloc] initWithObjects:@"www.taobao.com", @"www.aliyun.com", nil];
  2. [httpdns setPreResolveHosts:hosts];

注意预解析接口设置的同时会实时触发异步网络请求,应该在代码逻辑上确保调用预解析接口时,已经进行了必备的初始化设置。

比如:setHTTPSRequestEnabled: 需要在预解析接口之前调用,否则会导致预解析的相关 IP 采用 HTTP请求。

2.4 启用鉴权功能

首先需要在控制台开启鉴权功能:

open auth feature

在控制台开启鉴权功能后,SDK 需要更改初始化方式,改用下面的方法进行初始化,即可开启鉴权:

  1. /*!
  2. * @brief 启用鉴权功能的初始化接口
  3. * @details 初始化、开启鉴权功能,并设置 HTTPDNS 服务 Account ID,鉴权功能对应的 secretKey。
  4. * 您可以从控制台获取您的 Account ID 、secretKey 信息。
  5. * 此方法会初始化为单例。
  6. * @param accountId 您的 HTTPDNS Account ID
  7. * @param secretKey 鉴权对应的 secretKey
  8. */
  9. - (instancetype)initWithAccountID:(int)accountID secretKey:(NSString *)secretKey;

目前 iOS SDK 鉴权时间戳过期时间统一为 10 分钟,鉴权机制细节可以参考《HTTPDNS > 开发指南 > HTTP API手册 > 鉴权解析接口》

同时鉴权功能,支持对设备的时间进行校对,对应的方法为:

  1. /*!
  2. * @brief 校正 App 签名时间
  3. * @param authCurrentTime 用于校正的时间戳,正整数。
  4. * @details 不进行该操作,将以设备时间为准,为`(NSUInteger)[[NSDate date] timeIntervalSince1970]`。进行该操作后,如果有偏差,每次网络请求都会对设备时间进行矫正。
  5. * @attention 校正操作在 APP 的一个生命周期内生效,APP 重启后需要重新设置才能重新生效。可以重复设置。
  6. */
  7. - (void)setAuthCurrentTime:(NSUInteger)authCurrentTime;

3. 服务API与使用示例

3.1 服务API

首先在AliyunEmasServices-Info.plist 获取您的 accountID 和 secretKey 。

HTTPDNSAPPKEYIMAGE

  1. /**
  2. * SDK 自动初始化
  3. * 无需配置appKey和appSecret;
  4. * 结合 AliyunEmasServices-Info.plist 配置文件使用。
  5. */
  6. - (instancetype)autoInit;
  7. /**
  8. * 初始化并设置 HTTPDNS 服务 Account ID,您可以从控制台获取您的 Account ID 信息
  9. * 此方法会初始化为单例。
  10. * @param accountId 您的 HTTPDNS Account ID
  11. */
  12. - (instancetype)initWithAccountID:(int)accountID;
  13. /**
  14. * @brief 启用鉴权功能的初始化接口
  15. * @details 初始化、开启鉴权功能,并设置 HTTPDNS 服务 Account ID,鉴权功能对应的 secretKey。
  16. * 您可以从控制台获取您的 Account ID 、secretKey 信息。
  17. * 此方法会初始化为单例。
  18. * @param accountId 您的 HTTPDNS Account ID
  19. * @param secretKey 鉴权对应的 secretKey
  20. */
  21. - (instancetype)initWithAccountID:(int)accountID secretKey:(NSString *)secretKey;
  22. /**
  23. * @brief 校正 App 签名时间
  24. * @param authCurrentTime 用于校正的时间戳,正整数。
  25. * @details 不进行该操作,将以设备时间为准,为`(NSUInteger)[[NSDate date] timeIntervalSince1970]`。进行该操作后,如果有偏差,每次网络请求都会对设备时间进行矫正。
  26. * @attention 校正操作在 APP 的一个生命周期内生效,APP 重启后需要重新设置才能重新生效。可以重复设置。
  27. */
  28. - (void)setAuthCurrentTime:(NSUInteger)authCurrentTime;
  29. /**
  30. * 获取 HTTPDNS 服务实例
  31. */
  32. + (instancetype)sharedInstance;
  33. /**
  34. * 设置HTTPDNS域名解析请求类型(HTTP/HTTPS),若不调用该接口,默认为HTTP请求。
  35. * HTTP请求基于底层CFNetwork实现,不受ATS限制;
  36. * @param enable YES: HTTPS请求, NO: HTTP请求
  37. */
  38. - (void)setHTTPSRequestEnabled:(BOOL)enable;
  39. /**
  40. * 设置持久化缓存功能
  41. * 开启后,每次网络解析记录,会更新到本地缓存,
  42. * App 重启后,首先加载本地缓存到内存中,
  43. * 在网络解析返回前,优先使用缓存记录。利于优化 App 启动时数据加载性能。
  44. * 该功能旨在提升首屏加载速度,但持久化缓存会将上一次解析到的结果保存到本地持久层,App 重启后,如果启动持久化缓存会优先从持久层加载解析结果。所以存在第一次使用的ip为过期ip(ttl过期,大多数情况下该 ip 依然可以正常使用)的可能性。如果业务服务器ip变化较频繁,建议谨慎接入该功能,以免对业务造成影响。另外,持久化缓存仅影响第一次域名解析结果,后续解析仍会请求httpdns服务器,并更新本地缓存。
  45. @param enable True:开启,False:关闭
  46. */
  47. - (void)setCachedIPEnabled:(BOOL)enable;
  48. /**
  49. * 将app使用到的域名预设进来,以便于HTTPDNS 进行预解析
  50. * @param hosts 预解析列表
  51. */
  52. - (void)setPreResolveHosts:(NSArray *)hosts;
  53. /**
  54. * 异步解析接口,首先查询缓存,若存在则返回结果,若不存在返回nil并且进行异步域名解析更新缓存
  55. * @param host 域名(如www.aliyun.com)
  56. * @return 域名对应的解析结果
  57. */
  58. - (NSString *)getIpByHostAsync:(NSString *)host;
  59. /**
  60. * 异步解析接口,首先查询缓存,若存在则返回结果列表,若不存在返回nil并且进行异步域名解析更新缓存
  61. * @param host 域名(如www.aliyun.com)
  62. * @return 域名对应的解析结果列表
  63. */
  64. - (NSArray *)getIpsByHostAsync:(NSString *)host;
  65. /**
  66. * 异步解析接口,首先查询缓存,若存在则返回结果,若不存在返回空对象并且进行异步域名解析更新缓存。返回的结果是URL使用场景下的格式化结果
  67. * @param host 域名(如www.aliyun.com)
  68. * @return 域名对应的解析结果
  69. */
  70. - (NSString *)getIpByHostAsyncInURLFormat:(NSString *)host;
  71. /**
  72. * 开启IPv6结果解析,开启后调用 getIPv6ByHostAsync: 接口使用
  73. *【注意】开启IPv6结果解析后,SDK在IPv6-Only网络环境下,对IPv4解析结果不再自动转换为IPv6地址,getIpsByHostAsync:返回IPv4地址,getIPv6ByHostAsync:返回IPv6地址
  74. * @param enable 是否开启,默认为NO
  75. */
  76. - (void)enableIPv6:(BOOL)enable;
  77. /**
  78. * 异步解析域名,返回IPv6地址
  79. * 开启IPv6结果解析后,若域名存在IPv6地址,则返回IPv6解析结果
  80. * 例:域名:ipv6.sjtu.edu.cn,IPv4地址:202.120.2.47,IPv6地址:2001:da8:8000:1:0:0:0:80,解析成功后接口返回结果:2001:da8:8000:1:0:0:0:80
  81. * @param host 解析域名
  82. * @return IPv6解析结果,若没有IPv6地址,则返回nil
  83. */
  84. - (NSString *)getIPv6ByHostAsync:(NSString *)host;
  85. /**
  86. * 设置降级策略,用户可定制规则降级为原生DNS解析方式;
  87. * @param delegate 降级代理
  88. */
  89. - (void)setDelegateForDegradationFilter:(id<HttpDNSDegradationDelegate>)delegate;
  90. @protocol HttpDNSDegradationDelegate <NSObject>
  91. /**
  92. * 降级过滤器
  93. * @param hostName 当前的目标域名(如www.aliyun.com),您可以针对域名进行降级过滤
  94. * @return 是否降级走原生DNS逻辑
  95. */
  96. - (BOOL)shouldDegradeHTTPDNS:(NSString *)hostName;
  97. /**
  98. * 是否允许 HTTPDNS 返回 TTL 过期的域名
  99. * 当您允许返回TTL过期的IP时,SDK在实时返回过期IP的同时依然会进行异步更新以获取最新的IP信息
  100. * @param enable 是否返回TTL过期域名
  101. */
  102. - (void)setExpiredIPEnabled:(BOOL)enable;
  103. /**
  104. * 本地日志 log 开关
  105. */
  106. - (void)setLogEnabled:(BOOL)enable;
  107. /**
  108. * 设置网络切换时是否自动刷新所有域名解析结果,如果打开此开关,在网络切换时,会自动刷新所有域名的解析结果,但会产生一定流量消耗
  109. * @param enable
  110. */
  111. - (void)setPreResolveAfterNetworkChanged:(BOOL)enable;
  112. /**
  113. * 设置网络请求的超时时间
  114. * 超时时间默认为15秒
  115. * @param timeoutInterval 超时时间,单位为秒
  116. */
  117. - (void)setTimeoutInterval:(NSTimeInterval)timeoutInterval;
  118. /**
  119. * 获取用于用户追踪的 sessionId
  120. * sessionId为随机生成,长度为12位,App生命周期内保持不变
  121. *
  122. * 为了排查可能的解析问题,需要您将 sessionId 和解析出的IP一起记录在日志中
  123. * 请参考: 解析异常排查之 “会话追踪方案” https://help.aliyun.com/document_detail/100530.html
  124. */
  125. - (NSString *)getSessionId;
  126. /**
  127. * 设置日志输出回调(v1.6.20及以上版本支持)
  128. */
  129. - (void)setLogHandler:(id<HttpdnsLoggerProtocol>)logHandler;
从安全角度我们强烈建议用户使用异步解析接口。在DDOS攻击等特殊场景下,HTTPDNS有可能会触发流量黑洞,此时同步接口就有可能出现短暂的请求解析超时等待,而异步接口的网络请求都是后台操作的,业务层面不会感知到请求超时的动作,能够做到对异常情况的冗余。
  1. /**
  2. * 同步解析接口,首先查询缓存,若存在则返回结果,若不存在则进行同步域名解析请求,解析完成返回最新解析结果,若解析失败返回nil
  3. * @param host 域名(如www.aliyun.com)
  4. * @return 域名对应的解析结果
  5. */
  6. - (NSString *)getIpByHost:(NSString *)host;
  7. /**
  8. * 同步解析接口,首先查询缓存,若存在则返回结果,若不存在则进行同步域名解析请求,解析完成返回最新解析结果列表,若解析失败返回nil
  9. * @param host 域名(如www.aliyun.com)
  10. * @return 域名对应的解析结果列表
  11. */
  12. - (NSArray *)getIpsByHost:(NSString *)host;
  13. /**
  14. * 同步解析接口,首先查询缓存,若存在则返回结果,若不存在则进行同步域名解析请求,解析完成返回最新解析结果,若解析失败返回空对象。返回的结果是URL使用场景下的格式化结果
  15. * @param host 域名(如www.aliyun.com)
  16. * @return 域名对应的解析结果
  17. */
  18. - (NSString *)getIpByHostInURLFormat:(NSString *)host;

HTTPDNS 场景下兼容 IPv6-only 网络环境需要注意的细节:

当您使用 IP 形式的 URL 进行网络请求时,IPv4 与 IPv6 的 IP 地址使用方式略有不同:

即在URL中使用IPv6地址时需要在IPv6地址基础上额外加上[]。为了方便开发者的使用,HTTPDNS提供了适配URL格式的IP获取接口 -[HttpDnsService getIpByHostAsyncInURLFormat:]。当您通过HTTPDNS进行IP获取,并使用该IP进行基于URL的网络访问时,您可以通过上述API直接获取符合URL使用场景,格式化后的IP信息,如1.1.1.1[2001:db8:c000:221::]。如果您仅仅为了获取精准的IP信息并另做它用,您可以继续使用老接口 -[HttpDnsService getIpByHostAsync:]

3.2 使用示例

您可以通过获取alicloud-ios-demo工程源码获得HTTPDNS服务的使用例程。

4. 注意事项

4.1 请记录从HTTPDNS获取的IP及sessionId

我们提供了用于解析问题排查的解决方案,需要您将从HTTPDNS获取的IP及sessionId记录到日志中, 详情可以参考 《解析异常排查之 “会话追踪方案”》

4.2 HTTP请求头HOST字段设置

标准的HTTP协议中服务端会将HTTP请求头HOST字段的值作为请求的域名信息进行解析。使用HTTPDNS后,您可能需要将HTTP请求URL中的HOST字段替换为HTTPDNS解析获得的IP,这时标准的网络库会将您的IP赋值给HTTP请求头的HOST字段,进而导致服务端的解析异常(服务端认可的是您的域名信息,而非IP信息)。为了解决这个问题,您可以主动设置HTTP请求HOST字段的值,如:

  1. NSString *originalUrl = @"http://www.aliyun.com/";
  2. NSURL* url = [NSURL URLWithString:originalUrl];
  3. NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:url];
  4. // 同步接口获取IP
  5. NSString* ip = [httpdns getIpByHostAsync:url.host];
  6. if (ip) {
  7. // 通过HTTPDNS获取IP成功,进行URL替换和HOST头设置
  8. NSRange hostFirstRange = [originalUrl rangeOfString: url.host];
  9. if (NSNotFound != hostFirstRange.location) {
  10. NSString* newUrl = [originalUrl stringByReplacingCharactersInRange:hostFirstRange withString:ip];
  11. request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:newUrl]];
  12. // 设置请求HOST字段
  13. [request setValue:url.host forHTTPHeaderField:@"host"];
  14. }
  15. }

部分网络库支持COOKIE的自动存储管理,当您使用HTTPDNS进行IP URL请求时,部分网络库会将您URL中的IP信息作为COOKIE对应的域名信息进行存储管理(而非HTTP请求头HOST字段信息),进而造成COOKIE管理与使用上的困扰,因此您需要关闭COOKIE的自动管理功能(默认关闭)。

4.4 HTTPS/WebView/SNI场景

4.5 代理情况下的使用

当存在中间HTTP代理时,客户端发起的请求中请求行会使用绝对路径的URL,在您开启HTTPDNS并采用IP URL进行访问时,中间代理将识别您的IP信息并将其作为真实访问的HOST信息传递给目标服务器,这时目标服务器将无法处理这类无真实HOST信息的HTTP请求。移动网关提供了X-Online-Host的私有协议字段来解决这个问题,比如:

  1. 目标URLhttp://www.aliyun.com/product/oss/
  2. 通过HTTPDNS解析出来的www.aliyun.comIP1.1.1.1
  3. 代理:10.0.0.172:80
  4. 您的HTTP请求头:
  5. GET http://1.1.1.1/product/oss/ HTTP/1.1 # 通过代理发起的HTTP请求头,请求行是一个绝对路径
  6. Host: www.aliyun.com # 这个Header会被代理网关忽略,代理网关会使用请求行绝对路径中的host字段作为源站的host,即1.1.1.1
  7. X-Online-Host: www.aliyun.com # 这个Header就是移动网关为了传递真实Host添加的私有头部,源站需要配置识别该私有头部以获取真实的Host信息

同样您可以通过下述方法进行X-Online-Host请求头域的设置,并在服务端设置对该私有头域的解析。

  1. [request setValue:url.host forHTTPHeaderField:@"X-Online-Host"];

在绝大多数场景下,我们建议您在代理模式下关闭HTTPDNS功能。