Flutter SDK接入

更新时间:
复制为 MD 格式

通过客户端接入概述您已经了解了HTTPDNS接入的基本原理,本文介绍通过Flutter SDK接入HTTPDNS的方法。

FlutterGoogle开源的应用开发框架,仅通过一套代码库,就能构建精美的、原生平台编译的多平台应用。

我们提供纯 Dart 实现的 HTTPDNS SDK,无需依赖原生平台 SDK,并展示如何在Flutter常用的网络框架中集成使用HTTPDNS。本SDK已在GitHubpub.dev发布。

以下是SDK的使用说明和最佳实践:

一、快速入门

1.1 开通服务

请参考快速入门开通HTTPDNS。

1.2 获取配置

请参考开发配置EMAS控制台开发配置中获取AccountId/SecretKey/AESSecretKey等信息,用于初始化SDK。

二、安装配置

2.1 添加Flutter依赖

在您的Flutter项目的pubspec.yaml中加入dependencies:

dependencies:
  flutter:
    sdk: flutter
  aliyun_httpdns: ^2.0.0  # 从SDK发布说明获取最新版本号
  dio: ^5.9.0  # Dio网络库
  http: ^1.2.0  # http包

添加依赖之后需要执行一次 flutter pub get

说明

从 2.0.0 版本起,本 SDK 为纯 Dart 实现,无需配置 Android 或 iOS 原生依赖,安装后直接使用。

三、配置和使用

3.1 初始化配置

应用启动后,需要先初始化插件,才能调用HTTPDNS能力。 初始化主要是配置AccountId/SecretKey等信息及功能开关。 示例代码如下:

// 初始化 HTTPDNS
final config = AliyunHttpdnsConfig(
  accountId: 您的AccountId,
  secretKey: '您的SecretKey',
  httpsEnabled: true,
  persistentCacheEnabled: true,
  reuseExpiredIPEnabled: true,
  preResolveAfterNetworkChanged: true,
  ipRankingDatasource: {
    'www.aliyun.com': 443,
  },
);
await AliyunHttpdns.init(config);

// 开启日志(可选)
AliyunHttpdns.setLogEnabled(true);

// 设置预解析域名
await AliyunHttpdns.setPreResolveHosts(['www.aliyun.com'], ipType: HttpdnsIpType.auto);
重要
  • httpsEnabled 参数设置为true后,计费会增加,请仔细阅读产品计费文档。

  • 如果您对域名信息或SDNS参数有更高的安全诉求,可以配置 aesSecretKey 参数启用对解析请求进行内容层加密,使用内容加密后计费会增加,请仔细阅读产品计费文档。

3.1.1 日志配置

应用开发过程中,如果要输出HTTPDNS的日志,可以调用日志输出控制方法,开启日志,示例代码如下:

AliyunHttpdns.setLogEnabled(true);

// 自定义日志处理器(可选)
AliyunHttpdns.setLogHandler((message) {
  print(message);
});

3.1.2 sessionId记录

应用在运行过程中,可以调用获取SessionId方法获取sessionId,记录到应用的数据采集系统中。 sessionId用于表示标识一次应用运行,线上排查时,可以用于查询应用一次运行过程中的解析日志,示例代码如下:

final sessionId = AliyunHttpdns.getSessionId();
print("SessionId = $sessionId");

3.2 域名解析

3.2.1 预解析

当需要提前解析域名时,可以调用预解析域名方法,示例代码如下:

await AliyunHttpdns.setPreResolveHosts(["www.aliyun.com", "www.example.com"], ipType: HttpdnsIpType.auto);

调用之后,SDK会发起域名解析,并把结果缓存到内存,用于后续请求时直接使用。

3.2.2 域名解析

当需要解析域名时,可以通过调用域名解析方法解析域名获取IP,示例代码如下:

Future<void> _resolve() async {
  final result = await AliyunHttpdns.resolveHostSyncNonBlocking('www.aliyun.com', ipType: HttpdnsIpType.auto);
  final ipv4List = result?.ips ?? [];
  final ipv6List = result?.ipv6s ?? [];
  print('IPv4: $ipv4List');
  print('IPv6: $ipv6List');
}

