全部产品
阿里云办公

Android SDK手册

更新时间:2018-08-10 16:33:52

HTTPDNS Android SDK开发指南


1. 前言

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

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

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

1.1 手动集成SDK

  • 您可以通过上述github demo获取HTTPDNS SDK;
  • 您可以通过访问移动服务APP列表页(https://ams.console.aliyun.com/#/appList 若您第一次访问,请创建APP),点击下图红框中的下载OneSDK,进入OneSDK下载页并勾选HTTPDNS组件获取SDKapplistsdk download

1.2 Maven集成

  • build.gradle中添加Maven仓库地址:
  1. allprojects {
  2. repositories {
  3. maven {
  4. url 'http://maven.aliyun.com/nexus/content/repositories/releases/'
  5. }
  6. }
  7. }
  • gradle添加依赖:
  1. dependencies {
  2. compile ('com.aliyun.ams:alicloud-android-httpdns:1.1.7@aar') {
  3. transitive true
  4. }
  5. }

开发时可以如上所述指定完整的版本号,也可以指定模糊版本号,gradle自动拉取满足条件的最新版本SDK,如compile 'com.aliyun.ams:alicloud-android-httpdns:1.+'

若SDK集成过程中出现UTDID冲突,请参考 阿里云-移动云产品SDK UTDID冲突解决方案


2. 应用程序初始化

2.1 获取服务实例

2.1.1 普通方式

HTTPDNS Android SDK以全局service实例的方式提供域名解析服务,您可以通过以下方式获取实例:

  1. HttpDnsService httpdns = HttpDns.getService(applicationContext, accountID);
  2. // 参数applicationContext是您Android App的Context
  3. // 参数accountID是系统分配的Account ID,当您开通HTTPDNS后,您可以在控制台获取到您对应的Account ID信息

2.1.2 鉴权方式

httpdns v1.1.3及以上版本支持鉴权方式,该方式需要去httpdns控制台进行关闭非鉴权接口(请慎重操作),详情见鉴权解析接口,您可以通过以下方式获取实例:

  1. HttpDnsService httpdns = HttpDns.getService(applicationContext, accountID, secretKey);
  2. // 参数applicationContext是您Android App的Context
  3. // 参数accountID是系统分配的Account ID,当您开通HTTPDNS后,您可以在控制台获取到您对应的Account ID信息
  4. // 参数secretKey是鉴权对应的secretKey

鉴权默认过期时间为10分钟

2.1.3 EMAS统一接入服务

httpdns v1.1.7即以上版本支持EMAS统一接入服务, 接入该服务后,无需配置accountIdsecretkey,直接使用HttpDns.getService(getApplicationContext())进行初始化即可。EMAS统一接入服务接入细节请参考:Android EMAS统一接入

2.2 设置预解析域名

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

  1. ArrayList<String> hostList = new ArrayList<>(Arrays.asList("www.taobao.com", "www.aliyun.com"));
  2. httpdns.setPreResolveHosts(hostList);

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

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

3. 服务API与使用示例

3.1 服务API

  1. /**
  2. * 获取HTTPDNS服务实例
  3. *
  4. * @param applicationContext 您的Android App Context
  5. * @param accountId 您的HTTPDNS租户ID
  6. */
  7. HttpDnsService getService(Context applicationContext, String accountID);
  8. /**
  9. * 获取HTTPDNS服务实例。使用该方法获取实例需要接入EMAS统一接入服务
  10. *
  11. * @param applicationContext 您的Android App Context
  12. */
  13. HttpDnsService getService(Context applicationContext);
  14. /**
  15. * 将app使用到的域名预设进来,以便于HTTPDNS 进行预解析
  16. *
  17. * @param hostList 预解析列表
  18. */
  19. void setPreResolveHosts(ArrayList<String> hostList);
  20. /**
  21. * 设置网络切换时是否自动刷新所有域名解析结果,如果打开此开关,在网络切换时,会自动刷新所有域名的解析结果,但会产生一定流量消耗
  22. *
  23. * @param enable
  24. */
  25. void setPreResolveAfterNetworkChanged(boolean enable);
  26. /**
  27. * 设置降级策略,用户可定制规则降级为原生DNS解析方式
  28. *
  29. * @param filter 降级代理
  30. */
  31. void setDegradationFilter(DegradationFilter filter);
  32. public interface DegradationFilter {
  33. /**
  34. * 降级过滤器
  35. *
  36. * @param hostName 当前的目标域名(如www.aliyun.com),您可以针对域名进行降级过滤
  37. * @return 是否降级走原生DNS逻辑
  38. */
  39. boolean shouldDegradeHttpDNS(String hostName);
  40. }
  41. /**
  42. * 是否允许HTTPDNS返回TTL过期的域名
  43. * 当您允许返回TTL过期的IP时,SDK在实时返回过期IP的同时依然会进行异步更新以获取最新的IP信息
  44. *
  45. * @param enable 是否返回TTL过期域名
  46. */
  47. void setExpiredIPEnabled(boolean enable);
  48. /**
  49. * 是否允许启用持久化缓存功能
  50. * 该功能旨在提升首屏加载速度,但持久化缓存会将上一次解析到的结果保存到本地持久层,app重启后,如果启动持久化缓存会优先从持久层加载解析结果。所以存在第一次使用的ip为过期ip(ttl过期,大多数情况下该ip依然可以正常使用)的可能性。如果业务服务器ip变化较频繁,建议谨慎接入该功能,以免对业务造成影响。另外,持久化缓存仅影响第一次域名解析结果,后续解析仍会请求httpdns服务器,并更新本地缓存。
  51. *
  52. * @param enable
  53. */
  54. void setCachedIPEnabled(boolean enable);
  55. /***
  56. * 校正App签名时间
  57. * @param time time为epoch时间戳,1970年1月1日以来的秒数
  58. */
  59. void setAuthCurrentTime(long time);
  60. /**
  61. * 是否允许HTTPDNS打印Log
  62. *
  63. * @param shouldPrintLog 是否打印Log
  64. */
  65. void setLogEnabled(boolean shouldPrintLog);
  66. /**
  67. * 设置自定义请求超时时间,默认为15S
  68. *
  69. * @param timeoutInterval 单位是毫秒(ms)
  70. */
  71. void setTimeoutInterval(int timeoutInterval);
  72. /**
  73. * 设置是否通过HTTPS协议解析域名,默认通过HTTP协议解析
  74. *
  75. * @param enabled
  76. */
  77. void setHTTPSRequestEnabled(boolean enabled);
  78. /**
  79. * 异步解析接口,首先查询缓存,若存在则返回结果,若不存在返回null并且进行异步域名解析更新缓存。
  80. * 若接口返回null,,为避免影响业务请降级到local dns解析策略。
  81. *
  82. * @param host 域名(如www.aliyun.com)
  83. * @return 域名对应的解析结果
  84. */
  85. String getIpByHostAsync(String host);
  86. /**
  87. * 异步解析接口, 获取ip列表,首先查询缓存,若存在则返回结果,若不存在返回长度为0 的String 数组并且进行异步域名解析更新缓存。
  88. * 若接口返回长度为0 的String 数组,为避免影响业务请降级到local dns解析策略。
  89. *
  90. * @param host
  91. * @return 域名对应的解析结果列表
  92. */
  93. String[] getIpsByHostAsync(String host);
  94. 关于异步解析接口调用的最佳实践,请参考[如何利用HTTPDNS降低DNS解析开销](https://yq.aliyun.com/articles/8624?spm=5176.100239.0.0.7ISvKE)
  95. /**
  96. * V1.1.5及以上版本支持。设置IP探测列表。设置该接口后,如果解析了相对应的域名,则SDK会对返回的IP进行IP探测,对返回的IP列表进行动态排序,以保证第一个IP是可用性最好的IP
  97. */
  98. void setIPProbeList(List<IPProbeItem> ipProbeList);
  99. /* 指定要探测的域名以及探测时的端口号
  100. */
  101. public IPProbeItem(String hostname, int port
  102. ----------------------
  103. /**
  104. * 同步解析接口,首先查询缓存,若存在则返回结果,若不存在则进行同步域名解析请求,解析完成返回最新解析结果,若解析失败返回null。
  105. *
  106. * @param host 域名(如www.aliyun.com)
  107. * @return 域名对应的解析结果
  108. */
  109. String getIpByHost(String host);
  110. /*注:HTTPDNS Android SDK已在v1.0.12版本中下线同步解析接口`String getIpByHost(String host)`和`String[] getIpsByHost(String host)`。从安全角度我们强烈建议用户使用异步解析接口。在DDOS攻击等特殊场景下,HTTPDNS有可能会触发流量黑洞,此时同步接口就有可能出现短暂的请求解析超时等待,而异步接口的网络请求都是后台操作的,业务层面不会感知到请求超时的动作,能够做到对异常情况的冗余。*/
  111. /**
  112. * 同步解析接口, 获取ip列表,首先查询缓存,若存在则返回结果,若不存在则进行同步域名解析请求,解析完成返回最新解析结果,若解析失败返回长度为0 的String 数组。
  113. *
  114. * @param host
  115. * @return 域名对应的解析结果列表
  116. */
  117. String[] getIpsByHost(String host);
  118. /**
  119. * 获取用于用户追踪的sessionId
  120. * sessionId为随机生成,长度为12位,App生命周期内保持不变
  121. * @return sessionId
  122. */
  123. String getSessionId();

3.2 使用示例

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

4. 注意事项

4.1 HTTP请求头HOST字段设置

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

  1. String originalUrl = "http://www.aliyun.com/";
  2. URL url = new URL(originalURL);
  3. String originalHost = url.getHost();
  4. // 异步接口获取IP
  5. String ip = httpdns.getIpByHostAsync(originalHost);
  6. HttpURLConnection conn;
  7. if (ip != null) {
  8. // 通过HTTPDNS获取IP成功,进行URL替换和HOST头设置
  9. url = new URL(originalUrl.replaceFirst(originalHost, ip));
  10. conn = (HttpURLConnection) url.openConnection();
  11. // 设置请求HOST字段
  12. conn.setRequestProperty("Host", originHost);
  13. } else {
  14. conn = (HttpURLConnection) url.openConnection();
  15. }

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

4.3 HTTPS/WebView/SNI场景

4.4 代理情况下的使用

当存在中间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信息

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

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

5. 混淆配置

  1. -keep class com.alibaba.sdk.android.**{*;}
  2. -keep class com.ut.**{*;}
  3. -keep class com.ta.**{*;}