全部产品

Android SDK开发指南

更新时间:2020-09-16 16:22:27

本文档介绍了阿里云公共DNS Android SDK的接入和开发方式。

1.概述

阿里云公共DNS SDK是阿里云面向广大移动开发者提供DNS域名解析服务的开发工具包。

开发者利用本SDK,可以在自己的Android APP中轻松接入阿里云公共DNS,解决域名解析异常的问题,低成本实现域名解析精准调度。您可以参考Demo示例工程源码了解如何使用本SDK。

SDK当前版本封装了阿里公共DNS的DoH JSON API,提供Java函数接口给Android APP进行域名解析,并且提供了基于TTL和LRU策略的高效域名缓存功能。在公共DNS原有功能的基础上,SDK还可以为用户带来以下优势:

  • 简单易用:

    用户仅需集成我们提供的SDK,便可接入阿里云公共DNS业务。接入方法简单易用,为用户提供更为轻松便捷的解析服务。

  • 零延迟:

    SDK内部实现了LRU的缓存机制,将每次域名解析后的IP缓存到本地;并且主动更新TTL过期缓存,保证缓存及时有效,从而帮助用户达到域名解析零延迟的效果。

2.如何使用SDK

2.1 jar集成

  1. 您需先在控制台注册自己的应用,获取应用的唯一标识Account ID

  2. 然后通过控制台的链接获取阿里公共DNS SDK

  3. 获取到的SDK的pdns-sdk-android.jar集成到自己工程项目libs目录中即可轻松使用

2.2 gradle集成maven

在 build.gradle 文件中加入以下代码:

allprojects {
  repositories {
    maven {
      url 'https://maven.aliyun.com/repository/public/'
    }
    mavenLocal()
    mavenCentral()
  }
}

加入你要引用的文件信息:

dependencies {
  compile 'com.alibaba.pdns:pdns-android-sdk:1.0.1'

}

2.3 应用程序初始化

public class DnsCacheApplication extends Application{

    private String accountID="10001"; //可以更换成您的accountID
    private static final String TAOBAO_URL="www.taobao.com";
    private static final String M_TAOBAO_URL="m.taobao.com";
    private static final String ALIYUN_URL="aliyun.com";
    private static final int CACHE_MAX_NUMBER=100; //缓存的域名最大个数

    @Override
    public void onCreate() {
       super.onCreate();
       DNSResolver.Init(this, accountID);
       DNSResolver.setEnableShort (false);
       DNSResolver.setEnableIPv6 false);
       DNSResolver.setSchemaType(DNSResolver.HTTP);
       DNSResolver.getInstance().setMaxCacheSize(CACHE_MAX_NUMBER);      
       DNSResolver.getInstance().preLoadDomains(newString[]{TAOBAO_URL,M_TAOBAO_URL,ALIYUN_URL});
    }
}

接入阿里公共DNS SDK时建议在Application子类里集成。

说明

DNSResolver为阿里公共DNS SDK的核心类,其内部封装了阿里公共DNS提供的DoH JSON API,将用户的目标域名解析成为对应的IP。

另外,Android工程在使用SDK时,需要保证提供以下访问权限的配置:

<!--需要配置的权限-->
   <uses-permission android:name="android.permission.INTERNET"/>
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
   <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
   <uses-permission android:name="android.permission.WAKE_LOCK"/>
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

注意事项:

Android9.0会报异常:Didn't find class BasicHttpParams。

  • 原因:Apache Http客户端弃用 。

因为早在Android 6.0中,谷歌取消了对Apache Http客户端的支持。从Android 9.0开始,org.apache.http.legacy将从bootclasspath中删除。

该修改对于大多数 taskVersion<9.0的应用没有影响,对所有taskVersion>9.0的应用,如果继续使用Apache Http接口或者引用的lib包中用到该接口时,都会出现Apache Http接口找不到的异常。

  • 解决方案

在应用的AndroidManifest.xml文件的<application>中添加:

<uses-library android:name="org.apache.http.legacy" android:required="false"/>

2.3.1 服务初始化

阿里公共DNS SDK是通过DNSResolver类封装了阿里公共DNS服务请求和本地缓存实现的。用户通过DNSResolver.init(this,accountID)初始化,即可统一接入阿里公共DNS服务。(accountID为用户在控制台注册时,server端自动生成用户唯一标识)

2.3.2 设置预解析域名

在您初始化程序时,可以选择性地预先向阿里公共DNS SDK中注册您后续可能会使用到的域名,以便SDK提前解析,减少后续解析域名时请求的时延。调用以下方法设置预解析域名:

DNSResolver.getInstance().preLoadDomains(newString[]{TAOBAO_URL,M_TAOBAO_URL,ALIYUN_URL});
注意

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

2.3.3 设置是否使用服务端IPV6地址