四、Flutter最佳实践

4.1 原理说明

本示例展示了一种更直接的集成方式,通过自定义HTTP客户端适配器来实现HTTPDNS集成:

  1. 创建自定义的HTTP客户端适配器,拦截网络请求

  2. 在适配器中调用HTTPDNS插件解析域名为IP地址

  3. 使用解析得到的IP地址创建直接的Socket连接

  4. 对于HTTPS连接,确保正确设置SNI(Server Name Indication)为原始域名

这种方式直接在 HTTP 客户端层面集成 HTTPDNS 功能,实现简洁高效。

4.2 示例说明

本示例提供了一个完整的Flutter应用,展示如何集成HTTPDNS功能。

4.2.1 自定义HTTP客户端适配器实现

自定义适配器的实现请参考 lib/net/httpdns_http_client_adapter.dart 文件。本方案由EMAS团队设计实现,参考请注明出处。 适配器内部会拦截HTTP请求,调用HTTPDNS进行域名解析,并使用解析后的IP创建socket连接。

本示例支持三种网络库:Dio、HttpClient、http包。代码如下:

import 'dart:io';
import 'package:dio/io.dart';
import 'package:http/http.dart' as http;
import 'package:http/io_client.dart';
import 'package:flutter/foundation.dart';
import 'package:aliyun_httpdns/aliyun_httpdns.dart';

// Dio 适配器
IOHttpClientAdapter buildHttpdnsHttpClientAdapter() {
  final HttpClient client = HttpClient();
  _configureHttpClient(client);
  _configureConnectionFactory(client);

  final IOHttpClientAdapter adapter = IOHttpClientAdapter(createHttpClient: () => client)
    ..validateCertificate = (cert, host, port) => true;
  return adapter;
}

// 原生 HttpClient
HttpClient buildHttpdnsNativeHttpClient() {
  final HttpClient client = HttpClient();
  _configureHttpClient(client);
  _configureConnectionFactory(client);
  return client;
}

// http 包适配器
http.Client buildHttpdnsHttpPackageClient() {
  final HttpClient httpClient = buildHttpdnsNativeHttpClient();
  return IOClient(httpClient);
}

// HttpClient 基础配置
void _configureHttpClient(HttpClient client) {
  client.findProxy = (Uri _) => 'DIRECT';
  client.idleTimeout = const Duration(seconds: 30);
  client.maxConnectionsPerHost = 8;
}

// 配置基于 HTTPDNS 的连接工厂
// 本方案由EMAS团队设计实现,参考请注明出处。
void _configureConnectionFactory(HttpClient client) {
  client.connectionFactory = (Uri uri, String? proxyHost, int? proxyPort) async {
    final String domain = uri.host;
    final bool https = uri.scheme.toLowerCase() == 'https';
    final int port = uri.port == 0 ? (https ? 443 : 80) : uri.port;

    final List<InternetAddress> targets = await _resolveTargets(domain);
    final Object target = targets.isNotEmpty ? targets.first : domain;

    if (!https) {
      return Socket.startConnect(target, port);
    }

    // HTTPS:先 TCP,再 TLS(SNI=域名),并保持可取消
    bool cancelled = false;
    final Future<ConnectionTask<Socket>> rawStart = Socket.startConnect(target, port);
    final Future<Socket> upgraded = rawStart.then((task) async {
      final Socket raw = await task.socket;
      if (cancelled) {
        raw.destroy();
        throw const SocketException('Connection cancelled');
      }
      final SecureSocket secure = await SecureSocket.secure(
        raw,
        host: domain, // 重要:使用原始域名作为SNI
      );
      if (cancelled) {
        secure.destroy();
        throw const SocketException('Connection cancelled');
      }
      return secure;
    });
    return ConnectionTask.fromSocket(
      upgraded,
      () {
        cancelled = true;
        try {
          rawStart.then((t) => t.cancel());
        } catch (_) {}
      },
    );
  };
}