阿里公共DNS服务支持IPV4、IPV6双栈访问,通过设置DNSResolver.setEnableIPv6(boolean enable)的方法选择使用那种接入协议。当设置为ture表示使用IPV6的IP访问服务端接口,false表示使用IPV4的IP访问服务端接口。如不显式设置,默认为使用IPV4地址访问。另外当设置为IPV6时访问阿里公共DNS服务不通时则自动切换为IPV4,并且支持重试3次策略。

2.3.4 设置是否开启Short模式

阿里公共DNS的DoH JSON API返回数据类型分为全量JSON和简要IP数组格式,可以通过调用DNSResolver.setEnableShort (boolean enable)来开启或关闭short模式。如不显式设置,默认为关闭short模式。

如下方式:

DNSResolver.setEnableShort (true); //默认值是false,该参数用户可以不需设置,不设置则默认为false。
注意

short模式为SDK调用阿里公共DNS服务返回的比较简单IP数组,可以减少回复的数据量,适用于对网络流量敏感的场景。

2.3.5 设置缓存模块最大缓存数量

DNSResolver.getInstance().setMaxCacheSize(CACHE_MAX_NUMBER);
private static final int CACHE_MAX_NUMBER =100;//缓存域名最大count默认是100。

用户可以自定义最大count的值。

2.3.6 设置访问服务端协议

DNSResolver.setSchemaType(DNSResolver.HTTP); 默认访问为http的模式。

DNSResolver.HTTP,以HTTP协议访问服务端接口;

DNSResolver.HTTPS,以HTTPS协议访问服务端接口。

3.服务API

/**
  * 获取url对应IPv4记录的DomainInfo对象数组
  *
  * @param url例如(http://www.taobao.com)
  * @return目标url对应IPV4类型的DomainInfo对象数组
  */
  public DomainInfo[] getIPsV4DInfoByUrl(String url) 

注意:DomainInfo对象中的url为替换host为IP拼接后的url,用户不需再手动url的替换拼接。

/**
   * 获取url对应IPv6记录的DomainInfo对象数组
   * 
   * @param url 例如(http://m.taobao.com)
   * @return 目标url对应IPV6类型的DomainInfo对象数组
   */
    public DomainInfo[] getIPsV6DInfoByUrl(String url) 
   

 /**
    * 获取url对应IPV4记录的DomainInfo对象
    *
    * @param url 例如(http://m.taobao.com)
    * @return 目标url对应IPV4类型的DomainInfo对象集合中随机的一个
    */
    public DomainInfo getIPV4DInfoByUrl(String url) 


 /**
    * 获取url对应IPV6记录的DomainInfo对象
    *
    * @param url 例如(http://www.taobao.com)
    * @return 目标url对应IPV6类型的DomainInfo对象集合中随机的一个
    */
  public DomainInfo getIPV6DInfoByUrl(String url) 


/**
    * 获取hostName对应IPV4记录数组
    * @param hostName例如(www.taobao.com)
    * @return 返回目标hostName对应的IPV4地址的数组
    */
  public  String[] getIPsV4ByHost(String hostName) 


/**
    * 获取hostName对应IPV6记录数组
    * @param hostName例如(www.taobao.com)
    * @return 返回目标hostName对应的IPV6地址的数组
    */
  public String[] getIPsV6ByHost(String hostName) 


/**
    * 获取hostName对应IPV4记录
    * @param hostName例如(www.taobao.com)
    * @return 返回目标hostName对应的IPV4地址集合中的一个随机IPV4地址 
    */
  public String getIPV4ByHost(String hostName) 


/**
    * 获取hostName对应IPV6记录
    * @param hostName例如(www.taobao.com)
    * @return 返回目标hostName对应的IPV6地址集合中的一个随机IPV6地址
    */
 public String getIPV6ByHost(String hostName) 


/**
 * 预加载逻辑
 *
 * @param domains
 */
public void preLoadDomains(final String[] domains) 

  说明:以上返回的domainInfo对象,主要是封装了如下属性

 /**
   * id访问域名自增的id编号
    */
 public String id = null;

   /**
    * 可以直接使用的url 已经替换了host为ip后的url
    */
public String url = null;


    /**
    * 需要设置到http header里面的目标服务名称
    */
    public String host = "";


   /**
    * 返回的内容体
    */
   public String data = null;


   /**
    * 开始请求的时间
    */
   public String startTime = null;


   /**
    * 请求结束的时间,如果请求超时,该值为null
    */
   public String stopTime = null; 


  /**
   * server返回的状态值200 \ 404 \ 500等 
   */
public String code = null;

4.SDK API使用示例

URl:传进来的访问地址,例如:http://www.taobao.com。

 String hostname = "www.taobao.com";
 String url = "http://www.taobao.com";

获得IPv4地址:

String IPV4 = DNSResolver.getInstance().getIPV4ByHost(hostname);

获得IPv6地址:

String IPV6 =  DNSResolver.getInstance().getIPV6ByUrl (url);

获得url对应的DomainInfo对象:

DomainInfo dinfo = DNSResolver.getInstance().getIPV4DInfoByUrl(url); //获取替换后地址

示例:

public class MainActivity extends AppCompatActivity {
   private Button button;
   private TextView tvInfo;
   private TextView tvResult;
   private String hostUrl = "http://www.taobao.com";
   private String hostName = “www.taobao.com”;
   private static final String TAG = "PDnsDemo";
   private static ExecutorService pool = Executors.newSingleThreadExecutor();
   private static final String PDNS_RESULT = "pdns_result";
   private static final int SHOW_CONSOLE_TEXT = 10000;
   private Handler mHandler;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.demo_activity_main);
       init();
       initHandler();
   }
 private void init() {
       tvInfo = findViewById(R.id.tv_respons_info);
       tvResult = findViewById(R.id.tv_respons);
       button = findViewById(R.id.btn_onclik);
       button.setOnClickListener(new View.OnClickListener() {
           public void onClick(View view) {
               new Thread(new Runnable() {
                      @Override
                      public void  run() {
           //调用阿里公共sdk里的getIPV4ByHost()方法获得目标域名解析后的IP
               String ipv4 = DNSResolver.getInstance().getIPV4ByHost(hostName);
               tvInfo.setText("您解析域名的IP是:"+ ipv4);
          //调用阿里公共sdk里getIPV4DInfoByUr获取目标域名解析后的domainInfo对象中的URL,该URL为已替换原来url中host为IP的url
              DomainInfo dinfo = DNSResolver.getInstance().getIPV4DInfoByUrl(hostUrl);
                     if (dinfo != null) {
                           showResponse(dinfo);
                       }
                   }
               }).start();
           }
       });
   }
   private void initHandler() {
       mHandler = new Handler() {
           @Override
           public void handleMessage(Message msg) {
               switch (msg.what)  {
                   case SHOW_CONSOLE_TEXT:
                       tvResult.setText(msg.getData().getString(PDNS_RESULT) + "\n");
                       break;
               }
           }
       };
   }
   private void showResponse(final DomainInfo dinfo) {
                //发送网络请求
               String requestUrl = dinfo.url;
               HttpURLConnection conn = null;
               try {
                   URL url = new URL(requestUrl);
                   conn = (HttpURLConnection) url.openConnection();
                   //使用IP的方式进行访问时,需要设置HTTP请求头的HOST字段为原来的域名
                   conn.setRequestProperty("Host", url.getHost());//设置HTTP请求头HOST字段
                   DataInputStream dis = new DataInputStream(conn.getInputStream());
                   int len;
                   byte[] buff = new byte[4096];
                   StringBuilder response = new StringBuilder();
                   while ((len = dis.read(buff)) != -1) {
                       response.append(new String(buff, 0, len));
                   }
                   Log.d(TAG, "Response: " + response.toString());
                   dis.close();
                   sendMessage(response.toString());
               } catch (IOException e) {
                   e.printStackTrace();
               }finally {
                   if (conn != null) {
                       conn.disconnect();
                   }
               }
           }
   private void sendMessage(String message) {
       if (mHandler != null) {
           Message msg = mHandler.obtainMessage();
           Bundle bundle = new Bundle();
           bundle.putString(PDNS_RESULT, message);
           msg.setData(bundle);
           msg.what = SHOW_CONSOLE_TEXT;
           mHandler.sendMessage(msg);
       }
   }

}

public class DnsCacheApplication extends Application {

   private String accountID = "10001"; //可以更换成您的accountID
   private static final String TAOBAO_URL = "www.taobao.com";
   private static final String M_TAOBAO_URL = "m.taobao.com";
   private static final String ALIYUN_URL = "aliyun.com";
   private static final String BAIDU_URL = "www.baidu.com";
   private static final int CACHE_MAX_NUMBER = 100; //缓存的域名最大个数

   @Override
   public void onCreate() {
       super.onCreate();
       DNSResolver.Init(this, accountID);
       DNSResolver.setEnableShort(false);
       DNSResolver.setEnableIPv6(false);
       DNSResolver.setSchemaType(DNSResolver.HTTP);
       DNSResolver.getInstance().setMaxCacheSize(CACHE_MAX_NUMBER);
       DNSResolver.getInstance().preLoadDomains(new String[]{TAOBAO_URL, M_TAOBAO_URL, ALIYUN_URL,BAIDU_URL});
   }
}

注意事项

  1. 通过阿里公共DNS获得域名的IP地址后,客户端可以使用这个IP发送业务请求,HTTP请求头的Host字段需改为原来的域名。

  2. 为帮助用户更快的使用阿里公共DNS SDK,我们为读者提供Demo程序,读者可以

    下载到本地作为参考。

点击这里,下载Demo程序。