// 通过 HTTPDNS 解析目标 IP 列表
Future<List<InternetAddress>> _resolveTargets(String domain) async {
  try {
    final result = await AliyunHttpdns.resolveHostSyncNonBlocking(domain, ipType: HttpdnsIpType.auto);
    final List<String> ipv4 = result?.ips ?? [];
    final List<String> ipv6 = result?.ipv6s ?? [];
    final List<InternetAddress> targets = [
      ...ipv4.map(InternetAddress.tryParse).whereType<InternetAddress>(),
      ...ipv6.map(InternetAddress.tryParse).whereType<InternetAddress>(),
    ];
    if (targets.isEmpty) {
      debugPrint('[dio] HTTPDNS no result for $domain, fallback to system DNS');
    } else {
      debugPrint('[dio] HTTPDNS resolved $domain -> ${targets.first.address}');
    }
    return targets;
  } catch (e) {
    debugPrint('[dio] HTTPDNS resolve failed: $e, fallback to system DNS');
    return const <InternetAddress>[];
  }
}

4.2.2 适配器集成和使用

适配器的集成请参考 lib/main.dart 文件。 首先需要初始化HTTPDNS,然后配置网络库使用自定义适配器,示例代码如下:

class _MyHomePageState extends State<MyHomePage> {
  late final Dio _dio;
  late final HttpClient _httpClient;
  late final http.Client _httpPackageClient;

  @override
  void initState() {
    super.initState();
    
    // 初始化 HTTPDNS
    _initHttpDnsOnce();
    
    // 配置网络库使用 HTTPDNS 适配器
    _dio = Dio();
    _dio.httpClientAdapter = buildHttpdnsHttpClientAdapter();
    _dio.options.headers['Connection'] = 'keep-alive';
    
    _httpClient = buildHttpdnsNativeHttpClient();
    _httpPackageClient = buildHttpdnsHttpPackageClient();
  }

  Future<void> _initHttpDnsOnce() async {
    try {
      final config = AliyunHttpdnsConfig(
        accountId: 您的AccountId,
        secretKey: '您的SecretKey',
        httpsEnabled: true,
        reuseExpiredIPEnabled: true,
      );
      await AliyunHttpdns.init(config);
      AliyunHttpdns.setLogEnabled(true);
      
      // 设置预解析域名
      await AliyunHttpdns.setPreResolveHosts(['www.aliyun.com'], ipType: HttpdnsIpType.auto);
    } catch (e) {
      debugPrint('[httpdns] init failed: $e');
    }
  }
}

使用配置好的网络库发起请求时,会自动使用HTTPDNS进行域名解析:

// 使用 Dio
final response = await _dio.get('https://www.aliyun.com');

// 使用 HttpClient
final request = await _httpClient.getUrl(Uri.parse('https://www.aliyun.com'));
final response = await request.close();

// 使用 http 包
final response = await _httpPackageClient.get(Uri.parse('https://www.aliyun.com'));

4.2.3 资源清理

在组件销毁时,记得清理相关资源:

@override
void dispose() {
  _urlController.dispose();
  _httpClient.close();
  _httpPackageClient.close();
  super.dispose();
}

五、API

5.1 日志输出控制

控制是否打印Log。

AliyunHttpdns.setLogEnabled(true);

5.2 初始化

初始化配置,在应用启动时调用。

// 创建配置
final config = AliyunHttpdnsConfig(
  accountId: 您的AccountId,                        // 必填
  secretKey: 'your_secret_key',             // 可选
  aesSecretKey: 'your_aes_secret_key',      // 可选
  region: HttpdnsRegion.cn,                 // 默认中国大陆
  httpsEnabled: true,                        // 默认 true
  persistentCacheEnabled: true,              // 持久化缓存
  reuseExpiredIPEnabled: true,               // 复用过期 IP
  preResolveAfterNetworkChanged: true,       // 网络变化后预解析
  ipRankingDatasource: {                     // IP 优选配置(可选)
    'www.aliyun.com': 443,
  },
  timeout: 2,                                // 请求超时(秒)
);

// 初始化 SDK
await AliyunHttpdns.init(config);

// 开启日志(可选)
AliyunHttpdns.setLogEnabled(true);

初始化参数:

参数名

类型

是否必须

功能

accountId

int

必选参数

Account ID

secretKey

String?

可选参数

加签密钥

aesSecretKey

String?

可选参数

加密密钥

region

HttpdnsRegion

可选参数

服务区域,默认 cn

httpsEnabled

bool

可选参数

是否使用HTTPS解析链路,默认 true

persistentCacheEnabled

bool

可选参数

是否开启持久化缓存,默认 false

reuseExpiredIPEnabled

bool

可选参数

是否允许复用过期IP,默认 false

preResolveAfterNetworkChanged

bool

可选参数

网络切换时是否自动刷新解析,默认 false

discardExpiredAfterSeconds

int?

可选参数

过期缓存丢弃时间(秒)

ipRankingDatasource

Map<String, int>?

可选参数

IP优选配置,域名和端口的映射

timeout

int

可选参数

请求超时时间(秒),默认 2

重要

httpsEnabled 参数设置为true后,计费会增加,请仔细阅读产品计费文档。

如果您对域名信息或SDNS参数有更高的安全诉求,可以配置 aesSecretKey 参数启用对解析请求进行内容层加密,使用内容加密后计费会增加,请仔细阅读产品计费文档。

5.3 域名解析

解析指定域名。SDK 提供三种解析方式:

5.3.1 同步非阻塞解析(推荐)

立即返回缓存结果,缓存未命中时返回空并在后台发起请求。

final result = await AliyunHttpdns.resolveHostSyncNonBlocking(
  'www.aliyun.com', 
  ipType: HttpdnsIpType.auto,
);

// 带 SDNS 参数
final result2 = await AliyunHttpdns.resolveHostSyncNonBlocking(
  'www.aliyun.com',
  ipType: HttpdnsIpType.auto,
  sdnsParams: {'key': 'value'},
  cacheKey: 'custom_cache_key',
);

5.3.2 同步阻塞解析

阻塞等待直到获取结果或超时。

final result = await AliyunHttpdns.resolveHostSync(
  'www.aliyun.com',
  ipType: HttpdnsIpType.auto,
);

// 带 SDNS 参数
final result2 = await AliyunHttpdns.resolveHostSync(
  'www.aliyun.com',
  ipType: HttpdnsIpType.auto,
  sdnsParams: {'key': 'value'},
  cacheKey: 'custom_cache_key',
);

5.3.3 异步回调解析

通过回调函数返回解析结果。

await AliyunHttpdns.resolveHostAsync(
  'www.aliyun.com',
  ipType: HttpdnsIpType.auto,
  callback: (result) {
    print('解析结果: $result');
  },
);

// 带 SDNS 参数
await AliyunHttpdns.resolveHostAsync(
  'www.aliyun.com',
  ipType: HttpdnsIpType.auto,
  sdnsParams: {'key': 'value'},
  cacheKey: 'custom_cache_key',
  callback: (result) {
    print('解析结果: $result');
  },
);

解析参数说明

参数名

类型

是否必须

功能

host

String

必选参数

要解析的域名

ipType

HttpdnsIpType

可选参数

请求IP类型:auto, v4, v6, both

sdnsParams

Map<String, String>?

可选参数

SDNS参数,用于自定义解析

cacheKey

String?

可选参数

自定义缓存Key

返回数据结构 (ResolveResult)

字段名

类型

功能

host

String

域名

ips

List

IPv4地址列表

ipv6s

List

IPv6地址列表

ttl

int

IPv4 TTL(秒)

v6ttl

int

IPv6 TTL(秒)

5.4 预解析域名

预解析域名,解析后缓存在SDK中,下次解析时直接从缓存中获取,提高解析速度。

await AliyunHttpdns.setPreResolveHosts(
  ["www.aliyun.com"], 
  ipType: HttpdnsIpType.auto
);

参数:

参数名

类型

是否必须

功能

hosts

List

必选参数

预解析域名列表

ipType

HttpdnsIpType

可选参数

请求IP类型:auto, v4, v6, both

5.5 获取SessionId

获取SessionId,用于排查追踪问题。

final sessionId = await AliyunHttpdns.getSessionId();
print("SessionId = $sessionId");

无需参数,直接返回当前会话ID。

5.6 清除缓存

清除DNS解析缓存。

// 清除所有缓存
await AliyunHttpdns.cleanHostCache(null);

// 清除指定域名缓存
await AliyunHttpdns.cleanHostCache(['www.aliyun.com']);

5.7 网络变化时自动刷新预解析

设置在网络环境变化时是否自动刷新预解析域名的缓存,通过初始化配置设置。

final config = AliyunHttpdnsConfig(
  accountId: 您的AccountId,
  secretKey: 'your_secret_key',
  preResolveAfterNetworkChanged: true,  // 网络变化时自动刷新
);
await AliyunHttpdns.init(config);

5.8 持久化缓存配置

设置是否开启持久化缓存功能。开启后,SDK 会将解析结果保存到本地,App 重启后可以从本地加载缓存。通过初始化配置设置。

final config = AliyunHttpdnsConfig(
  accountId: 您的AccountId,
  secretKey: 'your_secret_key',
  persistentCacheEnabled: true,              // 开启持久化缓存
  discardExpiredAfterSeconds: 86400,         // 可选,过期超过1天的缓存丢弃
);
await AliyunHttpdns.init(config);

参数:

参数名

类型

是否必须

功能

persistentCacheEnabled

bool

可选参数

是否开启持久化缓存,默认 false

discardExpiredAfterSeconds

int?

可选参数

过期时间阈值(秒),App 启动时会丢弃过期超过此时长的缓存记录

5.9 IP 优选

设置需要进行 IP 优选的域名列表。开启后,SDK 会对解析返回的 IP 列表进行 TCP 测速并排序,以保证第一个 IP 是可用性最好的 IP。通过初始化配置设置:

final config = AliyunHttpdnsConfig(
  accountId: 您的AccountId,
  secretKey: 'your_secret_key',
  ipRankingDatasource: {
    'www.aliyun.com': 443,
  },
);
await AliyunHttpdns.init(config);

参数:

参数名

类型

是否必须

功能

ipRankingDatasource

Map<String, int>?

可选参数

域名和端口的映射,如:{'www.aliyun.com': 443}

5.10 自定义 TTL

可以通过设置回调函数来修改解析结果的 TTL。

AliyunHttpdns.setTtlChanger((host, ipType, ttl) {
  // 返回修改后的 TTL
  return ttl * 2;
});

5.11 SDNS 全局参数

设置全局 SDNS 参数,所有解析请求都会携带这些参数。

AliyunHttpdns.setSdnsGlobalParams({
  'key1': 'value1',
  'key2': 'value2',
});

5.12 校正签名时间

当客户端时间与服务器时间不一致时,可通过此方法校准时间。

AliyunHttpdns.setAuthCurrentTime(serverTimestamp);

六、版本升级指南

6.1 版本 1.x 升级到 2.0.0 指南

2.0.0 版本重构为纯 Dart 实现,主要优势:

  • 无需依赖 Android/iOS 原生 SDK,简化项目配置和版本管理

  • 跨平台行为一致,更易调试和维护

  • 减少包体积,无原生桥接开销

本次升级涉及部分 API 变化,主要是初始化方式和参数类型的调整。按照下面的步骤操作即可完成升级。

升级步骤详解

1. 更新依赖版本

pubspec.yaml

dependencies:aliyun_httpdns: ^2.0.0

执行更新:

flutter pub upgrade aliyun_httpdns
说明

2.0.0 为纯 Dart 实现,可以删除项目中与原生 SDK 相关的配置(如 build.gradle 中的 HTTPDNS 依赖、podspec 中的 AlicloudHTTPDNS 依赖)。

2. 重构初始化代码

升级前(1.x)

// 1.x:两阶段初始化
await AliyunHttpdns.init(
  accountId: 您的AccountId,
  secretKey: "your_secret_key",
  aesSecretKey: "your_aes_key",
);

await AliyunHttpdns.setHttpsRequestEnabled(true);
await AliyunHttpdns.setPersistentCacheIPEnabled(true);
await AliyunHttpdns.setReuseExpiredIPEnabled(true);
await AliyunHttpdns.setPreResolveAfterNetworkChanged(true);
await AliyunHttpdns.setIPRankingList({'www.aliyun.com': 443});

await AliyunHttpdns.build();

升级后(2.0)

final config = AliyunHttpdnsConfig(
  accountId: 您的AccountId,
  secretKey: 'your_secret_key',
  aesSecretKey: 'your_aes_key',
  httpsEnabled: true,
  persistentCacheEnabled: true,
  reuseExpiredIPEnabled: true,
  preResolveAfterNetworkChanged: true,
  ipRankingDatasource: {'www.aliyun.com': 443},
);
await AliyunHttpdns.init(config);

说明 :

  • 所有功能配置合并到 AliyunHttpdnsConfig 构造参数中

  • 不再需要调用 build() 方法

  • 新增 regiontimeoutdiscardExpiredAfterSeconds 等配置参数

3. 更新解析接口

升级前(1.x)

final res = await AliyunHttpdns.resolveHostSyncNonBlocking(
  'www.aliyun.com',
  ipType: 'both',
);
final ipv4s = res['ipv4'] ?? [];
final ipv6s = res['ipv6'] ?? [];

升级后(2.0)

final result = await AliyunHttpdns.resolveHostSyncNonBlocking(
  'www.aliyun.com',
  ipType: HttpdnsIpType.auto,
);
final ipv4s = result?.ips ?? [];
final ipv6s = result?.ipv6s ?? [];

说明 :

  • ipType 从字符串改为 HttpdnsIpType 枚举(auto, v4, v6, both)

  • 返回值从 Map<String, List<String>> 改为 ResolveResult? 对象

  • 字段名从 ipv4/ipv6 改为 ips/ipv6s

  • 新增 resolveHostSync 和 resolveHostAsync 两种解析方式

4. 更新预解析接口

升级前(1.x)

await AliyunHttpdns.setPreResolveHosts(['www.aliyun.com']);

升级后(2.0)

await AliyunHttpdns.setPreResolveHosts(['www.aliyun.com']);
5. 新增自定义日志处理器
AliyunHttpdns.setLogHandler((message) {
  print(message);
});
6. 更新清除缓存接口

升级前(1.x)

await AliyunHttpdns.cleanAllHostCache();

升级后(2.0)

// 清除所有缓存
await AliyunHttpdns.cleanHostCache(null);

// 清除指定域名缓存(新增)
await AliyunHttpdns.cleanHostCache(['www.aliyun.com']);
说明

若您的应用未使用到变化的 API,可以不用处理。

API 升级映射表(1.x → 2.0)

接口分类

1.x

2.0

初始化

init(accountId:, secretKey:) + 各种 set 方法 + build()

init(AliyunHttpdnsConfig(...))

启用 HTTPS 请求

setHttpsRequestEnabled(true)

AliyunHttpdnsConfig(httpsEnabled: true)

启用过期 IP

setReuseExpiredIPEnabled(true)

AliyunHttpdnsConfig(reuseExpiredIPEnabled: true)

开启本地缓存

setPersistentCacheIPEnabled(true)

AliyunHttpdnsConfig(persistentCacheEnabled: true)

网络切换预解析

setPreResolveAfterNetworkChanged(true)

AliyunHttpdnsConfig(preResolveAfterNetworkChanged: true)

IP 优选

setIPRankingList({...})

AliyunHttpdnsConfig(ipRankingDatasource: {...})

构建服务

build()

不再需要

同步非阻塞解析

resolveHostSyncNonBlocking(..., ipType: 'both')

resolveHostSyncNonBlocking(..., ipType: HttpdnsIpType.both)

同步阻塞解析

resolveHostSync(...)(新增)

异步回调解析

resolveHostAsync(..., callback: ...)(新增)

返回值

Map<String, List<String>>res['ipv4']

ResolveResult?result?.ips

设置预解析域名

setPreResolveHosts(..., ipType: 'both')

setPreResolveHosts(..., ipType: HttpdnsIpType.both)

清除缓存

cleanAllHostCache()

cleanHostCache(List<String>?)

自定义 TTL

setTtlChanger(...)(新增)

SDNS 全局参数

setSdnsGlobalParams({...})(新增)

自定义日志处理器

setLogHandler(...)(新增)

校正签名时间

setAuthCurrentTime(int)(新增)

6.2 版本 0.x 升级到 1.0.0 指南

1.0.0 版本进行了全面的架构重构和接口优化。这次升级旨在:

  • 统一配置模式:从分散的运行时配置改为两阶段初始化模式(init + build),解决配置时序问题,提升 SDK 稳定性

  • 标准化解析接口:重新设计解析接口架构,提供统一的 resolveHostSyncNonBlocking 方法,返回结构化数据而非 JSON 字符串

  • 静态方法设计:从单例模式改为静态方法调用,简化使用方式,无需创建实例

  • 性能优化:通过接口优化和内部实现改进,提升解析性能和资源利用效率

这是一次不兼容的重大变更,虽然变更较大,但您只需要修改应用中实际使用的接口。通过下面的升级步骤和新旧 API 映射表,您可以系统性地完成这次重要升级。

升级步骤详解

1. 更新依赖版本

pubspec.yaml

dependencies:aliyun_httpdns: ^1.0.0

执行更新:

flutter pub upgrade aliyun_httpdns
2. 重构初始化代码

升级前

// 旧版本:单例模式 + 一步初始化
final _aliyunHttpDns = AliyunHttpDns();

await _aliyunHttpDns.init(
  "YOUR_ACCOUNT_ID",              // String 类型
  secretKey: "your_secret_key",
  aesSecretKey: "your_aes_key",
  region: "",
  timeout: 2000,
  enableHttps: true,
  enableExpireIp: true,
  enableCacheIp: true,
  enableDegradationLocalDns: true,
  preResolveAfterNetworkChanged: true,
  ipRankingMap: {"www.aliyun.com": 80},
  sdnsGlobalParam: {"aa": "bb"},
  bizTags: ["tag1", "tag2"]
);

升级后

// 新版本:静态方法 + 两阶段初始化

// 第一阶段:初始化基本配置
await AliyunHttpdns.init(
  accountId: your_account_id,            // int 类型,必须设置
  secretKey: "your_secret_key",          // 可选
  aesSecretKey: "your_aes_key",          // 可选
);

// 第二阶段:设置功能选项
await AliyunHttpdns.setHttpsRequestEnabled(true);        // 替代 enableHttps
await AliyunHttpdns.setLogEnabled(true);                 // 替代 enableLog
await AliyunHttpdns.setPersistentCacheIPEnabled(true);   // 替代 enableCacheIp
await AliyunHttpdns.setReuseExpiredIPEnabled(true);      // 替代 enableExpireIp
await AliyunHttpdns.setPreResolveAfterNetworkChanged(true); // 替代 preResolveAfterNetworkChanged

// 第三阶段:构建服务(必须调用)
await AliyunHttpdns.build();

说明

  • 移除了 regiontimeoutenableDegradationLocalDnsipRankingMapsdnsGlobalParambizTags 等参数

  • 新增 build() 方法,必须在配置完成后调用

  • 所有方法改为静态方法,无需创建实例

3. 更新解析接口

升级前

// 同步非阻塞,返回 JSON 字符串
String result = await _aliyunHttpDns.resolve(
  "YOUR_ACCOUNT_ID",          // accountId
  "www.aliyun.com",           // host
  kRequestIpv4AndIpv6,        // requestIpType
);

// 需要手动解析 JSON
Map<String, dynamic> map = json.decode(result);
List<String> ipv4s = List<String>.from(map['ipv4'] ?? []);
List<String> ipv6s = List<String>.from(map['ipv6'] ?? []);

// 使用第一个 IP
String ip = ipv4s.isNotEmpty ? ipv4s.first : '';

升级后

// 同步非阻塞,返回结构化数据
Map<String, List<String>> result = await AliyunHttpdns.resolveHostSyncNonBlocking(
  'www.aliyun.com',           // hostname(无需 accountId)
  ipType: 'both',             // 替代 kRequestIpv4AndIpv6
);

// 直接获取 IP 列表
List<String> ipv4s = result['ipv4'] ?? [];
List<String> ipv6s = result['ipv6'] ?? [];

// 使用第一个 IP
String ip = ipv4s.isNotEmpty ? ipv4s.first : '';

自定义解析参数

// 升级前
String result = await _aliyunHttpDns.resolve(
  "YOUR_ACCOUNT_ID",
  "www.aliyun.com",
  kRequestIpv4AndIpv6,
  params: {"key": "value"},
  cacheKey: "custom_key"
);

// 升级后
Map<String, List<String>> result = await AliyunHttpdns.resolveHostSyncNonBlocking(
  'www.aliyun.com',
  ipType: 'both',
  sdnsParams: {"key": "value"},    // 参数名变更
  cacheKey: "custom_key"
);
4. 更新预解析接口

升级前

await _aliyunHttpDns.setPreResolveHosts(
  "YOUR_ACCOUNT_ID",                     // accountId
  ["www.aliyun.com"],
  kRequestIpv4AndIpv6                    // requestIpType
);

升级后

await AliyunHttpdns.setPreResolveHosts(
  ["www.aliyun.com"],                     // 无需 accountId
  ipType: 'both'                          // 替代 kRequestIpv4AndIpv6
);
5. 更新日志配置

升级前

await _aliyunHttpDns.enableLog(true);

升级后

await AliyunHttpdns.setLogEnabled(true);
6. 更新 SessionId 获取

升级前

String sessionId = await _aliyunHttpDns.getSessionId("YOUR_ACCOUNT_ID");

升级后

String? sessionId = await AliyunHttpdns.getSessionId();
7. 新增功能使用

清除缓存

await AliyunHttpdns.cleanAllHostCache();

持久化缓存配置

await AliyunHttpdns.setPersistentCacheIPEnabled(true);
说明

若您的应用未使用到不兼容的 API,可以不用处理。

API 升级映射表

接口分类

升级前

升级后

创建实例

AliyunHttpDns()

无需创建,直接使用静态方法

初始化

init(String accountId, {...})

init({required int accountId, ...})

构建服务

build() (新增,必须调用)

启用 HTTPS 请求

init(enableHttps: true)

setHttpsRequestEnabled(true)

启用过期 IP

init(enableExpireIp: true)

setReuseExpiredIPEnabled(true)

开启本地缓存

init(enableCacheIp: true)

setPersistentCacheIPEnabled(true)

网络切换预解析

init(preResolveAfterNetworkChanged: true)

setPreResolveAfterNetworkChanged(true)

控制日志输出

enableLog(bool)

setLogEnabled(bool)

同步非阻塞解析

resolve(String accountId, String host, String requestIpType)

resolveHostSyncNonBlocking(String hostname, {String ipType})

IPv4 解析

resolve(..., kRequestIpv4)

resolveHostSyncNonBlocking(..., ipType: 'ipv4')

IPv6 解析

resolve(..., kRequestIpv6)

resolveHostSyncNonBlocking(..., ipType: 'ipv6')

IPv4 和 IPv6 解析

resolve(..., kRequestIpv4AndIpv6)

resolveHostSyncNonBlocking(..., ipType: 'both')

自动选择

resolveHostSyncNonBlocking(..., ipType: 'auto') 

自定义解析参数

resolve(..., params: {...})

resolveHostSyncNonBlocking(..., sdnsParams: {...})

设置预解析域名

setPreResolveHosts(String accountId, List<String>, String requestIpType)

setPreResolveHosts(List<String>, {String ipType})

获取 SessionId

getSessionId(String accountId)

getSessionId()

清除缓存

cleanAllHostCache() 

校正签名时间

setAuthCurrentTime(String accountId, int)

已移除