From ba286489496fca1382e1c5d6b4b2579047a94267 Mon Sep 17 00:00:00 2001 From: AmisKwok Date: Mon, 14 Sep 2026 06:57:07 +0800 Subject: [PATCH 1/6] feat: add partial web platform support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the services that depend on dart:io into io/web variants behind conditional imports so the plugin compiles for Flutter Web. Connectivity uses connectivity_plus, ping degrades to an HTTPS round trip, DNS uses DNS-over-HTTPS, and the speed test, quality score and benchmarks are unchanged. Capabilities the browser sandbox forbids degrade to null or an unavailable result instead of throwing. 将依赖 dart:io 的服务拆分为 io/web 两份实现并以条件导入隔离,使插件可编译到 Flutter Web;浏览器沙箱禁止的能力优雅降级为 null 或不可用结果而非抛异常。 --- docs/404.html | 2 +- docs/404/index.html | 2 +- docs/API-Reference/index.html | 4 +- docs/Benchmark/index.html | 4 +- docs/Connectivity/index.html | 4 +- docs/DNS/index.html | 4 +- docs/FAQ/index.html | 4 +- docs/Full-Report/index.html | 4 +- docs/Getting-Started/index.html | 4 +- docs/Installation/index.html | 8 +- docs/Ping/index.html | 4 +- docs/Platform-Support/index.html | 4 +- docs/Ports/index.html | 4 +- docs/Quality/index.html | 4 +- docs/Speed-Test/index.html | 4 +- docs/Usage/index.html | 4 +- .../static/chunks/nextra-data-en-US.json | 2 +- .../pages/API-Reference-8e9a91f2d08796c0.js | 1 - .../pages/API-Reference-e13a2917d7546319.js | 1 + .../pages/Benchmark-5a9a84620f44f1ef.js | 1 - .../pages/Benchmark-a292e8cb0a504f00.js | 1 + .../pages/Connectivity-f42171fa3a2a6178.js | 1 - .../pages/Connectivity-f9b385023ad97f07.js | 1 + .../chunks/pages/DNS-93340032eaa9ffdd.js | 1 + .../chunks/pages/DNS-9c89ec32dcd86fa0.js | 1 - .../chunks/pages/FAQ-c14e0ebd2147b3f8.js | 1 + .../chunks/pages/FAQ-fc88c8a22ac8a489.js | 1 - .../pages/Full-Report-5051e1f889df2f3a.js | 1 - .../pages/Full-Report-8fdda01136483e9e.js | 1 + ...js => Getting-Started-0b9a79d0ebc87cdf.js} | 2 +- .../pages/Installation-43ade467e1e7ca4a.js | 1 + .../pages/Installation-b38e40fcafc59c1e.js | 1 - .../chunks/pages/Ping-e7614d3667bef7af.js | 1 + .../chunks/pages/Ping-ffd9c666caab5ae7.js | 1 - .../Platform-Support-2f4f155ba23a4f83.js | 1 - .../Platform-Support-45a009c029992240.js | 1 + .../chunks/pages/Ports-325a60377e02f441.js | 1 - .../chunks/pages/Ports-743ec1523389b840.js | 1 + .../chunks/pages/Quality-84301e2f3a2871a5.js | 1 - .../chunks/pages/Quality-ac653fb19750eaeb.js | 1 + .../pages/Speed-Test-03d333b534600839.js | 1 + .../pages/Speed-Test-f92135729d9500cb.js | 1 - .../chunks/pages/Usage-362f5b8f3e61e54f.js | 1 - .../chunks/pages/Usage-668e8555c3b8432b.js | 1 + .../chunks/pages/index-2a81fce2c8fa4aa7.js | 1 + .../chunks/pages/index-b4ab3b9e4fb7d062.js | 1 - .../dF_UuZS4SBtufIwTYLshU/_buildManifest.js | 1 + .../_ssgManifest.js | 0 .../kzRY1NuiYAeDBzYFfxfw_/_buildManifest.js | 1 - docs/favicon.svg | 2 +- docs/index.html | 4 +- example/web/favicon.png | Bin 0 -> 917 bytes example/web/icons/Icon-192.png | Bin 0 -> 5292 bytes example/web/icons/Icon-512.png | Bin 0 -> 8252 bytes example/web/icons/Icon-maskable-192.png | Bin 0 -> 5292 bytes example/web/icons/Icon-maskable-512.png | Bin 0 -> 8252 bytes example/web/index.html | 46 ++++ example/web/manifest.json | 35 +++ lib/src/models/network_capabilities.dart | 101 +------- lib/src/models/network_capabilities_io.dart | 92 +++++++ lib/src/models/network_capabilities_web.dart | 64 +++++ lib/src/services/connectivity_service.dart | 236 +----------------- lib/src/services/connectivity_service_io.dart | 227 +++++++++++++++++ .../services/connectivity_service_web.dart | 170 +++++++++++++ lib/src/services/dns_service.dart | 227 +---------------- lib/src/services/dns_service_io.dart | 220 ++++++++++++++++ lib/src/services/dns_service_web.dart | 178 +++++++++++++ lib/src/services/ping_service.dart | 166 +----------- lib/src/services/ping_service_io.dart | 159 ++++++++++++ lib/src/services/ping_service_web.dart | 119 +++++++++ lib/src/services/port_service.dart | 109 +------- lib/src/services/port_service_io.dart | 101 ++++++++ lib/src/services/port_service_web.dart | 60 +++++ lib/src/zero_network_kit_web.dart | 22 ++ pubspec.yaml | 7 +- 75 files changed, 1591 insertions(+), 852 deletions(-) delete mode 100644 docs/_next/static/chunks/pages/API-Reference-8e9a91f2d08796c0.js create mode 100644 docs/_next/static/chunks/pages/API-Reference-e13a2917d7546319.js delete mode 100644 docs/_next/static/chunks/pages/Benchmark-5a9a84620f44f1ef.js create mode 100644 docs/_next/static/chunks/pages/Benchmark-a292e8cb0a504f00.js delete mode 100644 docs/_next/static/chunks/pages/Connectivity-f42171fa3a2a6178.js create mode 100644 docs/_next/static/chunks/pages/Connectivity-f9b385023ad97f07.js create mode 100644 docs/_next/static/chunks/pages/DNS-93340032eaa9ffdd.js delete mode 100644 docs/_next/static/chunks/pages/DNS-9c89ec32dcd86fa0.js create mode 100644 docs/_next/static/chunks/pages/FAQ-c14e0ebd2147b3f8.js delete mode 100644 docs/_next/static/chunks/pages/FAQ-fc88c8a22ac8a489.js delete mode 100644 docs/_next/static/chunks/pages/Full-Report-5051e1f889df2f3a.js create mode 100644 docs/_next/static/chunks/pages/Full-Report-8fdda01136483e9e.js rename docs/_next/static/chunks/pages/{Getting-Started-51c49bf7439b90f4.js => Getting-Started-0b9a79d0ebc87cdf.js} (51%) create mode 100644 docs/_next/static/chunks/pages/Installation-43ade467e1e7ca4a.js delete mode 100644 docs/_next/static/chunks/pages/Installation-b38e40fcafc59c1e.js create mode 100644 docs/_next/static/chunks/pages/Ping-e7614d3667bef7af.js delete mode 100644 docs/_next/static/chunks/pages/Ping-ffd9c666caab5ae7.js delete mode 100644 docs/_next/static/chunks/pages/Platform-Support-2f4f155ba23a4f83.js create mode 100644 docs/_next/static/chunks/pages/Platform-Support-45a009c029992240.js delete mode 100644 docs/_next/static/chunks/pages/Ports-325a60377e02f441.js create mode 100644 docs/_next/static/chunks/pages/Ports-743ec1523389b840.js delete mode 100644 docs/_next/static/chunks/pages/Quality-84301e2f3a2871a5.js create mode 100644 docs/_next/static/chunks/pages/Quality-ac653fb19750eaeb.js create mode 100644 docs/_next/static/chunks/pages/Speed-Test-03d333b534600839.js delete mode 100644 docs/_next/static/chunks/pages/Speed-Test-f92135729d9500cb.js delete mode 100644 docs/_next/static/chunks/pages/Usage-362f5b8f3e61e54f.js create mode 100644 docs/_next/static/chunks/pages/Usage-668e8555c3b8432b.js create mode 100644 docs/_next/static/chunks/pages/index-2a81fce2c8fa4aa7.js delete mode 100644 docs/_next/static/chunks/pages/index-b4ab3b9e4fb7d062.js create mode 100644 docs/_next/static/dF_UuZS4SBtufIwTYLshU/_buildManifest.js rename docs/_next/static/{kzRY1NuiYAeDBzYFfxfw_ => dF_UuZS4SBtufIwTYLshU}/_ssgManifest.js (100%) delete mode 100644 docs/_next/static/kzRY1NuiYAeDBzYFfxfw_/_buildManifest.js create mode 100644 example/web/favicon.png create mode 100644 example/web/icons/Icon-192.png create mode 100644 example/web/icons/Icon-512.png create mode 100644 example/web/icons/Icon-maskable-192.png create mode 100644 example/web/icons/Icon-maskable-512.png create mode 100644 example/web/index.html create mode 100644 example/web/manifest.json create mode 100644 lib/src/models/network_capabilities_io.dart create mode 100644 lib/src/models/network_capabilities_web.dart create mode 100644 lib/src/services/connectivity_service_io.dart create mode 100644 lib/src/services/connectivity_service_web.dart create mode 100644 lib/src/services/dns_service_io.dart create mode 100644 lib/src/services/dns_service_web.dart create mode 100644 lib/src/services/ping_service_io.dart create mode 100644 lib/src/services/ping_service_web.dart create mode 100644 lib/src/services/port_service_io.dart create mode 100644 lib/src/services/port_service_web.dart create mode 100644 lib/src/zero_network_kit_web.dart diff --git a/docs/404.html b/docs/404.html index 7f69fef..2ef2bbe 100644 --- a/docs/404.html +++ b/docs/404.html @@ -1 +1 @@ -404: This page could not be found

404

This page could not be found.

\ No newline at end of file +404: This page could not be found

404

This page could not be found.

\ No newline at end of file diff --git a/docs/404/index.html b/docs/404/index.html index 7f69fef..2ef2bbe 100644 --- a/docs/404/index.html +++ b/docs/404/index.html @@ -1 +1 @@ -404: This page could not be found

404

This page could not be found.

\ No newline at end of file +404: This page could not be found

404

This page could not be found.

\ No newline at end of file diff --git a/docs/API-Reference/index.html b/docs/API-Reference/index.html index 1031692..3002734 100644 --- a/docs/API-Reference/index.html +++ b/docs/API-Reference/index.html @@ -1,4 +1,4 @@ -
📚 API Reference

API Reference / 接口参考

+
📚 API Reference

API Reference / 接口参考

A condensed field reference for every public model. For copy-paste examples of each method, see the capability pages.

这里是每个公开模型的字段速查。每个方法的复制即用示例请见各能力页面。

@@ -95,4 +95,4 @@

API.md 与 API_zh.md。

-


Zero Network Kit · MPL-2.0
\ No newline at end of file +

Zero Network Kit · MPL-2.0
\ No newline at end of file diff --git a/docs/Benchmark/index.html b/docs/Benchmark/index.html index 7c274e1..6de4b96 100644 --- a/docs/Benchmark/index.html +++ b/docs/Benchmark/index.html @@ -1,4 +1,4 @@ -
📊 Benchmarks

Benchmarks / 微基准测试

+
📊 Benchmarks

Benchmarks / 微基准测试

NetworkBenchmark measures how fast the diagnostics API itself runs — useful when deciding whether a diagnostic belongs on your startup path.

NetworkBenchmark 衡量诊断 API 自身的开销——可用在判断某项诊断能否放在启动路径上。

@@ -33,4 +33,4 @@

minDuration, maxDuration, standardDeviation, operationsPerSecond, failures, timestamp.

BenchmarkSuiteResult: suiteName, results, totalDuration, timestamp, and -suite['name'].


Zero Network Kit · MPL-2.0
\ No newline at end of file +suite['name'].


Zero Network Kit · MPL-2.0
\ No newline at end of file diff --git a/docs/Connectivity/index.html b/docs/Connectivity/index.html index b141962..7bf2c01 100644 --- a/docs/Connectivity/index.html +++ b/docs/Connectivity/index.html @@ -1,4 +1,4 @@ -
📡 Connectivity

Connectivity / 连通性

+
📡 Connectivity

Connectivity / 连通性

NetworkDiagnostic.checkConnection() captures a single snapshot of the current network; onConnectivityChanged emits a fresh snapshot on every transport change.

@@ -145,4 +145,4 @@

}, ); } -}


Zero Network Kit · MPL-2.0
\ No newline at end of file +}
📖 Usage⏱ Latency / Ping
\ No newline at end of file diff --git a/docs/DNS/index.html b/docs/DNS/index.html index 35db973..c1ebdff 100644 --- a/docs/DNS/index.html +++ b/docs/DNS/index.html @@ -1,4 +1,4 @@ -
🌍 DNS

DNS / DNS 解析

+
🌍 DNS

DNS / DNS 解析

NetworkDiagnostic.resolve() tests DNS resolution across multiple servers in parallel, so you can spot the fastest one. Each result is either the system resolver or a raw UDP query against an explicit server.

@@ -72,4 +72,4 @@

final fastest = results
     .where((r) => r.isSuccess)
     .reduce((a, b) => a.responseTimeMs <= b.responseTimeMs ? a : b);
-print('fastest resolver: ${fastest.server}');


Zero Network Kit · MPL-2.0
\ No newline at end of file +print('fastest resolver: ${fastest.server}');
⏱ Latency / Ping🔌 Ports
\ No newline at end of file diff --git a/docs/FAQ/index.html b/docs/FAQ/index.html index c9d0ae0..1c0bb3a 100644 --- a/docs/FAQ/index.html +++ b/docs/FAQ/index.html @@ -1,4 +1,4 @@ -
❓ FAQ

FAQ / 常见问题

+

Zero Network Kit · MPL-2.0
\ No newline at end of file +

采用 MPL-2.0。详见仓库 LICENSE。


Zero Network Kit · MPL-2.0
\ No newline at end of file diff --git a/docs/Full-Report/index.html b/docs/Full-Report/index.html index be83623..e7b5d4d 100644 --- a/docs/Full-Report/index.html +++ b/docs/Full-Report/index.html @@ -1,4 +1,4 @@ -
📋 Full Report

Full Report / 汇总报告

+
📋 Full Report

Full Report / 汇总报告

NetworkDiagnostic.diagnose() runs every probe you ask for and aggregates them into one NetworkDiagnosticReport. A failing sub-test never aborts the run — its field simply stays empty/null.

@@ -80,4 +80,4 @@

includePorts 默认 false,默认运行不会扫描端口。

The report is JSON-encodable via report.toMap(). -报告可通过 report.toMap() 序列化为 JSON。


Zero Network Kit · MPL-2.0
\ No newline at end of file +报告可通过 report.toMap() 序列化为 JSON。


Zero Network Kit · MPL-2.0
\ No newline at end of file diff --git a/docs/Getting-Started/index.html b/docs/Getting-Started/index.html index 322b2af..8f8ee2c 100644 --- a/docs/Getting-Started/index.html +++ b/docs/Getting-Started/index.html @@ -1,4 +1,4 @@ -
🚀 Getting Started

Getting Started / 快速开始

+
🚀 Getting Started

Getting Started / 快速开始

Quick Start / 快速开始

Import the package and start diagnosing — no init() required:

导入包即可开始诊断,无需 init():

@@ -83,4 +83,4 @@

Installation — Detailed installation methods / 详细安装方式
  • Usage — Global config & dependency injection / 全局配置与依赖注入
  • Platform Support — Capability matrix / 能力矩阵
  • -


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +

    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/Installation/index.html b/docs/Installation/index.html index 0d5c1fd..ac93c8b 100644 --- a/docs/Installation/index.html +++ b/docs/Installation/index.html @@ -1,9 +1,9 @@ -
    📦 Installation

    Installation / 安装

    +

    Then run:

    然后运行:

    flutter pub get
    @@ -14,7 +14,7 @@

    zero_network_kit: git: url: https://github.com/zero-labsco/zero_network_kit.git - ref: release/v1.0.0

    + ref: release/v1.0.1

    Platform Setup / 平台配置

    Android

    The plugin manifest already declares INTERNET, ACCESS_NETWORK_STATE and @@ -62,4 +62,4 @@

  • Getting Started — Quick start guide / 快速开始
  • Usage — Full usage guide / 完整使用指南
  • -


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +
    🚀 Getting Started📖 Usage
    \ No newline at end of file diff --git a/docs/Ping/index.html b/docs/Ping/index.html index b93690f..af0b75c 100644 --- a/docs/Ping/index.html +++ b/docs/Ping/index.html @@ -1,4 +1,4 @@ -
    ⏱ Latency / Ping

    Latency / Ping / 延迟探测

    +
    ⏱ Latency / Ping

    Latency / Ping / 延迟探测

    NetworkDiagnostic.ping() measures round-trip time towards a target host and reports sent / received counts, packet loss, min/avg/max and jitter.

    NetworkDiagnostic.ping() 测量到目标主机的往返时间,并给出发送/接收次数、丢包率、 @@ -75,4 +75,4 @@

    mode: PingMode.icmp on desktop to get closer to real ICMP. TCP 探测需要一个在监听的端口。对不接受 TCP/443 的主机探测 port: 443 会失败—— 那是“被过滤”,不是“离线”。在桌面上用 PingMode.icmp 更接近真实 ICMP。

    -


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +

    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/Platform-Support/index.html b/docs/Platform-Support/index.html index 979be90..2a6e0b5 100644 --- a/docs/Platform-Support/index.html +++ b/docs/Platform-Support/index.html @@ -1,4 +1,4 @@ -
    🖥 Platform Support

    Platform Support / 平台支持

    +
    🖥 Platform Support

    Platform Support / 平台支持

    zero_network_kit is declared on five plugin platforms: Android, iOS, macOS, Windows and Linux. Web is not supported — the Dart services rely on dart:io, which does not compile for the web, and browsers have no raw @@ -123,4 +123,4 @@

    final details = await ZeroNetworkKit.getNativeNetworkDetails(); if (details != null) { print(details); // SSID, BSSID, gateway, MAC, VPN flag, RSSI … -}


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +}
    📊 Benchmarks📚 API Reference
    \ No newline at end of file diff --git a/docs/Ports/index.html b/docs/Ports/index.html index a48d876..8c4498c 100644 --- a/docs/Ports/index.html +++ b/docs/Ports/index.html @@ -1,4 +1,4 @@ -
    🔌 Ports

    Ports / 端口检测

    +
    🔌 Ports

    Ports / 端口检测

    checkPort() returns a full PortCheckResult for one port; isPortOpen() is the plain boolean convenience; scanPorts() runs many ports concurrently with bounded in-flight connections.

    @@ -65,4 +65,4 @@

    checkPort() 返回 PortCheckResult(含 isOpen、responseTimeMs、 errorMessage);单端口布尔诉求请用 isPortOpen()。需要 RTT 或失败原因时可直接 调用 checkPort(),或给 scanPorts(..., ports: [443]) 取单条结果。

    -


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +

    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/Quality/index.html b/docs/Quality/index.html index 8ae4fd3..eab92a5 100644 --- a/docs/Quality/index.html +++ b/docs/Quality/index.html @@ -1,4 +1,4 @@ -
    ⭐ Quality Score

    Quality Score / 质量评分

    +
    ⭐ Quality Score

    Quality Score / 质量评分

    NetworkDiagnostic.evaluateQuality() returns a weighted 0–100 score plus a level and human-readable suggestions, computed over whatever metrics are available.

    @@ -128,4 +128,4 @@

    ); print('${score.score.toStringAsFixed(1)} → ${score.level.label}');

    Tune the ideal values globally through NetworkDiagnosticConfig(qualityTargets: ...). -调整理想值请通过 NetworkDiagnosticConfig(qualityTargets: ...) 全局设置。


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +调整理想值请通过 NetworkDiagnosticConfig(qualityTargets: ...) 全局设置。

    🚀 Speed Test📋 Full Report
    \ No newline at end of file diff --git a/docs/Speed-Test/index.html b/docs/Speed-Test/index.html index 8d75998..593b2a6 100644 --- a/docs/Speed-Test/index.html +++ b/docs/Speed-Test/index.html @@ -1,4 +1,4 @@ -
    🚀 Speed Test

    Speed Test / 测速

    +
    🚀 Speed Test

    Speed Test / 测速

    NetworkDiagnostic.runSpeedTest() measures download and upload throughput and samples latency during the run, reporting progress through onProgress.

    NetworkDiagnostic.runSpeedTest() 测量下载与上传吞吐量,并在过程中采样延迟,通过 @@ -87,4 +87,4 @@

    downloadUrl / uploadUrl for production. 默认端点指向 Cloudflare 公共服务并会产生真实流量(默认下载约 25 MB)。在按量计费 网络上运行前请征得同意,并为生产环境替换 downloadUrl / uploadUrl。

    -


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +

    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/Usage/index.html b/docs/Usage/index.html index 13b0562..579821a 100644 --- a/docs/Usage/index.html +++ b/docs/Usage/index.html @@ -1,4 +1,4 @@ -
    📖 Usage

    Usage / 用法

    +

    Zero Network Kit · MPL-2.0
    \ No newline at end of file +

    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/_next/static/chunks/nextra-data-en-US.json b/docs/_next/static/chunks/nextra-data-en-US.json index d5e43f0..4e0dcb1 100644 --- a/docs/_next/static/chunks/nextra-data-en-US.json +++ b/docs/_next/static/chunks/nextra-data-en-US.json @@ -1 +1 @@ -{"/API-Reference":{"title":"API Reference / 接口参考","data":{"":"A condensed field reference for every public model. For copy-paste examples of\r\neach method, see the capability pages.这里是每个公开模型的字段速查。每个方法的复制即用示例请见各能力页面。","networktype#NetworkType":"Member\tNotes\tvalues\tnone, wifi, mobile, ethernet, vpn, bluetooth, other\tlabel\tHuman readable: 'Wi-Fi', 'Mobile', …\tid\tStable English identifier (name), safe to persist\tisConnected\ttrue unless none\tNetworkType.fromRaw(Object?)\tParses a raw platform string","networkconnectioninfo#NetworkConnectionInfo":"isConnected, type, ssid, signalStrength (dBm), ipAddress,\r\nipv6Address, gateway, macAddress, isVpn, isReachable, timestamp,\r\nplus copyWith({bool? isReachable}).","pingresult#PingResult":"Fields host, port, mode, sent, received, times, timestamp;\r\nderived getters lost, packetLoss (%), minTime, maxTime, averageTime,\r\njitter, isSuccess.","dnstestresult#DnsTestResult":"Fields server, domain, isSuccess, responseTime, resolvedIps,\r\nerrorMessage, timestamp; derived responseTimeMs, primaryAddress.","portcheckresult#PortCheckResult":"Fields host, port, isOpen, responseTime, errorMessage, timestamp;\r\nderived responseTimeMs.","speedtestresult#SpeedTestResult":"Fields downloadSpeed, uploadSpeed (Mbps), ping (ms), jitter (ms),\r\npacketLoss (%), downloadedBytes, uploadedBytes, downloadDuration,\r\nuploadDuration, server, timestamp; derived duration; static helper\r\nSpeedTestResult.mbpsFromBytes(bytes, elapsed).","speedtestprogress--speedtestphase#SpeedTestProgress / SpeedTestPhase":"phase (download, upload, completed), bytes, elapsed, speedMbps.","networkqualityscore--networkqualitylevel#NetworkQualityScore / NetworkQualityLevel":"score (0–100), level, metrics (Map), suggestions,\r\ntimestamp; NetworkQualityLevel.fromScore(double), level.label.","networkdiagnosticreport#NetworkDiagnosticReport":"connection, ping, dnsResults, portResults, speedTest, quality,\r\ntimestamp.","benchmarkresult--benchmarksuiteresult#BenchmarkResult / BenchmarkSuiteResult":"BenchmarkResult: testName, iterations, totalDuration,\r\naverageDuration, minDuration, maxDuration, standardDeviation,\r\noperationsPerSecond, failures, timestamp.\r\nBenchmarkSuiteResult: suiteName, results, totalDuration, timestamp,\r\nand suite['name'].","gotchas--常见陷阱#Gotchas / 常见陷阱":"type.label, not displayName. NetworkType exposes label / id.\ncheckPort() returns PortCheckResult. Use isPortOpen() for a plain\r\nboolean, or scanPorts(..., ports: [p]).first for RTT / error message.\nincludeSystemResolver defaults to false. Pass true to add the\r\nsystem DNS row.\nA TCP ping needs a listening port. Probing host with port: 443 fails\r\nif that host does not accept TCP/443 — that is \"filtered\", not \"offline\". Use\r\nmode: PingMode.icmp on desktop to get closer to real ICMP.\nPingMode.icmp is desktop-only and silently degrades when the ping\r\nbinary is unavailable.\nThe speed test moves real traffic (≈25 MB download by default). Ask for\r\nconsent before running it on a metered connection.\nMissing permissions degrade, they never throw. A missing location\r\npermission yields ssid == null; the rest of the snapshot still arrives.\nincludePorts is false by default in diagnose().\ninit() is optional, but dispose() only closes the client the plugin\r\nowns — an httpClient you injected stays open, so close it yourself.\nFull source-level API docs live in the repo:\r\nAPI.md\r\n(English) and\r\nAPI_zh.md\r\n(简体中文).\r\n完整源码级 API 文档见仓库内的\r\nAPI.md\r\n与 API_zh.md。"}},"/Benchmark":{"title":"Benchmarks / 微基准测试","data":{"":"NetworkBenchmark measures how fast the diagnostics API itself runs — useful\r\nwhen deciding whether a diagnostic belongs on your startup path.NetworkBenchmark 衡量诊断 API 自身的开销——可用在判断某项诊断能否放在启动路径上。","all-at-once--一次性全跑#All at once / 一次性全跑":"final suite = await NetworkBenchmark.runAll(\r\n iterations: 20,\r\n warmupIterations: 3,\r\n host: '1.1.1.1',\r\n dnsDomain: 'example.com',\r\n port: 443,\r\n);\r\n\r\nfor (final result in suite.results) {\r\n print('${result.testName.padRight(12)} '\r\n 'avg ${(result.averageDuration.inMicroseconds / 1000).toStringAsFixed(2)} ms '\r\n '± ${(result.standardDeviation.inMicroseconds / 1000).toStringAsFixed(2)} ms '\r\n '${result.operationsPerSecond.toStringAsFixed(1)} ops/s '\r\n 'failures=${result.failures}');\r\n}\r\n\r\n// Look up one benchmark by name / 按名称查单个结果\r\nprint(suite['ping']?.averageDuration);\r\nprint(suite.totalDuration);","individual-suites--单个基准#Individual suites / 单个基准":"await NetworkBenchmark.benchmarkConnection(iterations: 20);\r\nawait NetworkBenchmark.benchmarkPing(iterations: 20, host: '1.1.1.1');\r\nawait NetworkBenchmark.benchmarkDns(iterations: 20, domain: 'example.com');\r\nawait NetworkBenchmark.benchmarkPortCheck(iterations: 20, port: 443);\r\nawait NetworkBenchmark.benchmarkPlatformChannel(iterations: 20);","result-fields--结果字段#Result fields / 结果字段":"BenchmarkResult: testName, iterations, totalDuration, averageDuration,\r\nminDuration, maxDuration, standardDeviation, operationsPerSecond,\r\nfailures, timestamp.BenchmarkSuiteResult: suiteName, results, totalDuration, timestamp, and\r\nsuite['name']."}},"/Connectivity":{"title":"Connectivity / 连通性","data":{"":"NetworkDiagnostic.checkConnection() captures a single snapshot of the current\r\nnetwork; onConnectivityChanged emits a fresh snapshot on every transport\r\nchange.NetworkDiagnostic.checkConnection() 捕获当前网络的一次快照;onConnectivityChanged\r\n在每次传输方式变化时推送新快照。","snapshot--快照#Snapshot / 快照":"final connection = await NetworkDiagnostic.checkConnection();\r\n\r\nprint('type : ${connection.type.label}'); // Wi-Fi / Mobile / Ethernet …\r\nprint('connected : ${connection.isConnected}');\r\nprint('ipv4 : ${connection.ipAddress}');\r\nprint('ipv6 : ${connection.ipv6Address}');\r\nprint('gateway : ${connection.gateway}');\r\nprint('ssid : ${connection.ssid}');\r\nprint('rssi : ${connection.signalStrength} dBm');\r\nprint('mac : ${connection.macAddress}');\r\nprint('vpn : ${connection.isVpn}');\r\nprint('timestamp : ${connection.timestamp}');\nField\tNotes\ttype\tNetworkType (none, wifi, mobile, ethernet, vpn, bluetooth, other)\tisConnected\ttrue unless type is none\tipAddress / ipv6Address\tLocal IPv4 / IPv6 (Dart NetworkInterface)\tgateway / macAddress\tNative; null on desktop except Windows\tssid / signalStrength\tNative; always null on desktop\tisVpn\tNative VPN detection\tisReachable\tOnly filled when probeReachability: true\ttimestamp\tWhen the snapshot was taken\t\nUse connection.type.label / connection.type.id. There is no\r\ndisplayName.\r\n请使用 connection.type.label / connection.type.id,没有 displayName。","parameters--参数#Parameters / 参数":"Parameter\tDefault\tMeaning\tincludeNativeDetails\ttrue\tAlso read SSID / gateway / MAC / VPN from the native side\tprobeReachability\tfalse\tMake a real request and fill isReachable\tprobeTimeout\t3s\tTimeout of that reachability probe\t\n// Skip the native channel (cheapest call — good on hot paths).\r\nfinal quick = await NetworkDiagnostic.checkConnection(includeNativeDetails: false);\r\n\r\n// Prove the internet is actually reachable, not just that a NIC is up.\r\nfinal verified = await NetworkDiagnostic.checkConnection(\r\n probeReachability: true,\r\n probeTimeout: const Duration(seconds: 5),\r\n);\r\nif (verified.isReachable == false) {\r\n print('Interface is up but the internet is unreachable.');\r\n}","change-stream--变化监听#Change stream / 变化监听":"final subscription = NetworkDiagnostic.onConnectivityChanged.listen(\r\n (info) => print('now on ${info.type.id} · ${info.ipAddress}'),\r\n);\r\n// Later:\r\nawait subscription.cancel();\nIn a widget:\nStreamBuilder(\r\n stream: NetworkDiagnostic.onConnectivityChanged,\r\n builder: (context, snapshot) {\r\n final info = snapshot.data;\r\n if (info == null) return const Text('Checking…');\r\n return Text('${info.type.label} · ${info.isConnected}');\r\n },\r\n)","connectivity-only-minimal-example--仅连通性最小示例#Connectivity-only: minimal example / 仅连通性:最小示例":"If all you need is \"am I online, on what transport, what IP, and react to\r\nchanges\", you only need this page — no init() required.如果只需要「在不在線、走什么網络、IP 是多少、切换时通知」,只看本页即可——\r\n无需 init()。\nclass ConnectivityScreen extends StatelessWidget {\r\n const ConnectivityScreen({super.key});\r\n\r\n @override\r\n Widget build(BuildContext context) {\r\n return StreamBuilder(\r\n stream: NetworkDiagnostic.onConnectivityChanged,\r\n builder: (context, snap) {\r\n final c = snap.data;\r\n if (c == null) {\r\n return const Center(child: CircularProgressIndicator());\r\n }\r\n return ListView(\r\n children: [\r\n ListTile(title: const Text('Type / 类型'), trailing: Text(c.type.label)),\r\n ListTile(title: const Text('Online / 在线'), trailing: Text('${c.isConnected}')),\r\n ListTile(title: const Text('IPv4'), trailing: Text(c.ipAddress ?? '—')),\r\n ListTile(title: const Text('IPv6'), trailing: Text(c.ipv6Address ?? '—')),\r\n ],\r\n );\r\n },\r\n );\r\n }\r\n}"}},"/DNS":{"title":"DNS / DNS 解析","data":{"":"NetworkDiagnostic.resolve() tests DNS resolution across multiple servers in\r\nparallel, so you can spot the fastest one. Each result is either the system\r\nresolver or a raw UDP query against an explicit server.NetworkDiagnostic.resolve() 并行测试多台 DNS 服务器的解析表现,从而挑出最快的一台。\r\n每条结果要么来自系统解析器,要么是对指定服务器的原始 UDP 查询。","basic--基础#Basic / 基础":"final results = await NetworkDiagnostic.resolve(\r\n domain: 'example.com',\r\n dnsServers: const ['1.1.1.1', '8.8.8.8', '114.114.114.114'],\r\n timeout: const Duration(seconds: 5),\r\n concurrent: true,\r\n includeSystemResolver: true,\r\n);\r\n\r\nfor (final r in results) {\r\n if (r.isSuccess) {\r\n print('${r.server.padRight(16)} → ${r.resolvedIps.join(\", \")} '\r\n '(${r.responseTimeMs.toStringAsFixed(1)} ms)');\r\n } else {\r\n print('${r.server.padRight(16)} ✗ ${r.errorMessage}');\r\n }\r\n}\nParameter\tDefault\tMeaning\tdomain\tconfig.dnsDomain\tDomain to resolve\tdnsServers\tconfig.dnsServers\tServers queried in parallel (or in series)\ttimeout\tconfig.dnsTimeout\tTimeout of one query\tconcurrent\ttrue\tQuery all servers at once\tincludeSystemResolver\tfalse\tAlso add a system row\t\nNotes / 说明:\nA row with server == 'system' comes from the OS resolver; the others are raw\r\nUDP queries against the listed IPs, encoded by the built-in DnsPacket wire\r\ncodec.\r\nserver == 'system' 的行来自系统解析器,其余是对指定 IP 的原始 UDP 查询,由内置\r\nDnsPacket 编解码。\nincludeSystemResolver defaults to false at the facade level — pass\r\ntrue to include it.\r\n门面层默认不包含系统解析器,需显式传 true。","pick-the-fastest--挑出最快的#Pick the fastest / 挑出最快的":"final fastest = results\r\n .where((r) => r.isSuccess)\r\n .reduce((a, b) => a.responseTimeMs <= b.responseTimeMs ? a : b);\r\nprint('fastest resolver: ${fastest.server}');"}},"/FAQ":{"title":"FAQ / 常见问题","data":{"do-i-need-to-call-init--需要调用-init-吗#Do I need to call init()? / 需要调用 init() 吗?":"No. Every API falls back to built-in defaults. Call ZeroNetworkKit.init() only\r\nwhen you want to override defaults (e.g. a custom reachability host or DNS\r\nservers). Connectivity alone works with zero setup.不需要。每个 API 都走内置默认值。只有在想覆盖默认参数(如自定义可达性主机或 DNS\r\n服务器)时才调用 ZeroNetworkKit.init()。单用连通性完全零配置。","which-platforms-are-supported--支持哪些平台#Which platforms are supported? / 支持哪些平台?":"Android, iOS, macOS, Windows and Linux. Web is not supported.支持 Android、iOS、macOS、Windows 与 Linux。Web 不支持。详见\r\nPlatform Support。","why-is-ssid--signalstrength-null-on-desktop--为什么桌面上的-ssid信号强度是-null#Why is ssid / signalStrength null on desktop? / 为什么桌面上的 ssid/信号强度是 null?":"Desktop uses tier A: SSID and RSSI require system APIs that aren't exposed on\r\nmacOS/Linux/Windows the same way. They are always null on desktop; Windows\r\nadditionally provides gateway / MAC / DNS / VPN via GetAdaptersAddresses.桌面采用 A 档:SSID 与 RSSI 依赖系统 API,在桌面上不以同样方式暴露,因此恒为 null;\r\nWindows 额外通过 GetAdaptersAddresses 提供网关 / MAC / DNS / VPN。","why-does-getnativenetworkdetails-return-null--为什么-getnativenetworkdetails-返回-null#Why does getNativeNetworkDetails() return null? / 为什么 getNativeNetworkDetails 返回 null?":"Either the platform has no such data (e.g. desktop tier A), or the required\r\npermission is missing (e.g. location for Wi-Fi SSID on Android/iOS). The call\r\nnever throws — it degrades gracefully.要么是平台没有该数据(如桌面 A 档),要么是缺权限(如 Android/iOS 上读取 Wi-Fi SSID\r\n需定位权限)。该调用绝不抛异常,会优雅降级。","does-the-speed-test-use-my-bandwidth--测速会消耗我的流量吗#Does the speed test use my bandwidth? / 测速会消耗我的流量吗?":"Yes — the default endpoints are Cloudflare's public service and download ≈25 MB\r\nby default. Ask for consent on metered connections and override downloadUrl /\r\nuploadUrl for production.会——默认端点指向 Cloudflare 公共服务,默认下载约 25 MB。在按量计费网络上请征得同意,\r\n生产环境请替换 downloadUrl / uploadUrl。","how-do-i-test-my-integration-without-the-network--如何脱离网络测试我的集成#How do I test my integration without the network? / 如何脱离网络测试我的集成?":"Every service is injectable. Implement ConnectivityAdapter (or pass fake\r\nservice instances) and call NetworkDiagnostic.configure(...), then\r\nNetworkDiagnostic.reset() to restore defaults. See\r\nUsage → Dependency injection.每个服务都可注入。实现 ConnectivityAdapter(或直接传入假服务实例)后调用\r\nNetworkDiagnostic.configure(...),再用 NetworkDiagnostic.reset() 恢复默认。详见\r\n用法 → 依赖注入。","how-is-this-licensed--采用什么许可证#How is this licensed? / 采用什么许可证?":"MPL-2.0. See the repository LICENSE.采用 MPL-2.0。详见仓库 LICENSE。"}},"/Full-Report":{"title":"Full Report / 汇总报告","data":{"":"NetworkDiagnostic.diagnose() runs every probe you ask for and aggregates them\r\ninto one NetworkDiagnosticReport. A failing sub-test never aborts the run — its\r\nfield simply stays empty/null.NetworkDiagnostic.diagnose() 运行你指定的各项探测,并汇总为一份\r\nNetworkDiagnosticReport。任何子项失败都不会中断整体流程,对应字段保持空。","basic--基础#Basic / 基础":"final report = await NetworkDiagnostic.diagnose(\r\n includePing: true,\r\n includeDns: true,\r\n includePorts: true,\r\n includeSpeedTest: true,\r\n includeUpload: true,\r\n host: '1.1.1.1',\r\n dnsDomain: 'example.com',\r\n dnsServers: const ['1.1.1.1', '8.8.8.8'],\r\n ports: const [80, 443],\r\n);\r\n\r\nprint(report); // one-line summary\r\nprint(report.connection.type.label);\r\nprint(report.ping?.averageTime);\r\nprint(report.dnsResults.length);\r\nprint(report.portResults.where((p) => p.isOpen).length);\r\nprint(report.speedTest?.downloadSpeed);\r\nprint(report.quality.level.label);\nParameter\tDefault\tMeaning\tincludePing\ttrue\tSample latency / jitter / loss\tincludeDns\ttrue\tSample DNS latency\tincludePorts\tfalse\tScan ports (off by default)\tincludeSpeedTest\ttrue\tSample download / upload\tincludeUpload\ttrue\tInclude the upload metric\thost\tconfig.pingHost\tLatency / port target\tdnsDomain / dnsServers\tfrom config\tDNS target\tports\tconfig.probePorts\tPorts scanned when includePorts is true\t\nincludePorts defaults to false, so a default run does not scan ports.\r\nincludePorts 默认 false,默认运行不会扫描端口。\nThe report is JSON-encodable via report.toMap().\r\n报告可通过 report.toMap() 序列化为 JSON。"}},"/Getting-Started":{"title":"Getting Started / 快速开始","data":{"quick-start--快速开始#Quick Start / 快速开始":"Import the package and start diagnosing — no init() required:导入包即可开始诊断,无需 init():\nimport 'package:flutter/material.dart';\r\nimport 'package:zero_network_kit/zero_network_kit.dart';\r\n\r\nvoid main() {\r\n // Optional: apply your own global defaults once.\r\n // 可选:全局定制一次默认参数。\r\n ZeroNetworkKit.init(\r\n config: const NetworkDiagnosticConfig(pingHost: '1.1.1.1'),\r\n );\r\n runApp(const MyApp());\r\n}\nIf you only need connectivity, you don't even need init():如果只需要连通性,连 init() 都不需要:\nfinal connection = await NetworkDiagnostic.checkConnection();\r\nprint('${connection.type.label} · ${connection.ipAddress}');","what-you-get--你能得到什么#What you get / 你能得到什么":"Every method is a static, non-blocking call on the NetworkDiagnostic facade.\r\nThe plugin is pure Dart under the hood, so it is fully injectable and testable\r\nwithout touching the network.每个方法都是 NetworkDiagnostic 门面上的静态、非阻塞调用。插件内核是纯 Dart,\r\n因此完全可注入、可脱离网络做测试。\nNeed\tCall\tAm I online, on what transport?\tNetworkDiagnostic.checkConnection()\tReact to Wi-Fi ⇄ cellular switches\tNetworkDiagnostic.onConnectivityChanged\tLatency, jitter, packet loss\tNetworkDiagnostic.ping()\tIs DNS slow or broken?\tNetworkDiagnostic.resolve()\tIs host:port reachable?\tNetworkDiagnostic.checkPort() / isPortOpen()\tHow fast is down/up?\tNetworkDiagnostic.runSpeedTest()\tOne number for \"good or bad\"\tNetworkDiagnostic.evaluateQuality()\tEverything at once\tNetworkDiagnostic.diagnose()\tNative version / SSID / gateway / MAC\tZeroNetworkKit.getNativeNetworkDetails()\t\nSee Which API do I need? for the full map.","lifecycle--生命周期#Lifecycle / 生命周期":"ZeroNetworkKit.isInitialized; // false until init() runs\r\nZeroNetworkKit.config; // the effective NetworkDiagnosticConfig\r\n\r\nawait ZeroNetworkKit.dispose(); // releases the HTTP client the plugin owns\ndispose() only closes the HTTP client the plugin created itself. An\r\nhttp.Client you injected stays open — close it yourself.dispose() 只会关闭插件自己创建的 HTTP 客户端;你注入的 http.Client 不会被关闭。","next-steps--下一步#Next Steps / 下一步":"Installation — Detailed installation methods / 详细安装方式\nUsage — Global config & dependency injection / 全局配置与依赖注入\nPlatform Support — Capability matrix / 能力矩阵"}},"/Installation":{"title":"Installation / 安装","data":{"from-pubdev-recommended--从-pubdev-安装推荐#From pub.dev (Recommended) / 从 pub.dev 安装(推荐)":"Add the following to your pubspec.yaml:在 pubspec.yaml 中添加以下依赖:\ndependencies:\r\n zero_network_kit: ^1.0.0\nThen run:然后运行:\nflutter pub get","from-github--从-github-安装#From GitHub / 从 GitHub 安装":"Alternatively, install from GitHub:或者从 GitHub 安装:\ndependencies:\r\n zero_network_kit:\r\n git:\r\n url: https://github.com/zero-labsco/zero_network_kit.git\r\n ref: release/v1.0.0","platform-setup--平台配置#Platform Setup / 平台配置":"","android#Android":"The plugin manifest already declares INTERNET, ACCESS_NETWORK_STATE and\r\nACCESS_WIFI_STATE. Reading the Wi-Fi SSID additionally requires the\r\nlocation permission (ACCESS_FINE_LOCATION) on Android 8.1+, otherwise the\r\nsnapshot reports ssid: null.插件清单已声明 INTERNET、ACCESS_NETWORK_STATE 与 ACCESS_WIFI_STATE。读取 Wi-Fi\r\nSSID 还需在 Android 8.1+ 申请定位权限(ACCESS_FINE_LOCATION),否则快照中\r\nssid 为 null。","ios#iOS":"No additional configuration needed. Reading the Wi-Fi SSID additionally\r\nrequires the Access WiFi Information capability plus location authorisation.无需额外配置。读取 Wi-Fi SSID 还需开启 Access WiFi Information 能力并授权定位。","macos--windows--linux#macOS / Windows / Linux":"The plugin is declared on all three desktop platforms. On desktop, native\r\ndetails such as SSID / RSSI are always null (tier A). Windows additionally\r\nprovides gateway / MAC / DNS / VPN through GetAdaptersAddresses; macOS and\r\nLinux report only the Dart-side IP/IPv6. See\r\nPlatform Support for the full matrix.插件已在三个桌面平台声明。桌面上 SSID / 信号强度等原生详情恒为 null(A 档)。\r\nWindows 额外通过 GetAdaptersAddresses 提供网关 / MAC / DNS / VPN;macOS 与 Linux\r\n仅提供 Dart 侧的 IP/IPv6。完整矩阵见平台支持。","import--导入#Import / 导入":"import 'package:zero_network_kit/zero_network_kit.dart';","requirements--环境要求#Requirements / 环境要求":"Requirement\tVersion\tFlutter\t>= 3.3.0\tDart SDK\t>= 3.11.0 < 4.0.0","next-steps--下一步#Next Steps / 下一步":"Getting Started — Quick start guide / 快速开始\nUsage — Full usage guide / 完整使用指南"}},"/Ping":{"title":"Latency / Ping / 延迟探测","data":{"":"NetworkDiagnostic.ping() measures round-trip time towards a target host and\r\nreports sent / received counts, packet loss, min/avg/max and jitter.NetworkDiagnostic.ping() 测量到目标主机的往返时间,并给出发送/接收次数、丢包率、\r\n最小/平均/最大耗时与抖动。","basic--基础#Basic / 基础":"final ping = await NetworkDiagnostic.ping(\r\n host: '1.1.1.1',\r\n count: 5,\r\n timeout: const Duration(seconds: 2),\r\n interval: const Duration(milliseconds: 200),\r\n port: 443,\r\n);\r\n\r\nprint('received : ${ping.received}/${ping.sent}');\r\nprint('loss : ${ping.packetLoss.toStringAsFixed(1)} %');\r\nprint('min/avg/max: ${ping.minTime.toStringAsFixed(1)} / '\r\n '${ping.averageTime.toStringAsFixed(1)} / '\r\n '${ping.maxTime.toStringAsFixed(1)} ms');\r\nprint('jitter : ${ping.jitter.toStringAsFixed(2)} ms');\r\nprint('samples : ${ping.times}');\nParameter\tDefault\tMeaning\thost\tconfig.pingHost\tTarget host\tcount\tconfig.pingCount\tNumber of probes\ttimeout\tconfig.pingTimeout\tPer-probe timeout\tinterval\tconfig.pingInterval\tDelay between probes\tport\tconfig.pingPort\tTCP port probed in PingMode.tcp\tmode\tPingMode.tcp\tPingMode.tcp or PingMode.icmp","tcp-vs-icmp--tcp-与-icmp#TCP vs ICMP / TCP 与 ICMP":"PingMode.tcp performs a TCP handshake to host:port — the portable equivalent\r\nof ICMP and the only mode available on Android/iOS.PingMode.tcp 通过 TCP 握手到 host:port 测量往返,是移动端唯一可用的模式。\n// Desktop only — falls back gracefully if the `ping` binary is unavailable.\r\nawait NetworkDiagnostic.ping(host: '1.1.1.1', count: 4, mode: PingMode.icmp);\nping.isSuccess is true when at least one probe answered; check it before\r\ntrusting the averages.至少一次成功响应时 isSuccess 为 true,读平均值前建议先判断它。\nA TCP ping needs a listening port. Probing host with port: 443 fails if\r\nthat host does not accept TCP/443 — that is \"filtered\", not \"offline\". Use\r\nmode: PingMode.icmp on desktop to get closer to real ICMP.\r\nTCP 探测需要一个在监听的端口。对不接受 TCP/443 的主机探测 port: 443 会失败——\r\n那是“被过滤”,不是“离线”。在桌面上用 PingMode.icmp 更接近真实 ICMP。"}},"/Platform-Support":{"title":"Platform Support / 平台支持","data":{"":"zero_network_kit is declared on five plugin platforms: Android, iOS,\r\nmacOS, Windows and Linux. Web is not supported — the Dart services rely on\r\ndart:io, which does not compile for the web, and browsers have no raw\r\nTCP/UDP sockets.zero_network_kit 在 五 个插件平台上声明:Android、iOS、macOS、Windows 与\r\nLinux。不支持 Web——Dart 服务依赖 dart:io(无法在 Web 上编译),且浏览器没有\r\n原生 TCP/UDP 套接字。","capability-matrix--能力矩阵#Capability matrix / 能力矩阵":"Capability\tAndroid / iOS\tDesktop (macOS / Windows / Linux)\tConnectivity (connectivity_plus)\t✅\t✅\tLocal IP / IPv6 (NetworkInterface)\t✅\t✅\tNative details (SSID / gateway / MAC / VPN)\t✅\t⚠️ see below\tTCP ping\t✅\t✅\tICMP ping (Process.run('ping'))\t❌\t✅\tHTTP ping\t✅\t✅\tDNS system resolver\t✅\t✅\tDNS raw UDP\t✅\t✅\tPort check / scan\t✅\t✅\tSpeed test\t✅\t✅\tQuality score\t✅\t✅\tBenchmarks\t✅\t✅","networkcapabilities--能力查询#NetworkCapabilities / 能力查询":"Query the host platform before calling, so your UI can hide unsupported cards:在调用前查询当前平台能力,UI 即可据此隐藏不支持的卡片:\nfinal caps = NetworkDiagnostic.capabilities;\r\nprint(caps.platform); // 'android' | 'ios' | 'macos' | 'windows' | 'linux'\r\nprint(caps.supports(NetworkCapability.nativeDetails)); // mobile: true, desktop: false\r\nprint(caps.supports(NetworkCapability.icmpPing)); // desktop: true, mobile: false\nRules baked into NetworkCapabilities.current():\nnativeDetails is mobile-only (SSID / gateway / MAC / VPN need system APIs).\nicmpPing is desktop-only (uses the system ping binary).\nNetworkCapabilities.current() 内置规则:\nnativeDetails 仅移动端(SSID / 网关 / MAC / VPN 需要系统 API)。\nicmpPing 仅桌面(使用系统 ping 命令)。","native-details-on-desktop--桌面原生详情#Native details on desktop / 桌面原生详情":"Desktop uses tier A by default: the native layer only reports the platform\r\nversion and an (often empty) details map. IP/IPv6 come from Dart\r\nNetworkInterface. As a result:桌面默认采用 A 档:原生层只报告平台版本与(通常为空的)详情 map,IP/IPv6 由 Dart\r\nNetworkInterface 兜底。因此:\nSSID / signal strength are always null on desktop.\r\n桌面上的 SSID / 信号强度恒为 null。\ngateway / macAddress / isVpn are null on macOS and Linux.\r\nmacOS 与 Linux 上 gateway / macAddress / isVpn 为 null。\nWindows additionally implements GetAdaptersAddresses, so it reports\r\ngateway / macAddress / DNS / isVpn (SSID still null). This is a bonus\r\ntier-B fragment kept as-is.\r\nWindows 额外实现了 GetAdaptersAddresses,因此上报 gateway / macAddress /\r\nDNS / isVpn(SSID 仍为 null)。这是保留的 B 档赠品。\nWhatever the platform, a missing permission or an unreachable native call never\r\nthrows — the field simply stays null and the rest of the result still arrives.无论在哪个平台,缺权限或原生调用不可达都不会抛异常——对应字段保持 null,其余\r\n结果照常返回。","reading-native-data--读取原生数据#Reading native data / 读取原生数据":"final version = await ZeroNetworkKit.getPlatformVersion();\r\nprint(version); // e.g. 'Android 14' / 'iOS 18.0'\r\n\r\nfinal details = await ZeroNetworkKit.getNativeNetworkDetails();\r\nif (details != null) {\r\n print(details); // SSID, BSSID, gateway, MAC, VPN flag, RSSI …\r\n}"}},"/Ports":{"title":"Ports / 端口检测","data":{"":"checkPort() returns a full PortCheckResult for one port; isPortOpen() is the\r\nplain boolean convenience; scanPorts() runs many ports concurrently with\r\nbounded in-flight connections.checkPort() 返回单个端口的完整 PortCheckResult;isPortOpen() 是便捷的布尔版;\r\nscanPorts() 以有界并发批量扫描多个端口。","single-port--单端口#Single port / 单端口":"// Boolean convenience / 便捷布尔版\r\nfinal open = await NetworkDiagnostic.isPortOpen(\r\n host: 'example.com',\r\n port: 443,\r\n timeout: const Duration(seconds: 3),\r\n);\r\nprint(open ? 'HTTPS reachable' : 'HTTPS unreachable');\r\n\r\n// Full result with RTT and error message / 含 RTT 与错误信息的完整结果\r\nfinal result = await NetworkDiagnostic.checkPort(host: 'example.com', port: 443);\r\nprint('open=${result.isOpen} rtt=${result.responseTimeMs} ms '\r\n 'err=${result.errorMessage}');","bulk-scan--批量扫描#Bulk scan / 批量扫描":"final scan = await NetworkDiagnostic.scanPorts(\r\n host: 'example.com',\r\n ports: const [22, 80, 443, 8080, 8443],\r\n concurrency: 8,\r\n);\r\n\r\nfor (final r in scan) {\r\n print('${r.host}:${r.port} '\r\n '${r.isOpen ? \"open\" : \"closed\"} '\r\n '${r.responseTimeMs.toStringAsFixed(1)} ms '\r\n '${r.errorMessage ?? \"\"}');\r\n}\nParameter\tDefault\tMeaning\tports (scanPorts)\tconfig.probePorts ([80, 443])\tPorts to probe\tconcurrency\t12\tMax in-flight connections\ttimeout\tconfig.portCheckTimeout\tTimeout per port\t\ncheckPort() returns a PortCheckResult (with isOpen, responseTimeMs\r\nand errorMessage); use isPortOpen() for a plain boolean. When you need the\r\nround-trip time or the failure reason for a single port, call checkPort()\r\ndirectly or pass a one-element list to scanPorts():\r\nscanPorts(host: 'example.com', ports: [443]).first.\r\ncheckPort() 返回 PortCheckResult(含 isOpen、responseTimeMs、\r\nerrorMessage);单端口布尔诉求请用 isPortOpen()。需要 RTT 或失败原因时可直接\r\n调用 checkPort(),或给 scanPorts(..., ports: [443]) 取单条结果。"}},"/Quality":{"title":"Quality Score / 质量评分","data":{"":"NetworkDiagnostic.evaluateQuality() returns a weighted 0–100 score plus a\r\nlevel and human-readable suggestions, computed over whatever metrics are\r\navailable.NetworkDiagnostic.evaluateQuality() 返回一个加权 0–100 分,附带等级与可读建议,\r\n它基于当前可用的各项指标计算得出。","basic--基础#Basic / 基础":"final quality = await NetworkDiagnostic.evaluateQuality(\r\n includePing: true,\r\n includeDns: true,\r\n includeSpeedTest: true,\r\n includeUpload: true,\r\n);\r\n\r\nprint('${quality.score.toStringAsFixed(1)}/100 — ${quality.level.label}');\r\nquality.metrics.forEach((metric, value) {\r\n print(' $metric = ${value.toStringAsFixed(2)}');\r\n});\r\nfor (final suggestion in quality.suggestions) {\r\n print('• $suggestion');\r\n}\nParameter\tDefault\tMeaning\tincludePing\ttrue\tSample latency / jitter / loss\tincludeDns\ttrue\tSample DNS latency\tincludeSpeedTest\ttrue\tSample download / upload (heavy)\tincludeUpload\ttrue\tInclude the upload metric\tpingHost / pingCount\tfrom config\tLatency target\tdnsDomain / dnsServers\tfrom config\tDNS target\tdownloadUrl / uploadUrl\tfrom config\tBandwidth endpoints","lightweight-variant--轻量变体#Lightweight variant / 轻量变体":"final quality = await NetworkDiagnostic.evaluateQuality(includeSpeedTest: false);","level-thresholds--等级阈值#Level thresholds / 等级阈值":"≥90 excellent · ≥75 good · ≥60 fair · ≥40 poor · otherwise bad\r\n(NetworkQualityLevel.fromScore).≥90 极佳 · ≥75 良好 · ≥60 一般 · ≥40 较差 · 其余为极差。","weights--权重#Weights / 权重":"Metric\tWeight\tSource\tlatency\t0.25\tPingResult.averageTime\tjitter\t0.10\tPingResult.jitter\tpacketLoss\t0.15\tPingResult.packetLoss\tdownload\t0.25\tSpeedTestResult.downloadSpeed\tupload\t0.15\tSpeedTestResult.uploadSpeed\tdns\t0.10\tmean of successful DnsTestResult.responseTimeMs\tsignalStrength\t0.10\tNetworkConnectionInfo.signalStrength","pure-function--纯函数#Pure function / 纯函数":"If you already have the metrics, skip the network entirely:如果你已有指标,可完全跳过网络:\nfinal score = NetworkQualityEvaluator.evaluate(\r\n latency: 42, jitter: 6, packetLoss: 0,\r\n download: 88.4, upload: 12.1, dns: 25, signalStrength: -55,\r\n targets: const QualityTargets(),\r\n);\r\nprint('${score.score.toStringAsFixed(1)} → ${score.level.label}');\nTune the ideal values globally through NetworkDiagnosticConfig(qualityTargets: ...).\r\n调整理想值请通过 NetworkDiagnosticConfig(qualityTargets: ...) 全局设置。"}},"/Speed-Test":{"title":"Speed Test / 测速","data":{"":"NetworkDiagnostic.runSpeedTest() measures download and upload throughput and\r\nsamples latency during the run, reporting progress through onProgress.NetworkDiagnostic.runSpeedTest() 测量下载与上传吞吐量,并在过程中采样延迟,通过\r\nonProgress 汇报进度。","basic--基础#Basic / 基础":"final speed = await NetworkDiagnostic.runSpeedTest(\r\n includeUpload: true,\r\n includePing: true,\r\n onProgress: (progress) {\r\n print('${progress.phase.name}: '\r\n '${progress.speedMbps.toStringAsFixed(1)} Mbps '\r\n '(${progress.bytes} bytes, ${progress.elapsed.inMilliseconds} ms)');\r\n },\r\n);\r\n\r\nprint('download : ${speed.downloadSpeed.toStringAsFixed(2)} Mbps');\r\nprint('upload : ${speed.uploadSpeed.toStringAsFixed(2)} Mbps');\r\nprint('ping : ${speed.ping.toStringAsFixed(1)} ms');\r\nprint('jitter : ${speed.jitter.toStringAsFixed(2)} ms');\r\nprint('loss : ${speed.packetLoss.toStringAsFixed(1)} %');\r\nprint('server : ${speed.server}');\r\nprint('duration : ${speed.duration.inMilliseconds} ms');\nParameter\tDefault\tMeaning\tdownloadUrl / uploadUrl\tfrom config\tEndpoints used\ttimeout\tconfig.speedTestTimeout\tPer-request timeout\tmaxDuration\tconfig.speedTestMaxDuration\tSampling window per phase\tuploadPayloadBytes\tconfig.uploadPayloadBytes\tUpload size\tpingHost / pingCount\tfrom config\tLatency sampled during the test\tincludeUpload\ttrue\tSkip the upload phase\tincludePing\ttrue\tSkip the latency sample\tonProgress\tnull\tCalled repeatedly during both phases\t\nProgress phases: SpeedTestPhase.download → SpeedTestPhase.upload →\r\nSpeedTestPhase.completed.进度阶段依次为 download → upload → completed。","fast-low-traffic-variant--轻量低流量变体#Fast, low-traffic variant / 轻量低流量变体":"final quick = await NetworkDiagnostic.runSpeedTest(\r\n includeUpload: false,\r\n includePing: false,\r\n maxDuration: const Duration(seconds: 5),\r\n);\nThe default endpoints point at Cloudflare's public speed service and move real\r\ntraffic (≈25 MB download by default). Ask for consent before running it on a\r\nmetered connection, and override downloadUrl / uploadUrl for production.\r\n默认端点指向 Cloudflare 公共服务并会产生真实流量(默认下载约 25 MB)。在按量计费\r\n网络上运行前请征得同意,并为生产环境替换 downloadUrl / uploadUrl。"}},"/Usage":{"title":"Usage / 用法","data":{"which-api-do-i-need--该用哪个-api#Which API do I need? / 该用哪个 API?":"I want to know…\tCall\tAm I online, and over what transport?\tNetworkDiagnostic.checkConnection()\tReact to Wi-Fi ⇄ cellular switches\tNetworkDiagnostic.onConnectivityChanged\tLatency, jitter, packet loss\tNetworkDiagnostic.ping()\tIs DNS slow or broken?\tNetworkDiagnostic.resolve()\tIs host:port reachable?\tNetworkDiagnostic.checkPort()\tWhich of these ports are open?\tNetworkDiagnostic.scanPorts()\tHow fast is down/up?\tNetworkDiagnostic.runSpeedTest()\tOne number for “good or bad”\tNetworkDiagnostic.evaluateQuality()\tEverything at once, as a report\tNetworkDiagnostic.diagnose()\tIs the diagnostics API itself expensive?\tNetworkBenchmark.runAll()\tNative version / SSID / gateway / MAC\tZeroNetworkKit.getPlatformVersion(), getNativeNetworkDetails()","global-configuration--全局配置#Global configuration / 全局配置":"NetworkDiagnosticConfig centralises every default. Override only what you\r\nneed; the rest keep the defaults below.NetworkDiagnosticConfig 集中了全部默认参数,只需覆盖你关心的字段。\nZeroNetworkKit.init(\r\n config: const NetworkDiagnosticConfig(\r\n pingHost: '1.1.1.1',\r\n pingPort: 443,\r\n pingCount: 5,\r\n dnsDomain: 'example.com',\r\n dnsServers: ['1.1.1.1', '8.8.8.8'],\r\n downloadUrl: 'https://my-cdn.example.com/speedtest.bin',\r\n uploadUrl: 'https://my-cdn.example.com/upload',\r\n ),\r\n);\nField\tDefault\tMeaning\tpingHost\t'1.1.1.1'\tDefault ping / port-scan target\tpingPort\t443\tPort used by the TCP ping\tpingCount\t4\tProbes per ping run\tpingTimeout\t3s\tTimeout of one probe\tpingInterval\t200ms\tDelay between probes\tdnsDomain\t'www.google.com'\tDefault domain for DNS tests\tdnsServers\t['1.1.1.1', '8.8.8.8', '114.114.114.114']\tServers queried by default\tdnsTimeout\t5s\tTimeout per DNS server\tdownloadUrl\tCloudflare __down?bytes=25000000\tDownload endpoint\tuploadUrl\tCloudflare __up\tUpload endpoint\tuploadPayloadBytes\t1048576 (1 MiB)\tUpload payload size\tspeedTestTimeout\t30s\tPer-request timeout\tspeedTestMaxDuration\t10s\tSampling window per phase\tportCheckTimeout\t3s\tTimeout of one port check\tprobePorts\t[80, 443]\tPorts used by scanPorts() by default\tqualityTargets\tconst QualityTargets()\tIdeal values for scoring\t\nThe default speed-test endpoints are Cloudflare's public service. Swap them for\r\nyour own before shipping production traffic.\r\n默认测速端点是 Cloudflare 的公共服务,正式项目请替换为自建端点。","quality-targets--质量评分理想值#Quality targets / 质量评分理想值":"const NetworkDiagnosticConfig(\r\n qualityTargets: QualityTargets(\r\n excellentLatency: 30, // ms\r\n acceptableLatency: 150, // ms\r\n excellentJitter: 5, // ms\r\n acceptableJitter: 40, // ms\r\n acceptablePacketLoss: 5, // %\r\n excellentDownload: 50, // Mbps\r\n acceptableDownload: 5, // Mbps\r\n excellentUpload: 20, // Mbps\r\n acceptableUpload: 2, // Mbps\r\n excellentDns: 30, // ms\r\n acceptableDns: 200, // ms\r\n ),\r\n);","json-serialisation--序列化#JSON serialisation / 序列化":"Every result object implements toMap() and is JSON encodable:每个结果对象都实现了 toMap(),可直接 JSON 序列化:\nimport 'dart:convert';\r\n\r\nfinal report = await NetworkDiagnostic.diagnose(includeSpeedTest: false);\r\nfinal json = jsonEncode(report.toMap());\r\nprint(json);\r\n\r\n// Round-trip a connection snapshot.\r\nfinal decoded = NetworkConnectionInfo.fromMap(jsonDecode(jsonEncode(\r\n report.connection.toMap(),\r\n)) as Map);\nType\tSerialisation\tNetworkConnectionInfo\ttoMap() + fromMap()\tPingResult\ttoMap()\tDnsTestResult\ttoMap()\tPortCheckResult\ttoMap()\tSpeedTestResult\ttoMap()\tNetworkQualityScore\ttoMap()\tNetworkDiagnosticReport\ttoMap()\tBenchmarkResult / BenchmarkSuiteResult\ttoMap()","dependency-injection--tests--注入与测试#Dependency injection & tests / 注入与测试":"Every service accepts its collaborators, so your integration points are\r\nunit-testable without touching the network.每个服务都支持注入协作对象,可以完全脱离网络做单测。\nclass FakeConnectivityAdapter implements ConnectivityAdapter {\r\n @override\r\n Future> checkConnectivity() async => ['wifi'];\r\n\r\n @override\r\n Stream> get onConnectivityChanged => const Stream.empty();\r\n}\r\n\r\nNetworkDiagnostic.configure(\r\n config: const NetworkDiagnosticConfig(pingHost: '127.0.0.1'),\r\n connectivity: ConnectivityService(adapter: FakeConnectivityAdapter()),\r\n ping: PingService(),\r\n dns: DnsService(),\r\n ports: PortService(),\r\n speedTest: SpeedTestService(client: fakeClient),\r\n);\r\n\r\n// Restore defaults afterwards.\r\nNetworkDiagnostic.reset();\nSwap individual services directly when you prefer:也可以直接替换单个服务:\nNetworkDiagnostic.pingService = MyFakePingService();\r\nNetworkDiagnostic.dnsService = MyFakeDnsService();\nFor advanced service classes, the DNS wire codec and low-level APIs, import\r\npackage:zero_network_kit/advanced.dart.\r\n进阶的服务类、DNS 报文编解码器等底层 API 请通过\r\npackage:zero_network_kit/advanced.dart 引入。"}},"/":{"title":"Zero Network Kit","data":{"":"A Flutter plugin for network diagnostics: connectivity inspection, latency\r\nprobing, DNS resolution, port checks, bandwidth measurement, quality scoring and\r\nmicro-benchmarks — on Android, iOS, macOS, Windows and Linux.一个 Flutter 插件,提供网络诊断能力:连通性检测、延迟探测、DNS 解析、端口\r\n检测、带宽测速、质量评分与微基准测试——覆盖 Android、iOS、macOS、Windows 与 Linux。","-features--功能特性#✨ Features / 功能特性":"Feature\tDescription\tZero setup\tWorks out of the box; init() only to override defaults / 开箱即用,仅需在想覆盖默认值时才 init()\tConnectivity\tTransport type, IPv4/IPv6, gateway, SSID, RSSI, MAC, VPN / 传输类型、IPv4/IPv6、网关、SSID、信号强度、MAC、VPN\tLatency\tTCP handshake RTT everywhere; system ICMP on desktop / TCP 握手 RTT 全平台可用,桌面额外支持系统 ICMP\tDNS\tSystem resolver + raw UDP against explicit servers / 系统解析器 + 针对指定服务器的原始 UDP 查询\tPorts\tBounded-concurrency TCP reachability / 有界并发的 TCP 可达性检测\tSpeed test\tDownload/upload throughput with progress callbacks / 上下行测速,带进度回调\tQuality\tWeighted 0–100 score + level + suggestions / 加权 0–100 分 + 等级 + 建议\tFull report\tOne-shot aggregate of every probe / 一次性汇总所有探测\tBenchmarks\tMeasures how fast the diagnostics API itself runs / 衡量诊断 API 自身开销\tCapabilities\tQuery-then-call; hide unsupported cards (e.g. SSID on desktop) / 先查询后调用,隐藏不支持的卡片\tGraceful degradation\tMissing permission or unreachable sub-service never throws / 缺权限或子服务不可达时只返回 null,绝不抛异常\tHermetic tests\tEvery service accepts injected collaborators / 每个服务都支持注入协作对象,便于单测","-table-of-contents--目录#📚 Table of Contents / 目录":"Page\tDescription\tGetting Started\tQuick start guide / 快速开始\tInstallation\tHow to install / 安装方式\tUsage\tGlobal config, serialisation, dependency injection / 全局配置、序列化、依赖注入\tConnectivity\tConnection snapshot & change stream / 连通性快照与变化监听\tLatency / Ping\tTCP & ICMP latency probing / 延迟探测\tDNS\tResolver comparison across servers / DNS 解析\tPorts\tSingle port & bulk scan / 端口检测\tSpeed Test\tDownload/upload throughput / 测速\tQuality Score\tWeighted scoring / 质量评分\tFull Report\tOne-shot aggregate / 汇总报告\tBenchmarks\tMicro-benchmarks / 微基准\tPlatform Support\tCapability matrix & native details / 能力矩阵与原生详情\tAPI Reference\tModel field reference & gotchas / 模型字段速查与陷阱\tFAQ\tFrequently asked questions / 常见问题","-links--链接#🔗 Links / 链接":"GitHub\nOfficial Website\npub.dev","-license--许可证#📄 License / 许可证":"This project is licensed under the MPL-2.0.本项目采用 MPL-2.0 许可证。This plugin is provided \"as is\", without warranty of any kind. The author assumes\r\nno responsibility or liability for the functionality, security, or any\r\nconsequences arising from the use of modified versions or derivative projects.本插件按\"原样\"提供,不提供任何担保。作者不对修改版或衍生项目的功能、安全性及\r\n任何使用后果承担责任。"}}} \ No newline at end of file +{"/API-Reference":{"title":"API Reference / 接口参考","data":{"":"A condensed field reference for every public model. For copy-paste examples of\neach method, see the capability pages.这里是每个公开模型的字段速查。每个方法的复制即用示例请见各能力页面。","networktype#NetworkType":"Member\tNotes\tvalues\tnone, wifi, mobile, ethernet, vpn, bluetooth, other\tlabel\tHuman readable: 'Wi-Fi', 'Mobile', …\tid\tStable English identifier (name), safe to persist\tisConnected\ttrue unless none\tNetworkType.fromRaw(Object?)\tParses a raw platform string","networkconnectioninfo#NetworkConnectionInfo":"isConnected, type, ssid, signalStrength (dBm), ipAddress,\nipv6Address, gateway, macAddress, isVpn, isReachable, timestamp,\nplus copyWith({bool? isReachable}).","pingresult#PingResult":"Fields host, port, mode, sent, received, times, timestamp;\nderived getters lost, packetLoss (%), minTime, maxTime, averageTime,\njitter, isSuccess.","dnstestresult#DnsTestResult":"Fields server, domain, isSuccess, responseTime, resolvedIps,\nerrorMessage, timestamp; derived responseTimeMs, primaryAddress.","portcheckresult#PortCheckResult":"Fields host, port, isOpen, responseTime, errorMessage, timestamp;\nderived responseTimeMs.","speedtestresult#SpeedTestResult":"Fields downloadSpeed, uploadSpeed (Mbps), ping (ms), jitter (ms),\npacketLoss (%), downloadedBytes, uploadedBytes, downloadDuration,\nuploadDuration, server, timestamp; derived duration; static helper\nSpeedTestResult.mbpsFromBytes(bytes, elapsed).","speedtestprogress--speedtestphase#SpeedTestProgress / SpeedTestPhase":"phase (download, upload, completed), bytes, elapsed, speedMbps.","networkqualityscore--networkqualitylevel#NetworkQualityScore / NetworkQualityLevel":"score (0–100), level, metrics (Map), suggestions,\ntimestamp; NetworkQualityLevel.fromScore(double), level.label.","networkdiagnosticreport#NetworkDiagnosticReport":"connection, ping, dnsResults, portResults, speedTest, quality,\ntimestamp.","benchmarkresult--benchmarksuiteresult#BenchmarkResult / BenchmarkSuiteResult":"BenchmarkResult: testName, iterations, totalDuration,\naverageDuration, minDuration, maxDuration, standardDeviation,\noperationsPerSecond, failures, timestamp.\nBenchmarkSuiteResult: suiteName, results, totalDuration, timestamp,\nand suite['name'].","gotchas--常见陷阱#Gotchas / 常见陷阱":"type.label, not displayName. NetworkType exposes label / id.\ncheckPort() returns PortCheckResult. Use isPortOpen() for a plain\nboolean, or scanPorts(..., ports: [p]).first for RTT / error message.\nincludeSystemResolver defaults to false. Pass true to add the\nsystem DNS row.\nA TCP ping needs a listening port. Probing host with port: 443 fails\nif that host does not accept TCP/443 — that is \"filtered\", not \"offline\". Use\nmode: PingMode.icmp on desktop to get closer to real ICMP.\nPingMode.icmp is desktop-only and silently degrades when the ping\nbinary is unavailable.\nThe speed test moves real traffic (≈25 MB download by default). Ask for\nconsent before running it on a metered connection.\nMissing permissions degrade, they never throw. A missing location\npermission yields ssid == null; the rest of the snapshot still arrives.\nincludePorts is false by default in diagnose().\ninit() is optional, but dispose() only closes the client the plugin\nowns — an httpClient you injected stays open, so close it yourself.\nFull source-level API docs live in the repo:\nAPI.md\n(English) and\nAPI_zh.md\n(简体中文).\n完整源码级 API 文档见仓库内的\nAPI.md\n与 API_zh.md。"}},"/Benchmark":{"title":"Benchmarks / 微基准测试","data":{"":"NetworkBenchmark measures how fast the diagnostics API itself runs — useful\nwhen deciding whether a diagnostic belongs on your startup path.NetworkBenchmark 衡量诊断 API 自身的开销——可用在判断某项诊断能否放在启动路径上。","all-at-once--一次性全跑#All at once / 一次性全跑":"final suite = await NetworkBenchmark.runAll(\n iterations: 20,\n warmupIterations: 3,\n host: '1.1.1.1',\n dnsDomain: 'example.com',\n port: 443,\n);\nfor (final result in suite.results) {\n print('${result.testName.padRight(12)} '\n 'avg ${(result.averageDuration.inMicroseconds / 1000).toStringAsFixed(2)} ms '\n '± ${(result.standardDeviation.inMicroseconds / 1000).toStringAsFixed(2)} ms '\n '${result.operationsPerSecond.toStringAsFixed(1)} ops/s '\n 'failures=${result.failures}');\n}\n// Look up one benchmark by name / 按名称查单个结果\nprint(suite['ping']?.averageDuration);\nprint(suite.totalDuration);","individual-suites--单个基准#Individual suites / 单个基准":"await NetworkBenchmark.benchmarkConnection(iterations: 20);\nawait NetworkBenchmark.benchmarkPing(iterations: 20, host: '1.1.1.1');\nawait NetworkBenchmark.benchmarkDns(iterations: 20, domain: 'example.com');\nawait NetworkBenchmark.benchmarkPortCheck(iterations: 20, port: 443);\nawait NetworkBenchmark.benchmarkPlatformChannel(iterations: 20);","result-fields--结果字段#Result fields / 结果字段":"BenchmarkResult: testName, iterations, totalDuration, averageDuration,\nminDuration, maxDuration, standardDeviation, operationsPerSecond,\nfailures, timestamp.BenchmarkSuiteResult: suiteName, results, totalDuration, timestamp, and\nsuite['name']."}},"/Connectivity":{"title":"Connectivity / 连通性","data":{"":"NetworkDiagnostic.checkConnection() captures a single snapshot of the current\nnetwork; onConnectivityChanged emits a fresh snapshot on every transport\nchange.NetworkDiagnostic.checkConnection() 捕获当前网络的一次快照;onConnectivityChanged\n在每次传输方式变化时推送新快照。","snapshot--快照#Snapshot / 快照":"final connection = await NetworkDiagnostic.checkConnection();\nprint('type : ${connection.type.label}'); // Wi-Fi / Mobile / Ethernet …\nprint('connected : ${connection.isConnected}');\nprint('ipv4 : ${connection.ipAddress}');\nprint('ipv6 : ${connection.ipv6Address}');\nprint('gateway : ${connection.gateway}');\nprint('ssid : ${connection.ssid}');\nprint('rssi : ${connection.signalStrength} dBm');\nprint('mac : ${connection.macAddress}');\nprint('vpn : ${connection.isVpn}');\nprint('timestamp : ${connection.timestamp}');\nField\tNotes\ttype\tNetworkType (none, wifi, mobile, ethernet, vpn, bluetooth, other)\tisConnected\ttrue unless type is none\tipAddress / ipv6Address\tLocal IPv4 / IPv6 (Dart NetworkInterface)\tgateway / macAddress\tNative; null on desktop except Windows\tssid / signalStrength\tNative; always null on desktop\tisVpn\tNative VPN detection\tisReachable\tOnly filled when probeReachability: true\ttimestamp\tWhen the snapshot was taken\t\nUse connection.type.label / connection.type.id. There is no\ndisplayName.\n请使用 connection.type.label / connection.type.id,没有 displayName。","parameters--参数#Parameters / 参数":"Parameter\tDefault\tMeaning\tincludeNativeDetails\ttrue\tAlso read SSID / gateway / MAC / VPN from the native side\tprobeReachability\tfalse\tMake a real request and fill isReachable\tprobeTimeout\t3s\tTimeout of that reachability probe\t\n// Skip the native channel (cheapest call — good on hot paths).\nfinal quick = await NetworkDiagnostic.checkConnection(includeNativeDetails: false);\n// Prove the internet is actually reachable, not just that a NIC is up.\nfinal verified = await NetworkDiagnostic.checkConnection(\n probeReachability: true,\n probeTimeout: const Duration(seconds: 5),\n);\nif (verified.isReachable == false) {\n print('Interface is up but the internet is unreachable.');\n}","change-stream--变化监听#Change stream / 变化监听":"final subscription = NetworkDiagnostic.onConnectivityChanged.listen(\n (info) => print('now on ${info.type.id} · ${info.ipAddress}'),\n);\n// Later:\nawait subscription.cancel();\nIn a widget:\nStreamBuilder(\n stream: NetworkDiagnostic.onConnectivityChanged,\n builder: (context, snapshot) {\n final info = snapshot.data;\n if (info == null) return const Text('Checking…');\n return Text('${info.type.label} · ${info.isConnected}');\n },\n)","connectivity-only-minimal-example--仅连通性最小示例#Connectivity-only: minimal example / 仅连通性:最小示例":"If all you need is \"am I online, on what transport, what IP, and react to\nchanges\", you only need this page — no init() required.如果只需要「在不在線、走什么網络、IP 是多少、切换时通知」,只看本页即可——\n无需 init()。\nclass ConnectivityScreen extends StatelessWidget {\n const ConnectivityScreen({super.key});\n @override\n Widget build(BuildContext context) {\n return StreamBuilder(\n stream: NetworkDiagnostic.onConnectivityChanged,\n builder: (context, snap) {\n final c = snap.data;\n if (c == null) {\n return const Center(child: CircularProgressIndicator());\n }\n return ListView(\n children: [\n ListTile(title: const Text('Type / 类型'), trailing: Text(c.type.label)),\n ListTile(title: const Text('Online / 在线'), trailing: Text('${c.isConnected}')),\n ListTile(title: const Text('IPv4'), trailing: Text(c.ipAddress ?? '—')),\n ListTile(title: const Text('IPv6'), trailing: Text(c.ipv6Address ?? '—')),\n ],\n );\n },\n );\n }\n}"}},"/DNS":{"title":"DNS / DNS 解析","data":{"":"NetworkDiagnostic.resolve() tests DNS resolution across multiple servers in\nparallel, so you can spot the fastest one. Each result is either the system\nresolver or a raw UDP query against an explicit server.NetworkDiagnostic.resolve() 并行测试多台 DNS 服务器的解析表现,从而挑出最快的一台。\n每条结果要么来自系统解析器,要么是对指定服务器的原始 UDP 查询。","basic--基础#Basic / 基础":"final results = await NetworkDiagnostic.resolve(\n domain: 'example.com',\n dnsServers: const ['1.1.1.1', '8.8.8.8', '114.114.114.114'],\n timeout: const Duration(seconds: 5),\n concurrent: true,\n includeSystemResolver: true,\n);\nfor (final r in results) {\n if (r.isSuccess) {\n print('${r.server.padRight(16)} → ${r.resolvedIps.join(\", \")} '\n '(${r.responseTimeMs.toStringAsFixed(1)} ms)');\n } else {\n print('${r.server.padRight(16)} ✗ ${r.errorMessage}');\n }\n}\nParameter\tDefault\tMeaning\tdomain\tconfig.dnsDomain\tDomain to resolve\tdnsServers\tconfig.dnsServers\tServers queried in parallel (or in series)\ttimeout\tconfig.dnsTimeout\tTimeout of one query\tconcurrent\ttrue\tQuery all servers at once\tincludeSystemResolver\tfalse\tAlso add a system row\t\nNotes / 说明:\nA row with server == 'system' comes from the OS resolver; the others are raw\nUDP queries against the listed IPs, encoded by the built-in DnsPacket wire\ncodec.\nserver == 'system' 的行来自系统解析器,其余是对指定 IP 的原始 UDP 查询,由内置\nDnsPacket 编解码。\nincludeSystemResolver defaults to false at the facade level — pass\ntrue to include it.\n门面层默认不包含系统解析器,需显式传 true。","pick-the-fastest--挑出最快的#Pick the fastest / 挑出最快的":"final fastest = results\n .where((r) => r.isSuccess)\n .reduce((a, b) => a.responseTimeMs <= b.responseTimeMs ? a : b);\nprint('fastest resolver: ${fastest.server}');"}},"/FAQ":{"title":"FAQ / 常见问题","data":{"do-i-need-to-call-init--需要调用-init-吗#Do I need to call init()? / 需要调用 init() 吗?":"No. Every API falls back to built-in defaults. Call ZeroNetworkKit.init() only\nwhen you want to override defaults (e.g. a custom reachability host or DNS\nservers). Connectivity alone works with zero setup.不需要。每个 API 都走内置默认值。只有在想覆盖默认参数(如自定义可达性主机或 DNS\n服务器)时才调用 ZeroNetworkKit.init()。单用连通性完全零配置。","which-platforms-are-supported--支持哪些平台#Which platforms are supported? / 支持哪些平台?":"Android, iOS, macOS, Windows and Linux. Web is not supported.支持 Android、iOS、macOS、Windows 与 Linux。Web 不支持。详见\nPlatform Support。","why-is-ssid--signalstrength-null-on-desktop--为什么桌面上的-ssid信号强度是-null#Why is ssid / signalStrength null on desktop? / 为什么桌面上的 ssid/信号强度是 null?":"Desktop uses tier A: SSID and RSSI require system APIs that aren't exposed on\nmacOS/Linux/Windows the same way. They are always null on desktop; Windows\nadditionally provides gateway / MAC / DNS / VPN via GetAdaptersAddresses.桌面采用 A 档:SSID 与 RSSI 依赖系统 API,在桌面上不以同样方式暴露,因此恒为 null;\nWindows 额外通过 GetAdaptersAddresses 提供网关 / MAC / DNS / VPN。","why-does-getnativenetworkdetails-return-null--为什么-getnativenetworkdetails-返回-null#Why does getNativeNetworkDetails() return null? / 为什么 getNativeNetworkDetails 返回 null?":"Either the platform has no such data (e.g. desktop tier A), or the required\npermission is missing (e.g. location for Wi-Fi SSID on Android/iOS). The call\nnever throws — it degrades gracefully.要么是平台没有该数据(如桌面 A 档),要么是缺权限(如 Android/iOS 上读取 Wi-Fi SSID\n需定位权限)。该调用绝不抛异常,会优雅降级。","does-the-speed-test-use-my-bandwidth--测速会消耗我的流量吗#Does the speed test use my bandwidth? / 测速会消耗我的流量吗?":"Yes — the default endpoints are Cloudflare's public service and download ≈25 MB\nby default. Ask for consent on metered connections and override downloadUrl /\nuploadUrl for production.会——默认端点指向 Cloudflare 公共服务,默认下载约 25 MB。在按量计费网络上请征得同意,\n生产环境请替换 downloadUrl / uploadUrl。","how-do-i-test-my-integration-without-the-network--如何脱离网络测试我的集成#How do I test my integration without the network? / 如何脱离网络测试我的集成?":"Every service is injectable. Implement ConnectivityAdapter (or pass fake\nservice instances) and call NetworkDiagnostic.configure(...), then\nNetworkDiagnostic.reset() to restore defaults. See\nUsage → Dependency injection.每个服务都可注入。实现 ConnectivityAdapter(或直接传入假服务实例)后调用\nNetworkDiagnostic.configure(...),再用 NetworkDiagnostic.reset() 恢复默认。详见\n用法 → 依赖注入。","how-is-this-licensed--采用什么许可证#How is this licensed? / 采用什么许可证?":"MPL-2.0. See the repository LICENSE.采用 MPL-2.0。详见仓库 LICENSE。"}},"/Full-Report":{"title":"Full Report / 汇总报告","data":{"":"NetworkDiagnostic.diagnose() runs every probe you ask for and aggregates them\ninto one NetworkDiagnosticReport. A failing sub-test never aborts the run — its\nfield simply stays empty/null.NetworkDiagnostic.diagnose() 运行你指定的各项探测,并汇总为一份\nNetworkDiagnosticReport。任何子项失败都不会中断整体流程,对应字段保持空。","basic--基础#Basic / 基础":"final report = await NetworkDiagnostic.diagnose(\n includePing: true,\n includeDns: true,\n includePorts: true,\n includeSpeedTest: true,\n includeUpload: true,\n host: '1.1.1.1',\n dnsDomain: 'example.com',\n dnsServers: const ['1.1.1.1', '8.8.8.8'],\n ports: const [80, 443],\n);\nprint(report); // one-line summary\nprint(report.connection.type.label);\nprint(report.ping?.averageTime);\nprint(report.dnsResults.length);\nprint(report.portResults.where((p) => p.isOpen).length);\nprint(report.speedTest?.downloadSpeed);\nprint(report.quality.level.label);\nParameter\tDefault\tMeaning\tincludePing\ttrue\tSample latency / jitter / loss\tincludeDns\ttrue\tSample DNS latency\tincludePorts\tfalse\tScan ports (off by default)\tincludeSpeedTest\ttrue\tSample download / upload\tincludeUpload\ttrue\tInclude the upload metric\thost\tconfig.pingHost\tLatency / port target\tdnsDomain / dnsServers\tfrom config\tDNS target\tports\tconfig.probePorts\tPorts scanned when includePorts is true\t\nincludePorts defaults to false, so a default run does not scan ports.\nincludePorts 默认 false,默认运行不会扫描端口。\nThe report is JSON-encodable via report.toMap().\n报告可通过 report.toMap() 序列化为 JSON。"}},"/Getting-Started":{"title":"Getting Started / 快速开始","data":{"quick-start--快速开始#Quick Start / 快速开始":"Import the package and start diagnosing — no init() required:导入包即可开始诊断,无需 init():\nimport 'package:flutter/material.dart';\nimport 'package:zero_network_kit/zero_network_kit.dart';\nvoid main() {\n // Optional: apply your own global defaults once.\n // 可选:全局定制一次默认参数。\n ZeroNetworkKit.init(\n config: const NetworkDiagnosticConfig(pingHost: '1.1.1.1'),\n );\n runApp(const MyApp());\n}\nIf you only need connectivity, you don't even need init():如果只需要连通性,连 init() 都不需要:\nfinal connection = await NetworkDiagnostic.checkConnection();\nprint('${connection.type.label} · ${connection.ipAddress}');","what-you-get--你能得到什么#What you get / 你能得到什么":"Every method is a static, non-blocking call on the NetworkDiagnostic facade.\nThe plugin is pure Dart under the hood, so it is fully injectable and testable\nwithout touching the network.每个方法都是 NetworkDiagnostic 门面上的静态、非阻塞调用。插件内核是纯 Dart,\n因此完全可注入、可脱离网络做测试。\nNeed\tCall\tAm I online, on what transport?\tNetworkDiagnostic.checkConnection()\tReact to Wi-Fi ⇄ cellular switches\tNetworkDiagnostic.onConnectivityChanged\tLatency, jitter, packet loss\tNetworkDiagnostic.ping()\tIs DNS slow or broken?\tNetworkDiagnostic.resolve()\tIs host:port reachable?\tNetworkDiagnostic.checkPort() / isPortOpen()\tHow fast is down/up?\tNetworkDiagnostic.runSpeedTest()\tOne number for \"good or bad\"\tNetworkDiagnostic.evaluateQuality()\tEverything at once\tNetworkDiagnostic.diagnose()\tNative version / SSID / gateway / MAC\tZeroNetworkKit.getNativeNetworkDetails()\t\nSee Which API do I need? for the full map.","lifecycle--生命周期#Lifecycle / 生命周期":"ZeroNetworkKit.isInitialized; // false until init() runs\nZeroNetworkKit.config; // the effective NetworkDiagnosticConfig\nawait ZeroNetworkKit.dispose(); // releases the HTTP client the plugin owns\ndispose() only closes the HTTP client the plugin created itself. An\nhttp.Client you injected stays open — close it yourself.dispose() 只会关闭插件自己创建的 HTTP 客户端;你注入的 http.Client 不会被关闭。","next-steps--下一步#Next Steps / 下一步":"Installation — Detailed installation methods / 详细安装方式\nUsage — Global config & dependency injection / 全局配置与依赖注入\nPlatform Support — Capability matrix / 能力矩阵"}},"/Installation":{"title":"Installation / 安装","data":{"from-pubdev-recommended--从-pubdev-安装推荐#From pub.dev (Recommended) / 从 pub.dev 安装(推荐)":"Add the following to your pubspec.yaml:在 pubspec.yaml 中添加以下依赖:\ndependencies:\n zero_network_kit: ^1.0.1\nThen run:然后运行:\nflutter pub get","from-github--从-github-安装#From GitHub / 从 GitHub 安装":"Alternatively, install from GitHub:或者从 GitHub 安装:\ndependencies:\n zero_network_kit:\n git:\n url: https://github.com/zero-labsco/zero_network_kit.git\n ref: release/v1.0.1","platform-setup--平台配置#Platform Setup / 平台配置":"","android#Android":"The plugin manifest already declares INTERNET, ACCESS_NETWORK_STATE and\nACCESS_WIFI_STATE. Reading the Wi-Fi SSID additionally requires the\nlocation permission (ACCESS_FINE_LOCATION) on Android 8.1+, otherwise the\nsnapshot reports ssid: null.插件清单已声明 INTERNET、ACCESS_NETWORK_STATE 与 ACCESS_WIFI_STATE。读取 Wi-Fi\nSSID 还需在 Android 8.1+ 申请定位权限(ACCESS_FINE_LOCATION),否则快照中\nssid 为 null。","ios#iOS":"No additional configuration needed. Reading the Wi-Fi SSID additionally\nrequires the Access WiFi Information capability plus location authorisation.无需额外配置。读取 Wi-Fi SSID 还需开启 Access WiFi Information 能力并授权定位。","macos--windows--linux#macOS / Windows / Linux":"The plugin is declared on all three desktop platforms. On desktop, native\ndetails such as SSID / RSSI are always null (tier A). Windows additionally\nprovides gateway / MAC / DNS / VPN through GetAdaptersAddresses; macOS and\nLinux report only the Dart-side IP/IPv6. See\nPlatform Support for the full matrix.插件已在三个桌面平台声明。桌面上 SSID / 信号强度等原生详情恒为 null(A 档)。\nWindows 额外通过 GetAdaptersAddresses 提供网关 / MAC / DNS / VPN;macOS 与 Linux\n仅提供 Dart 侧的 IP/IPv6。完整矩阵见平台支持。","import--导入#Import / 导入":"import 'package:zero_network_kit/zero_network_kit.dart';","requirements--环境要求#Requirements / 环境要求":"Requirement\tVersion\tFlutter\t>= 3.3.0\tDart SDK\t>= 3.11.0 < 4.0.0","next-steps--下一步#Next Steps / 下一步":"Getting Started — Quick start guide / 快速开始\nUsage — Full usage guide / 完整使用指南"}},"/Ping":{"title":"Latency / Ping / 延迟探测","data":{"":"NetworkDiagnostic.ping() measures round-trip time towards a target host and\nreports sent / received counts, packet loss, min/avg/max and jitter.NetworkDiagnostic.ping() 测量到目标主机的往返时间,并给出发送/接收次数、丢包率、\n最小/平均/最大耗时与抖动。","basic--基础#Basic / 基础":"final ping = await NetworkDiagnostic.ping(\n host: '1.1.1.1',\n count: 5,\n timeout: const Duration(seconds: 2),\n interval: const Duration(milliseconds: 200),\n port: 443,\n);\nprint('received : ${ping.received}/${ping.sent}');\nprint('loss : ${ping.packetLoss.toStringAsFixed(1)} %');\nprint('min/avg/max: ${ping.minTime.toStringAsFixed(1)} / '\n '${ping.averageTime.toStringAsFixed(1)} / '\n '${ping.maxTime.toStringAsFixed(1)} ms');\nprint('jitter : ${ping.jitter.toStringAsFixed(2)} ms');\nprint('samples : ${ping.times}');\nParameter\tDefault\tMeaning\thost\tconfig.pingHost\tTarget host\tcount\tconfig.pingCount\tNumber of probes\ttimeout\tconfig.pingTimeout\tPer-probe timeout\tinterval\tconfig.pingInterval\tDelay between probes\tport\tconfig.pingPort\tTCP port probed in PingMode.tcp\tmode\tPingMode.tcp\tPingMode.tcp or PingMode.icmp","tcp-vs-icmp--tcp-与-icmp#TCP vs ICMP / TCP 与 ICMP":"PingMode.tcp performs a TCP handshake to host:port — the portable equivalent\nof ICMP and the only mode available on Android/iOS.PingMode.tcp 通过 TCP 握手到 host:port 测量往返,是移动端唯一可用的模式。\n// Desktop only — falls back gracefully if the `ping` binary is unavailable.\nawait NetworkDiagnostic.ping(host: '1.1.1.1', count: 4, mode: PingMode.icmp);\nping.isSuccess is true when at least one probe answered; check it before\ntrusting the averages.至少一次成功响应时 isSuccess 为 true,读平均值前建议先判断它。\nA TCP ping needs a listening port. Probing host with port: 443 fails if\nthat host does not accept TCP/443 — that is \"filtered\", not \"offline\". Use\nmode: PingMode.icmp on desktop to get closer to real ICMP.\nTCP 探测需要一个在监听的端口。对不接受 TCP/443 的主机探测 port: 443 会失败——\n那是“被过滤”,不是“离线”。在桌面上用 PingMode.icmp 更接近真实 ICMP。"}},"/Platform-Support":{"title":"Platform Support / 平台支持","data":{"":"zero_network_kit is declared on five plugin platforms: Android, iOS,\nmacOS, Windows and Linux. Web is not supported — the Dart services rely on\ndart:io, which does not compile for the web, and browsers have no raw\nTCP/UDP sockets.zero_network_kit 在 五 个插件平台上声明:Android、iOS、macOS、Windows 与\nLinux。不支持 Web——Dart 服务依赖 dart:io(无法在 Web 上编译),且浏览器没有\n原生 TCP/UDP 套接字。","capability-matrix--能力矩阵#Capability matrix / 能力矩阵":"Capability\tAndroid / iOS\tDesktop (macOS / Windows / Linux)\tConnectivity (connectivity_plus)\t✅\t✅\tLocal IP / IPv6 (NetworkInterface)\t✅\t✅\tNative details (SSID / gateway / MAC / VPN)\t✅\t⚠️ see below\tTCP ping\t✅\t✅\tICMP ping (Process.run('ping'))\t❌\t✅\tHTTP ping\t✅\t✅\tDNS system resolver\t✅\t✅\tDNS raw UDP\t✅\t✅\tPort check / scan\t✅\t✅\tSpeed test\t✅\t✅\tQuality score\t✅\t✅\tBenchmarks\t✅\t✅","networkcapabilities--能力查询#NetworkCapabilities / 能力查询":"Query the host platform before calling, so your UI can hide unsupported cards:在调用前查询当前平台能力,UI 即可据此隐藏不支持的卡片:\nfinal caps = NetworkDiagnostic.capabilities;\nprint(caps.platform); // 'android' | 'ios' | 'macos' | 'windows' | 'linux'\nprint(caps.supports(NetworkCapability.nativeDetails)); // mobile: true, desktop: false\nprint(caps.supports(NetworkCapability.icmpPing)); // desktop: true, mobile: false\nRules baked into NetworkCapabilities.current():\nnativeDetails is mobile-only (SSID / gateway / MAC / VPN need system APIs).\nicmpPing is desktop-only (uses the system ping binary).\nNetworkCapabilities.current() 内置规则:\nnativeDetails 仅移动端(SSID / 网关 / MAC / VPN 需要系统 API)。\nicmpPing 仅桌面(使用系统 ping 命令)。","native-details-on-desktop--桌面原生详情#Native details on desktop / 桌面原生详情":"Desktop uses tier A by default: the native layer only reports the platform\nversion and an (often empty) details map. IP/IPv6 come from Dart\nNetworkInterface. As a result:桌面默认采用 A 档:原生层只报告平台版本与(通常为空的)详情 map,IP/IPv6 由 Dart\nNetworkInterface 兜底。因此:\nSSID / signal strength are always null on desktop.\n桌面上的 SSID / 信号强度恒为 null。\ngateway / macAddress / isVpn are null on macOS and Linux.\nmacOS 与 Linux 上 gateway / macAddress / isVpn 为 null。\nWindows additionally implements GetAdaptersAddresses, so it reports\ngateway / macAddress / DNS / isVpn (SSID still null). This is a bonus\ntier-B fragment kept as-is.\nWindows 额外实现了 GetAdaptersAddresses,因此上报 gateway / macAddress /\nDNS / isVpn(SSID 仍为 null)。这是保留的 B 档赠品。\nWhatever the platform, a missing permission or an unreachable native call never\nthrows — the field simply stays null and the rest of the result still arrives.无论在哪个平台,缺权限或原生调用不可达都不会抛异常——对应字段保持 null,其余\n结果照常返回。","reading-native-data--读取原生数据#Reading native data / 读取原生数据":"final version = await ZeroNetworkKit.getPlatformVersion();\nprint(version); // e.g. 'Android 14' / 'iOS 18.0'\nfinal details = await ZeroNetworkKit.getNativeNetworkDetails();\nif (details != null) {\n print(details); // SSID, BSSID, gateway, MAC, VPN flag, RSSI …\n}"}},"/Ports":{"title":"Ports / 端口检测","data":{"":"checkPort() returns a full PortCheckResult for one port; isPortOpen() is the\nplain boolean convenience; scanPorts() runs many ports concurrently with\nbounded in-flight connections.checkPort() 返回单个端口的完整 PortCheckResult;isPortOpen() 是便捷的布尔版;\nscanPorts() 以有界并发批量扫描多个端口。","single-port--单端口#Single port / 单端口":"// Boolean convenience / 便捷布尔版\nfinal open = await NetworkDiagnostic.isPortOpen(\n host: 'example.com',\n port: 443,\n timeout: const Duration(seconds: 3),\n);\nprint(open ? 'HTTPS reachable' : 'HTTPS unreachable');\n// Full result with RTT and error message / 含 RTT 与错误信息的完整结果\nfinal result = await NetworkDiagnostic.checkPort(host: 'example.com', port: 443);\nprint('open=${result.isOpen} rtt=${result.responseTimeMs} ms '\n 'err=${result.errorMessage}');","bulk-scan--批量扫描#Bulk scan / 批量扫描":"final scan = await NetworkDiagnostic.scanPorts(\n host: 'example.com',\n ports: const [22, 80, 443, 8080, 8443],\n concurrency: 8,\n);\nfor (final r in scan) {\n print('${r.host}:${r.port} '\n '${r.isOpen ? \"open\" : \"closed\"} '\n '${r.responseTimeMs.toStringAsFixed(1)} ms '\n '${r.errorMessage ?? \"\"}');\n}\nParameter\tDefault\tMeaning\tports (scanPorts)\tconfig.probePorts ([80, 443])\tPorts to probe\tconcurrency\t12\tMax in-flight connections\ttimeout\tconfig.portCheckTimeout\tTimeout per port\t\ncheckPort() returns a PortCheckResult (with isOpen, responseTimeMs\nand errorMessage); use isPortOpen() for a plain boolean. When you need the\nround-trip time or the failure reason for a single port, call checkPort()\ndirectly or pass a one-element list to scanPorts():\nscanPorts(host: 'example.com', ports: [443]).first.\ncheckPort() 返回 PortCheckResult(含 isOpen、responseTimeMs、\nerrorMessage);单端口布尔诉求请用 isPortOpen()。需要 RTT 或失败原因时可直接\n调用 checkPort(),或给 scanPorts(..., ports: [443]) 取单条结果。"}},"/Quality":{"title":"Quality Score / 质量评分","data":{"":"NetworkDiagnostic.evaluateQuality() returns a weighted 0–100 score plus a\nlevel and human-readable suggestions, computed over whatever metrics are\navailable.NetworkDiagnostic.evaluateQuality() 返回一个加权 0–100 分,附带等级与可读建议,\n它基于当前可用的各项指标计算得出。","basic--基础#Basic / 基础":"final quality = await NetworkDiagnostic.evaluateQuality(\n includePing: true,\n includeDns: true,\n includeSpeedTest: true,\n includeUpload: true,\n);\nprint('${quality.score.toStringAsFixed(1)}/100 — ${quality.level.label}');\nquality.metrics.forEach((metric, value) {\n print(' $metric = ${value.toStringAsFixed(2)}');\n});\nfor (final suggestion in quality.suggestions) {\n print('• $suggestion');\n}\nParameter\tDefault\tMeaning\tincludePing\ttrue\tSample latency / jitter / loss\tincludeDns\ttrue\tSample DNS latency\tincludeSpeedTest\ttrue\tSample download / upload (heavy)\tincludeUpload\ttrue\tInclude the upload metric\tpingHost / pingCount\tfrom config\tLatency target\tdnsDomain / dnsServers\tfrom config\tDNS target\tdownloadUrl / uploadUrl\tfrom config\tBandwidth endpoints","lightweight-variant--轻量变体#Lightweight variant / 轻量变体":"final quality = await NetworkDiagnostic.evaluateQuality(includeSpeedTest: false);","level-thresholds--等级阈值#Level thresholds / 等级阈值":"≥90 excellent · ≥75 good · ≥60 fair · ≥40 poor · otherwise bad\n(NetworkQualityLevel.fromScore).≥90 极佳 · ≥75 良好 · ≥60 一般 · ≥40 较差 · 其余为极差。","weights--权重#Weights / 权重":"Metric\tWeight\tSource\tlatency\t0.25\tPingResult.averageTime\tjitter\t0.10\tPingResult.jitter\tpacketLoss\t0.15\tPingResult.packetLoss\tdownload\t0.25\tSpeedTestResult.downloadSpeed\tupload\t0.15\tSpeedTestResult.uploadSpeed\tdns\t0.10\tmean of successful DnsTestResult.responseTimeMs\tsignalStrength\t0.10\tNetworkConnectionInfo.signalStrength","pure-function--纯函数#Pure function / 纯函数":"If you already have the metrics, skip the network entirely:如果你已有指标,可完全跳过网络:\nfinal score = NetworkQualityEvaluator.evaluate(\n latency: 42, jitter: 6, packetLoss: 0,\n download: 88.4, upload: 12.1, dns: 25, signalStrength: -55,\n targets: const QualityTargets(),\n);\nprint('${score.score.toStringAsFixed(1)} → ${score.level.label}');\nTune the ideal values globally through NetworkDiagnosticConfig(qualityTargets: ...).\n调整理想值请通过 NetworkDiagnosticConfig(qualityTargets: ...) 全局设置。"}},"/Speed-Test":{"title":"Speed Test / 测速","data":{"":"NetworkDiagnostic.runSpeedTest() measures download and upload throughput and\nsamples latency during the run, reporting progress through onProgress.NetworkDiagnostic.runSpeedTest() 测量下载与上传吞吐量,并在过程中采样延迟,通过\nonProgress 汇报进度。","basic--基础#Basic / 基础":"final speed = await NetworkDiagnostic.runSpeedTest(\n includeUpload: true,\n includePing: true,\n onProgress: (progress) {\n print('${progress.phase.name}: '\n '${progress.speedMbps.toStringAsFixed(1)} Mbps '\n '(${progress.bytes} bytes, ${progress.elapsed.inMilliseconds} ms)');\n },\n);\nprint('download : ${speed.downloadSpeed.toStringAsFixed(2)} Mbps');\nprint('upload : ${speed.uploadSpeed.toStringAsFixed(2)} Mbps');\nprint('ping : ${speed.ping.toStringAsFixed(1)} ms');\nprint('jitter : ${speed.jitter.toStringAsFixed(2)} ms');\nprint('loss : ${speed.packetLoss.toStringAsFixed(1)} %');\nprint('server : ${speed.server}');\nprint('duration : ${speed.duration.inMilliseconds} ms');\nParameter\tDefault\tMeaning\tdownloadUrl / uploadUrl\tfrom config\tEndpoints used\ttimeout\tconfig.speedTestTimeout\tPer-request timeout\tmaxDuration\tconfig.speedTestMaxDuration\tSampling window per phase\tuploadPayloadBytes\tconfig.uploadPayloadBytes\tUpload size\tpingHost / pingCount\tfrom config\tLatency sampled during the test\tincludeUpload\ttrue\tSkip the upload phase\tincludePing\ttrue\tSkip the latency sample\tonProgress\tnull\tCalled repeatedly during both phases\t\nProgress phases: SpeedTestPhase.download → SpeedTestPhase.upload →\nSpeedTestPhase.completed.进度阶段依次为 download → upload → completed。","fast-low-traffic-variant--轻量低流量变体#Fast, low-traffic variant / 轻量低流量变体":"final quick = await NetworkDiagnostic.runSpeedTest(\n includeUpload: false,\n includePing: false,\n maxDuration: const Duration(seconds: 5),\n);\nThe default endpoints point at Cloudflare's public speed service and move real\ntraffic (≈25 MB download by default). Ask for consent before running it on a\nmetered connection, and override downloadUrl / uploadUrl for production.\n默认端点指向 Cloudflare 公共服务并会产生真实流量(默认下载约 25 MB)。在按量计费\n网络上运行前请征得同意,并为生产环境替换 downloadUrl / uploadUrl。"}},"/Usage":{"title":"Usage / 用法","data":{"which-api-do-i-need--该用哪个-api#Which API do I need? / 该用哪个 API?":"I want to know…\tCall\tAm I online, and over what transport?\tNetworkDiagnostic.checkConnection()\tReact to Wi-Fi ⇄ cellular switches\tNetworkDiagnostic.onConnectivityChanged\tLatency, jitter, packet loss\tNetworkDiagnostic.ping()\tIs DNS slow or broken?\tNetworkDiagnostic.resolve()\tIs host:port reachable?\tNetworkDiagnostic.checkPort()\tWhich of these ports are open?\tNetworkDiagnostic.scanPorts()\tHow fast is down/up?\tNetworkDiagnostic.runSpeedTest()\tOne number for “good or bad”\tNetworkDiagnostic.evaluateQuality()\tEverything at once, as a report\tNetworkDiagnostic.diagnose()\tIs the diagnostics API itself expensive?\tNetworkBenchmark.runAll()\tNative version / SSID / gateway / MAC\tZeroNetworkKit.getPlatformVersion(), getNativeNetworkDetails()","global-configuration--全局配置#Global configuration / 全局配置":"NetworkDiagnosticConfig centralises every default. Override only what you\nneed; the rest keep the defaults below.NetworkDiagnosticConfig 集中了全部默认参数,只需覆盖你关心的字段。\nZeroNetworkKit.init(\n config: const NetworkDiagnosticConfig(\n pingHost: '1.1.1.1',\n pingPort: 443,\n pingCount: 5,\n dnsDomain: 'example.com',\n dnsServers: ['1.1.1.1', '8.8.8.8'],\n downloadUrl: 'https://my-cdn.example.com/speedtest.bin',\n uploadUrl: 'https://my-cdn.example.com/upload',\n ),\n);\nField\tDefault\tMeaning\tpingHost\t'1.1.1.1'\tDefault ping / port-scan target\tpingPort\t443\tPort used by the TCP ping\tpingCount\t4\tProbes per ping run\tpingTimeout\t3s\tTimeout of one probe\tpingInterval\t200ms\tDelay between probes\tdnsDomain\t'www.google.com'\tDefault domain for DNS tests\tdnsServers\t['1.1.1.1', '8.8.8.8', '114.114.114.114']\tServers queried by default\tdnsTimeout\t5s\tTimeout per DNS server\tdownloadUrl\tCloudflare __down?bytes=25000000\tDownload endpoint\tuploadUrl\tCloudflare __up\tUpload endpoint\tuploadPayloadBytes\t1048576 (1 MiB)\tUpload payload size\tspeedTestTimeout\t30s\tPer-request timeout\tspeedTestMaxDuration\t10s\tSampling window per phase\tportCheckTimeout\t3s\tTimeout of one port check\tprobePorts\t[80, 443]\tPorts used by scanPorts() by default\tqualityTargets\tconst QualityTargets()\tIdeal values for scoring\t\nThe default speed-test endpoints are Cloudflare's public service. Swap them for\nyour own before shipping production traffic.\n默认测速端点是 Cloudflare 的公共服务,正式项目请替换为自建端点。","quality-targets--质量评分理想值#Quality targets / 质量评分理想值":"const NetworkDiagnosticConfig(\n qualityTargets: QualityTargets(\n excellentLatency: 30, // ms\n acceptableLatency: 150, // ms\n excellentJitter: 5, // ms\n acceptableJitter: 40, // ms\n acceptablePacketLoss: 5, // %\n excellentDownload: 50, // Mbps\n acceptableDownload: 5, // Mbps\n excellentUpload: 20, // Mbps\n acceptableUpload: 2, // Mbps\n excellentDns: 30, // ms\n acceptableDns: 200, // ms\n ),\n);","json-serialisation--序列化#JSON serialisation / 序列化":"Every result object implements toMap() and is JSON encodable:每个结果对象都实现了 toMap(),可直接 JSON 序列化:\nimport 'dart:convert';\nfinal report = await NetworkDiagnostic.diagnose(includeSpeedTest: false);\nfinal json = jsonEncode(report.toMap());\nprint(json);\n// Round-trip a connection snapshot.\nfinal decoded = NetworkConnectionInfo.fromMap(jsonDecode(jsonEncode(\n report.connection.toMap(),\n)) as Map);\nType\tSerialisation\tNetworkConnectionInfo\ttoMap() + fromMap()\tPingResult\ttoMap()\tDnsTestResult\ttoMap()\tPortCheckResult\ttoMap()\tSpeedTestResult\ttoMap()\tNetworkQualityScore\ttoMap()\tNetworkDiagnosticReport\ttoMap()\tBenchmarkResult / BenchmarkSuiteResult\ttoMap()","dependency-injection--tests--注入与测试#Dependency injection & tests / 注入与测试":"Every service accepts its collaborators, so your integration points are\nunit-testable without touching the network.每个服务都支持注入协作对象,可以完全脱离网络做单测。\nclass FakeConnectivityAdapter implements ConnectivityAdapter {\n @override\n Future> checkConnectivity() async => ['wifi'];\n @override\n Stream> get onConnectivityChanged => const Stream.empty();\n}\nNetworkDiagnostic.configure(\n config: const NetworkDiagnosticConfig(pingHost: '127.0.0.1'),\n connectivity: ConnectivityService(adapter: FakeConnectivityAdapter()),\n ping: PingService(),\n dns: DnsService(),\n ports: PortService(),\n speedTest: SpeedTestService(client: fakeClient),\n);\n// Restore defaults afterwards.\nNetworkDiagnostic.reset();\nSwap individual services directly when you prefer:也可以直接替换单个服务:\nNetworkDiagnostic.pingService = MyFakePingService();\nNetworkDiagnostic.dnsService = MyFakeDnsService();\nFor advanced service classes, the DNS wire codec and low-level APIs, import\npackage:zero_network_kit/advanced.dart.\n进阶的服务类、DNS 报文编解码器等底层 API 请通过\npackage:zero_network_kit/advanced.dart 引入。"}},"/":{"title":"Zero Network Kit","data":{"":"A Flutter plugin for network diagnostics: connectivity inspection, latency\nprobing, DNS resolution, port checks, bandwidth measurement, quality scoring and\nmicro-benchmarks — on Android, iOS, macOS, Windows and Linux.一个 Flutter 插件,提供网络诊断能力:连通性检测、延迟探测、DNS 解析、端口\n检测、带宽测速、质量评分与微基准测试——覆盖 Android、iOS、macOS、Windows 与 Linux。","-features--功能特性#✨ Features / 功能特性":"Feature\tDescription\tZero setup\tWorks out of the box; init() only to override defaults / 开箱即用,仅需在想覆盖默认值时才 init()\tConnectivity\tTransport type, IPv4/IPv6, gateway, SSID, RSSI, MAC, VPN / 传输类型、IPv4/IPv6、网关、SSID、信号强度、MAC、VPN\tLatency\tTCP handshake RTT everywhere; system ICMP on desktop / TCP 握手 RTT 全平台可用,桌面额外支持系统 ICMP\tDNS\tSystem resolver + raw UDP against explicit servers / 系统解析器 + 针对指定服务器的原始 UDP 查询\tPorts\tBounded-concurrency TCP reachability / 有界并发的 TCP 可达性检测\tSpeed test\tDownload/upload throughput with progress callbacks / 上下行测速,带进度回调\tQuality\tWeighted 0–100 score + level + suggestions / 加权 0–100 分 + 等级 + 建议\tFull report\tOne-shot aggregate of every probe / 一次性汇总所有探测\tBenchmarks\tMeasures how fast the diagnostics API itself runs / 衡量诊断 API 自身开销\tCapabilities\tQuery-then-call; hide unsupported cards (e.g. SSID on desktop) / 先查询后调用,隐藏不支持的卡片\tGraceful degradation\tMissing permission or unreachable sub-service never throws / 缺权限或子服务不可达时只返回 null,绝不抛异常\tHermetic tests\tEvery service accepts injected collaborators / 每个服务都支持注入协作对象,便于单测","-table-of-contents--目录#📚 Table of Contents / 目录":"Page\tDescription\tGetting Started\tQuick start guide / 快速开始\tInstallation\tHow to install / 安装方式\tUsage\tGlobal config, serialisation, dependency injection / 全局配置、序列化、依赖注入\tConnectivity\tConnection snapshot & change stream / 连通性快照与变化监听\tLatency / Ping\tTCP & ICMP latency probing / 延迟探测\tDNS\tResolver comparison across servers / DNS 解析\tPorts\tSingle port & bulk scan / 端口检测\tSpeed Test\tDownload/upload throughput / 测速\tQuality Score\tWeighted scoring / 质量评分\tFull Report\tOne-shot aggregate / 汇总报告\tBenchmarks\tMicro-benchmarks / 微基准\tPlatform Support\tCapability matrix & native details / 能力矩阵与原生详情\tAPI Reference\tModel field reference & gotchas / 模型字段速查与陷阱\tFAQ\tFrequently asked questions / 常见问题","-links--链接#🔗 Links / 链接":"GitHub\nOfficial Website\npub.dev","-license--许可证#📄 License / 许可证":"This project is licensed under the MPL-2.0.本项目采用 MPL-2.0 许可证。This plugin is provided \"as is\", without warranty of any kind. The author assumes\nno responsibility or liability for the functionality, security, or any\nconsequences arising from the use of modified versions or derivative projects.本插件按\"原样\"提供,不提供任何担保。作者不对修改版或衍生项目的功能、安全性及\n任何使用后果承担责任。"}}} \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/API-Reference-8e9a91f2d08796c0.js b/docs/_next/static/chunks/pages/API-Reference-8e9a91f2d08796c0.js deleted file mode 100644 index a9c332f..0000000 --- a/docs/_next/static/chunks/pages/API-Reference-8e9a91f2d08796c0.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[274],{9166:function(e,n,d){(window.__NEXT_P=window.__NEXT_P||[]).push(["/API-Reference",function(){return d(6043)}])},6043:function(e,n,d){"use strict";d.r(n),d.d(n,{useTOC:function(){return c}});var r=d(5893),s=d(7812),i=d(7080),t=d(8925);function c(e){let n={code:"code",...(0,t.a)()};return[{value:(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.code,{children:"NetworkType"})}),id:"networktype",depth:2},{value:(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.code,{children:"NetworkConnectionInfo"})}),id:"networkconnectioninfo",depth:2},{value:(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.code,{children:"PingResult"})}),id:"pingresult",depth:2},{value:(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.code,{children:"DnsTestResult"})}),id:"dnstestresult",depth:2},{value:(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.code,{children:"PortCheckResult"})}),id:"portcheckresult",depth:2},{value:(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.code,{children:"SpeedTestResult"})}),id:"speedtestresult",depth:2},{value:(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.code,{children:"SpeedTestProgress"})," / ",(0,r.jsx)(n.code,{children:"SpeedTestPhase"})]}),id:"speedtestprogress--speedtestphase",depth:2},{value:(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.code,{children:"NetworkQualityScore"})," / ",(0,r.jsx)(n.code,{children:"NetworkQualityLevel"})]}),id:"networkqualityscore--networkqualitylevel",depth:2},{value:(0,r.jsx)(r.Fragment,{children:(0,r.jsx)(n.code,{children:"NetworkDiagnosticReport"})}),id:"networkdiagnosticreport",depth:2},{value:(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.code,{children:"BenchmarkResult"})," / ",(0,r.jsx)(n.code,{children:"BenchmarkSuiteResult"})]}),id:"benchmarkresult--benchmarksuiteresult",depth:2},{value:"Gotchas / 常见陷阱",id:"gotchas--常见陷阱",depth:2}]}n.default=(0,s.c)(function(e){let{toc:n=c(e)}=e,d={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,t.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(d.h1,{children:"API Reference / 接口参考"}),"\n",(0,r.jsx)(d.p,{children:"A condensed field reference for every public model. For copy-paste examples of\r\neach method, see the capability pages."}),"\n",(0,r.jsx)(d.p,{children:"这里是每个公开模型的字段速查。每个方法的复制即用示例请见各能力页面。"}),"\n",(0,r.jsx)(d.h2,{id:n[0].id,children:n[0].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,r.jsxs)(d.table,{children:[(0,r.jsx)(d.thead,{children:(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.th,{children:"Member"}),(0,r.jsx)(d.th,{children:"Notes"})]})}),(0,r.jsxs)(d.tbody,{children:[(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:"values"}),(0,r.jsxs)(d.td,{children:[(0,r.jsx)(d.code,{children:"none"}),", ",(0,r.jsx)(d.code,{children:"wifi"}),", ",(0,r.jsx)(d.code,{children:"mobile"}),", ",(0,r.jsx)(d.code,{children:"ethernet"}),", ",(0,r.jsx)(d.code,{children:"vpn"}),", ",(0,r.jsx)(d.code,{children:"bluetooth"}),", ",(0,r.jsx)(d.code,{children:"other"})]})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"label"})}),(0,r.jsxs)(d.td,{children:["Human readable: ",(0,r.jsx)(d.code,{children:"'Wi-Fi'"}),", ",(0,r.jsx)(d.code,{children:"'Mobile'"}),", …"]})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"id"})}),(0,r.jsxs)(d.td,{children:["Stable English identifier (",(0,r.jsx)(d.code,{children:"name"}),"), safe to persist"]})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"isConnected"})}),(0,r.jsxs)(d.td,{children:[(0,r.jsx)(d.code,{children:"true"})," unless ",(0,r.jsx)(d.code,{children:"none"})]})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"NetworkType.fromRaw(Object?)"})}),(0,r.jsx)(d.td,{children:"Parses a raw platform string"})]})]})]}),"\n",(0,r.jsx)(d.h2,{id:n[1].id,children:n[1].value}),"\n",(0,r.jsxs)(d.p,{children:[(0,r.jsx)(d.code,{children:"isConnected"}),", ",(0,r.jsx)(d.code,{children:"type"}),", ",(0,r.jsx)(d.code,{children:"ssid"}),", ",(0,r.jsx)(d.code,{children:"signalStrength"})," (dBm), ",(0,r.jsx)(d.code,{children:"ipAddress"}),",\r\n",(0,r.jsx)(d.code,{children:"ipv6Address"}),", ",(0,r.jsx)(d.code,{children:"gateway"}),", ",(0,r.jsx)(d.code,{children:"macAddress"}),", ",(0,r.jsx)(d.code,{children:"isVpn"}),", ",(0,r.jsx)(d.code,{children:"isReachable"}),", ",(0,r.jsx)(d.code,{children:"timestamp"}),",\r\nplus ",(0,r.jsx)(d.code,{children:"copyWith({bool? isReachable})"}),"."]}),"\n",(0,r.jsx)(d.h2,{id:n[2].id,children:n[2].value}),"\n",(0,r.jsxs)(d.p,{children:["Fields ",(0,r.jsx)(d.code,{children:"host"}),", ",(0,r.jsx)(d.code,{children:"port"}),", ",(0,r.jsx)(d.code,{children:"mode"}),", ",(0,r.jsx)(d.code,{children:"sent"}),", ",(0,r.jsx)(d.code,{children:"received"}),", ",(0,r.jsx)(d.code,{children:"times"}),", ",(0,r.jsx)(d.code,{children:"timestamp"}),";\r\nderived getters ",(0,r.jsx)(d.code,{children:"lost"}),", ",(0,r.jsx)(d.code,{children:"packetLoss"})," (%), ",(0,r.jsx)(d.code,{children:"minTime"}),", ",(0,r.jsx)(d.code,{children:"maxTime"}),", ",(0,r.jsx)(d.code,{children:"averageTime"}),",\r\n",(0,r.jsx)(d.code,{children:"jitter"}),", ",(0,r.jsx)(d.code,{children:"isSuccess"}),"."]}),"\n",(0,r.jsx)(d.h2,{id:n[3].id,children:n[3].value}),"\n",(0,r.jsxs)(d.p,{children:["Fields ",(0,r.jsx)(d.code,{children:"server"}),", ",(0,r.jsx)(d.code,{children:"domain"}),", ",(0,r.jsx)(d.code,{children:"isSuccess"}),", ",(0,r.jsx)(d.code,{children:"responseTime"}),", ",(0,r.jsx)(d.code,{children:"resolvedIps"}),",\r\n",(0,r.jsx)(d.code,{children:"errorMessage"}),", ",(0,r.jsx)(d.code,{children:"timestamp"}),"; derived ",(0,r.jsx)(d.code,{children:"responseTimeMs"}),", ",(0,r.jsx)(d.code,{children:"primaryAddress"}),"."]}),"\n",(0,r.jsx)(d.h2,{id:n[4].id,children:n[4].value}),"\n",(0,r.jsxs)(d.p,{children:["Fields ",(0,r.jsx)(d.code,{children:"host"}),", ",(0,r.jsx)(d.code,{children:"port"}),", ",(0,r.jsx)(d.code,{children:"isOpen"}),", ",(0,r.jsx)(d.code,{children:"responseTime"}),", ",(0,r.jsx)(d.code,{children:"errorMessage"}),", ",(0,r.jsx)(d.code,{children:"timestamp"}),";\r\nderived ",(0,r.jsx)(d.code,{children:"responseTimeMs"}),"."]}),"\n",(0,r.jsx)(d.h2,{id:n[5].id,children:n[5].value}),"\n",(0,r.jsxs)(d.p,{children:["Fields ",(0,r.jsx)(d.code,{children:"downloadSpeed"}),", ",(0,r.jsx)(d.code,{children:"uploadSpeed"})," (Mbps), ",(0,r.jsx)(d.code,{children:"ping"})," (ms), ",(0,r.jsx)(d.code,{children:"jitter"})," (ms),\r\n",(0,r.jsx)(d.code,{children:"packetLoss"})," (%), ",(0,r.jsx)(d.code,{children:"downloadedBytes"}),", ",(0,r.jsx)(d.code,{children:"uploadedBytes"}),", ",(0,r.jsx)(d.code,{children:"downloadDuration"}),",\r\n",(0,r.jsx)(d.code,{children:"uploadDuration"}),", ",(0,r.jsx)(d.code,{children:"server"}),", ",(0,r.jsx)(d.code,{children:"timestamp"}),"; derived ",(0,r.jsx)(d.code,{children:"duration"}),"; static helper\r\n",(0,r.jsx)(d.code,{children:"SpeedTestResult.mbpsFromBytes(bytes, elapsed)"}),"."]}),"\n",(0,r.jsx)(d.h2,{id:n[6].id,children:n[6].value}),"\n",(0,r.jsxs)(d.p,{children:[(0,r.jsx)(d.code,{children:"phase"})," (",(0,r.jsx)(d.code,{children:"download"}),", ",(0,r.jsx)(d.code,{children:"upload"}),", ",(0,r.jsx)(d.code,{children:"completed"}),"), ",(0,r.jsx)(d.code,{children:"bytes"}),", ",(0,r.jsx)(d.code,{children:"elapsed"}),", ",(0,r.jsx)(d.code,{children:"speedMbps"}),"."]}),"\n",(0,r.jsx)(d.h2,{id:n[7].id,children:n[7].value}),"\n",(0,r.jsxs)(d.p,{children:[(0,r.jsx)(d.code,{children:"score"})," (0–100), ",(0,r.jsx)(d.code,{children:"level"}),", ",(0,r.jsx)(d.code,{children:"metrics"})," (",(0,r.jsx)(d.code,{children:"Map"}),"), ",(0,r.jsx)(d.code,{children:"suggestions"}),",\r\n",(0,r.jsx)(d.code,{children:"timestamp"}),"; ",(0,r.jsx)(d.code,{children:"NetworkQualityLevel.fromScore(double)"}),", ",(0,r.jsx)(d.code,{children:"level.label"}),"."]}),"\n",(0,r.jsx)(d.h2,{id:n[8].id,children:n[8].value}),"\n",(0,r.jsxs)(d.p,{children:[(0,r.jsx)(d.code,{children:"connection"}),", ",(0,r.jsx)(d.code,{children:"ping"}),", ",(0,r.jsx)(d.code,{children:"dnsResults"}),", ",(0,r.jsx)(d.code,{children:"portResults"}),", ",(0,r.jsx)(d.code,{children:"speedTest"}),", ",(0,r.jsx)(d.code,{children:"quality"}),",\r\n",(0,r.jsx)(d.code,{children:"timestamp"}),"."]}),"\n",(0,r.jsx)(d.h2,{id:n[9].id,children:n[9].value}),"\n",(0,r.jsxs)(d.p,{children:[(0,r.jsx)(d.code,{children:"BenchmarkResult"}),": ",(0,r.jsx)(d.code,{children:"testName"}),", ",(0,r.jsx)(d.code,{children:"iterations"}),", ",(0,r.jsx)(d.code,{children:"totalDuration"}),",\r\n",(0,r.jsx)(d.code,{children:"averageDuration"}),", ",(0,r.jsx)(d.code,{children:"minDuration"}),", ",(0,r.jsx)(d.code,{children:"maxDuration"}),", ",(0,r.jsx)(d.code,{children:"standardDeviation"}),",\r\n",(0,r.jsx)(d.code,{children:"operationsPerSecond"}),", ",(0,r.jsx)(d.code,{children:"failures"}),", ",(0,r.jsx)(d.code,{children:"timestamp"}),".\r\n",(0,r.jsx)(d.code,{children:"BenchmarkSuiteResult"}),": ",(0,r.jsx)(d.code,{children:"suiteName"}),", ",(0,r.jsx)(d.code,{children:"results"}),", ",(0,r.jsx)(d.code,{children:"totalDuration"}),", ",(0,r.jsx)(d.code,{children:"timestamp"}),",\r\nand ",(0,r.jsx)(d.code,{children:"suite['name']"}),"."]}),"\n",(0,r.jsx)(d.h2,{id:n[10].id,children:n[10].value}),"\n",(0,r.jsxs)(d.ol,{children:["\n",(0,r.jsxs)(d.li,{children:[(0,r.jsxs)(d.strong,{children:[(0,r.jsx)(d.code,{children:"type.label"}),", not ",(0,r.jsx)(d.code,{children:"displayName"}),"."]})," ",(0,r.jsx)(d.code,{children:"NetworkType"})," exposes ",(0,r.jsx)(d.code,{children:"label"})," / ",(0,r.jsx)(d.code,{children:"id"}),"."]}),"\n",(0,r.jsxs)(d.li,{children:[(0,r.jsxs)(d.strong,{children:[(0,r.jsx)(d.code,{children:"checkPort()"})," returns ",(0,r.jsx)(d.code,{children:"PortCheckResult"}),"."]})," Use ",(0,r.jsx)(d.code,{children:"isPortOpen()"})," for a plain\r\nboolean, or ",(0,r.jsx)(d.code,{children:"scanPorts(..., ports: [p]).first"})," for RTT / error message."]}),"\n",(0,r.jsxs)(d.li,{children:[(0,r.jsxs)(d.strong,{children:[(0,r.jsx)(d.code,{children:"includeSystemResolver"})," defaults to ",(0,r.jsx)(d.code,{children:"false"}),"."]})," Pass ",(0,r.jsx)(d.code,{children:"true"})," to add the\r\n",(0,r.jsx)(d.code,{children:"system"})," DNS row."]}),"\n",(0,r.jsxs)(d.li,{children:[(0,r.jsx)(d.strong,{children:"A TCP ping needs a listening port."})," Probing ",(0,r.jsx)(d.code,{children:"host"})," with ",(0,r.jsx)(d.code,{children:"port: 443"})," fails\r\nif that host does not accept TCP/443 — that is “filtered”, not “offline”. Use\r\n",(0,r.jsx)(d.code,{children:"mode: PingMode.icmp"})," on desktop to get closer to real ICMP."]}),"\n",(0,r.jsxs)(d.li,{children:[(0,r.jsxs)(d.strong,{children:[(0,r.jsx)(d.code,{children:"PingMode.icmp"})," is desktop-only"]})," and silently degrades when the ",(0,r.jsx)(d.code,{children:"ping"}),"\r\nbinary is unavailable."]}),"\n",(0,r.jsxs)(d.li,{children:[(0,r.jsx)(d.strong,{children:"The speed test moves real traffic"})," (≈25 MB download by default). Ask for\r\nconsent before running it on a metered connection."]}),"\n",(0,r.jsxs)(d.li,{children:[(0,r.jsx)(d.strong,{children:"Missing permissions degrade, they never throw."})," A missing location\r\npermission yields ",(0,r.jsx)(d.code,{children:"ssid == null"}),"; the rest of the snapshot still arrives."]}),"\n",(0,r.jsxs)(d.li,{children:[(0,r.jsxs)(d.strong,{children:[(0,r.jsx)(d.code,{children:"includePorts"})," is ",(0,r.jsx)(d.code,{children:"false"})," by default"]})," in ",(0,r.jsx)(d.code,{children:"diagnose()"}),"."]}),"\n",(0,r.jsxs)(d.li,{children:[(0,r.jsxs)(d.strong,{children:[(0,r.jsx)(d.code,{children:"init()"})," is optional, but ",(0,r.jsx)(d.code,{children:"dispose()"})," only closes the client the plugin\r\nowns"]})," — an ",(0,r.jsx)(d.code,{children:"httpClient"})," you injected stays open, so close it yourself."]}),"\n"]}),"\n",(0,r.jsxs)(d.blockquote,{children:["\n",(0,r.jsxs)(d.p,{children:["Full source-level API docs live in the repo:\r\n",(0,r.jsx)(d.a,{href:"https://github.com/zero-labsco/zero_network_kit/blob/main/API.md",children:"API.md"}),"\r\n(English) and\r\n",(0,r.jsx)(d.a,{href:"https://github.com/zero-labsco/zero_network_kit/blob/main/API_zh.md",children:"API_zh.md"}),"\r\n(简体中文).\r\n完整源码级 API 文档见仓库内的\r\n",(0,r.jsx)(d.a,{href:"https://github.com/zero-labsco/zero_network_kit/blob/main/API.md",children:"API.md"}),"\r\n与 ",(0,r.jsx)(d.a,{href:"https://github.com/zero-labsco/zero_network_kit/blob/main/API_zh.md",children:"API_zh.md"}),"。"]}),"\n"]})]})},"/API-Reference",{filePath:"pages/API-Reference.md",pageMap:i.v,frontMatter:{},title:"API Reference / 接口参考"},"undefined"==typeof RemoteContent?c:RemoteContent.useTOC)},7080:function(e,n,d){"use strict";d.d(n,{v:function(){return r}});let r=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=9166)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/API-Reference-e13a2917d7546319.js b/docs/_next/static/chunks/pages/API-Reference-e13a2917d7546319.js new file mode 100644 index 0000000..a24c175 --- /dev/null +++ b/docs/_next/static/chunks/pages/API-Reference-e13a2917d7546319.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[274],{9166:function(e,n,d){(window.__NEXT_P=window.__NEXT_P||[]).push(["/API-Reference",function(){return d(6043)}])},6043:function(e,n,d){"use strict";d.r(n),d.d(n,{useTOC:function(){return c}});var s=d(5893),r=d(7812),i=d(7080),t=d(8925);function c(e){let n={code:"code",...(0,t.a)()};return[{value:(0,s.jsx)(s.Fragment,{children:(0,s.jsx)(n.code,{children:"NetworkType"})}),id:"networktype",depth:2},{value:(0,s.jsx)(s.Fragment,{children:(0,s.jsx)(n.code,{children:"NetworkConnectionInfo"})}),id:"networkconnectioninfo",depth:2},{value:(0,s.jsx)(s.Fragment,{children:(0,s.jsx)(n.code,{children:"PingResult"})}),id:"pingresult",depth:2},{value:(0,s.jsx)(s.Fragment,{children:(0,s.jsx)(n.code,{children:"DnsTestResult"})}),id:"dnstestresult",depth:2},{value:(0,s.jsx)(s.Fragment,{children:(0,s.jsx)(n.code,{children:"PortCheckResult"})}),id:"portcheckresult",depth:2},{value:(0,s.jsx)(s.Fragment,{children:(0,s.jsx)(n.code,{children:"SpeedTestResult"})}),id:"speedtestresult",depth:2},{value:(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.code,{children:"SpeedTestProgress"})," / ",(0,s.jsx)(n.code,{children:"SpeedTestPhase"})]}),id:"speedtestprogress--speedtestphase",depth:2},{value:(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.code,{children:"NetworkQualityScore"})," / ",(0,s.jsx)(n.code,{children:"NetworkQualityLevel"})]}),id:"networkqualityscore--networkqualitylevel",depth:2},{value:(0,s.jsx)(s.Fragment,{children:(0,s.jsx)(n.code,{children:"NetworkDiagnosticReport"})}),id:"networkdiagnosticreport",depth:2},{value:(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.code,{children:"BenchmarkResult"})," / ",(0,s.jsx)(n.code,{children:"BenchmarkSuiteResult"})]}),id:"benchmarkresult--benchmarksuiteresult",depth:2},{value:"Gotchas / 常见陷阱",id:"gotchas--常见陷阱",depth:2}]}n.default=(0,r.c)(function(e){let{toc:n=c(e)}=e,d={a:"a",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,t.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(d.h1,{children:"API Reference / 接口参考"}),"\n",(0,s.jsx)(d.p,{children:"A condensed field reference for every public model. For copy-paste examples of\neach method, see the capability pages."}),"\n",(0,s.jsx)(d.p,{children:"这里是每个公开模型的字段速查。每个方法的复制即用示例请见各能力页面。"}),"\n",(0,s.jsx)(d.h2,{id:n[0].id,children:n[0].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,s.jsxs)(d.table,{children:[(0,s.jsx)(d.thead,{children:(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.th,{children:"Member"}),(0,s.jsx)(d.th,{children:"Notes"})]})}),(0,s.jsxs)(d.tbody,{children:[(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:"values"}),(0,s.jsxs)(d.td,{children:[(0,s.jsx)(d.code,{children:"none"}),", ",(0,s.jsx)(d.code,{children:"wifi"}),", ",(0,s.jsx)(d.code,{children:"mobile"}),", ",(0,s.jsx)(d.code,{children:"ethernet"}),", ",(0,s.jsx)(d.code,{children:"vpn"}),", ",(0,s.jsx)(d.code,{children:"bluetooth"}),", ",(0,s.jsx)(d.code,{children:"other"})]})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"label"})}),(0,s.jsxs)(d.td,{children:["Human readable: ",(0,s.jsx)(d.code,{children:"'Wi-Fi'"}),", ",(0,s.jsx)(d.code,{children:"'Mobile'"}),", …"]})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"id"})}),(0,s.jsxs)(d.td,{children:["Stable English identifier (",(0,s.jsx)(d.code,{children:"name"}),"), safe to persist"]})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"isConnected"})}),(0,s.jsxs)(d.td,{children:[(0,s.jsx)(d.code,{children:"true"})," unless ",(0,s.jsx)(d.code,{children:"none"})]})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"NetworkType.fromRaw(Object?)"})}),(0,s.jsx)(d.td,{children:"Parses a raw platform string"})]})]})]}),"\n",(0,s.jsx)(d.h2,{id:n[1].id,children:n[1].value}),"\n",(0,s.jsxs)(d.p,{children:[(0,s.jsx)(d.code,{children:"isConnected"}),", ",(0,s.jsx)(d.code,{children:"type"}),", ",(0,s.jsx)(d.code,{children:"ssid"}),", ",(0,s.jsx)(d.code,{children:"signalStrength"})," (dBm), ",(0,s.jsx)(d.code,{children:"ipAddress"}),",\n",(0,s.jsx)(d.code,{children:"ipv6Address"}),", ",(0,s.jsx)(d.code,{children:"gateway"}),", ",(0,s.jsx)(d.code,{children:"macAddress"}),", ",(0,s.jsx)(d.code,{children:"isVpn"}),", ",(0,s.jsx)(d.code,{children:"isReachable"}),", ",(0,s.jsx)(d.code,{children:"timestamp"}),",\nplus ",(0,s.jsx)(d.code,{children:"copyWith({bool? isReachable})"}),"."]}),"\n",(0,s.jsx)(d.h2,{id:n[2].id,children:n[2].value}),"\n",(0,s.jsxs)(d.p,{children:["Fields ",(0,s.jsx)(d.code,{children:"host"}),", ",(0,s.jsx)(d.code,{children:"port"}),", ",(0,s.jsx)(d.code,{children:"mode"}),", ",(0,s.jsx)(d.code,{children:"sent"}),", ",(0,s.jsx)(d.code,{children:"received"}),", ",(0,s.jsx)(d.code,{children:"times"}),", ",(0,s.jsx)(d.code,{children:"timestamp"}),";\nderived getters ",(0,s.jsx)(d.code,{children:"lost"}),", ",(0,s.jsx)(d.code,{children:"packetLoss"})," (%), ",(0,s.jsx)(d.code,{children:"minTime"}),", ",(0,s.jsx)(d.code,{children:"maxTime"}),", ",(0,s.jsx)(d.code,{children:"averageTime"}),",\n",(0,s.jsx)(d.code,{children:"jitter"}),", ",(0,s.jsx)(d.code,{children:"isSuccess"}),"."]}),"\n",(0,s.jsx)(d.h2,{id:n[3].id,children:n[3].value}),"\n",(0,s.jsxs)(d.p,{children:["Fields ",(0,s.jsx)(d.code,{children:"server"}),", ",(0,s.jsx)(d.code,{children:"domain"}),", ",(0,s.jsx)(d.code,{children:"isSuccess"}),", ",(0,s.jsx)(d.code,{children:"responseTime"}),", ",(0,s.jsx)(d.code,{children:"resolvedIps"}),",\n",(0,s.jsx)(d.code,{children:"errorMessage"}),", ",(0,s.jsx)(d.code,{children:"timestamp"}),"; derived ",(0,s.jsx)(d.code,{children:"responseTimeMs"}),", ",(0,s.jsx)(d.code,{children:"primaryAddress"}),"."]}),"\n",(0,s.jsx)(d.h2,{id:n[4].id,children:n[4].value}),"\n",(0,s.jsxs)(d.p,{children:["Fields ",(0,s.jsx)(d.code,{children:"host"}),", ",(0,s.jsx)(d.code,{children:"port"}),", ",(0,s.jsx)(d.code,{children:"isOpen"}),", ",(0,s.jsx)(d.code,{children:"responseTime"}),", ",(0,s.jsx)(d.code,{children:"errorMessage"}),", ",(0,s.jsx)(d.code,{children:"timestamp"}),";\nderived ",(0,s.jsx)(d.code,{children:"responseTimeMs"}),"."]}),"\n",(0,s.jsx)(d.h2,{id:n[5].id,children:n[5].value}),"\n",(0,s.jsxs)(d.p,{children:["Fields ",(0,s.jsx)(d.code,{children:"downloadSpeed"}),", ",(0,s.jsx)(d.code,{children:"uploadSpeed"})," (Mbps), ",(0,s.jsx)(d.code,{children:"ping"})," (ms), ",(0,s.jsx)(d.code,{children:"jitter"})," (ms),\n",(0,s.jsx)(d.code,{children:"packetLoss"})," (%), ",(0,s.jsx)(d.code,{children:"downloadedBytes"}),", ",(0,s.jsx)(d.code,{children:"uploadedBytes"}),", ",(0,s.jsx)(d.code,{children:"downloadDuration"}),",\n",(0,s.jsx)(d.code,{children:"uploadDuration"}),", ",(0,s.jsx)(d.code,{children:"server"}),", ",(0,s.jsx)(d.code,{children:"timestamp"}),"; derived ",(0,s.jsx)(d.code,{children:"duration"}),"; static helper\n",(0,s.jsx)(d.code,{children:"SpeedTestResult.mbpsFromBytes(bytes, elapsed)"}),"."]}),"\n",(0,s.jsx)(d.h2,{id:n[6].id,children:n[6].value}),"\n",(0,s.jsxs)(d.p,{children:[(0,s.jsx)(d.code,{children:"phase"})," (",(0,s.jsx)(d.code,{children:"download"}),", ",(0,s.jsx)(d.code,{children:"upload"}),", ",(0,s.jsx)(d.code,{children:"completed"}),"), ",(0,s.jsx)(d.code,{children:"bytes"}),", ",(0,s.jsx)(d.code,{children:"elapsed"}),", ",(0,s.jsx)(d.code,{children:"speedMbps"}),"."]}),"\n",(0,s.jsx)(d.h2,{id:n[7].id,children:n[7].value}),"\n",(0,s.jsxs)(d.p,{children:[(0,s.jsx)(d.code,{children:"score"})," (0–100), ",(0,s.jsx)(d.code,{children:"level"}),", ",(0,s.jsx)(d.code,{children:"metrics"})," (",(0,s.jsx)(d.code,{children:"Map"}),"), ",(0,s.jsx)(d.code,{children:"suggestions"}),",\n",(0,s.jsx)(d.code,{children:"timestamp"}),"; ",(0,s.jsx)(d.code,{children:"NetworkQualityLevel.fromScore(double)"}),", ",(0,s.jsx)(d.code,{children:"level.label"}),"."]}),"\n",(0,s.jsx)(d.h2,{id:n[8].id,children:n[8].value}),"\n",(0,s.jsxs)(d.p,{children:[(0,s.jsx)(d.code,{children:"connection"}),", ",(0,s.jsx)(d.code,{children:"ping"}),", ",(0,s.jsx)(d.code,{children:"dnsResults"}),", ",(0,s.jsx)(d.code,{children:"portResults"}),", ",(0,s.jsx)(d.code,{children:"speedTest"}),", ",(0,s.jsx)(d.code,{children:"quality"}),",\n",(0,s.jsx)(d.code,{children:"timestamp"}),"."]}),"\n",(0,s.jsx)(d.h2,{id:n[9].id,children:n[9].value}),"\n",(0,s.jsxs)(d.p,{children:[(0,s.jsx)(d.code,{children:"BenchmarkResult"}),": ",(0,s.jsx)(d.code,{children:"testName"}),", ",(0,s.jsx)(d.code,{children:"iterations"}),", ",(0,s.jsx)(d.code,{children:"totalDuration"}),",\n",(0,s.jsx)(d.code,{children:"averageDuration"}),", ",(0,s.jsx)(d.code,{children:"minDuration"}),", ",(0,s.jsx)(d.code,{children:"maxDuration"}),", ",(0,s.jsx)(d.code,{children:"standardDeviation"}),",\n",(0,s.jsx)(d.code,{children:"operationsPerSecond"}),", ",(0,s.jsx)(d.code,{children:"failures"}),", ",(0,s.jsx)(d.code,{children:"timestamp"}),".\n",(0,s.jsx)(d.code,{children:"BenchmarkSuiteResult"}),": ",(0,s.jsx)(d.code,{children:"suiteName"}),", ",(0,s.jsx)(d.code,{children:"results"}),", ",(0,s.jsx)(d.code,{children:"totalDuration"}),", ",(0,s.jsx)(d.code,{children:"timestamp"}),",\nand ",(0,s.jsx)(d.code,{children:"suite['name']"}),"."]}),"\n",(0,s.jsx)(d.h2,{id:n[10].id,children:n[10].value}),"\n",(0,s.jsxs)(d.ol,{children:["\n",(0,s.jsxs)(d.li,{children:[(0,s.jsxs)(d.strong,{children:[(0,s.jsx)(d.code,{children:"type.label"}),", not ",(0,s.jsx)(d.code,{children:"displayName"}),"."]})," ",(0,s.jsx)(d.code,{children:"NetworkType"})," exposes ",(0,s.jsx)(d.code,{children:"label"})," / ",(0,s.jsx)(d.code,{children:"id"}),"."]}),"\n",(0,s.jsxs)(d.li,{children:[(0,s.jsxs)(d.strong,{children:[(0,s.jsx)(d.code,{children:"checkPort()"})," returns ",(0,s.jsx)(d.code,{children:"PortCheckResult"}),"."]})," Use ",(0,s.jsx)(d.code,{children:"isPortOpen()"})," for a plain\nboolean, or ",(0,s.jsx)(d.code,{children:"scanPorts(..., ports: [p]).first"})," for RTT / error message."]}),"\n",(0,s.jsxs)(d.li,{children:[(0,s.jsxs)(d.strong,{children:[(0,s.jsx)(d.code,{children:"includeSystemResolver"})," defaults to ",(0,s.jsx)(d.code,{children:"false"}),"."]})," Pass ",(0,s.jsx)(d.code,{children:"true"})," to add the\n",(0,s.jsx)(d.code,{children:"system"})," DNS row."]}),"\n",(0,s.jsxs)(d.li,{children:[(0,s.jsx)(d.strong,{children:"A TCP ping needs a listening port."})," Probing ",(0,s.jsx)(d.code,{children:"host"})," with ",(0,s.jsx)(d.code,{children:"port: 443"})," fails\nif that host does not accept TCP/443 — that is “filtered”, not “offline”. Use\n",(0,s.jsx)(d.code,{children:"mode: PingMode.icmp"})," on desktop to get closer to real ICMP."]}),"\n",(0,s.jsxs)(d.li,{children:[(0,s.jsxs)(d.strong,{children:[(0,s.jsx)(d.code,{children:"PingMode.icmp"})," is desktop-only"]})," and silently degrades when the ",(0,s.jsx)(d.code,{children:"ping"}),"\nbinary is unavailable."]}),"\n",(0,s.jsxs)(d.li,{children:[(0,s.jsx)(d.strong,{children:"The speed test moves real traffic"})," (≈25 MB download by default). Ask for\nconsent before running it on a metered connection."]}),"\n",(0,s.jsxs)(d.li,{children:[(0,s.jsx)(d.strong,{children:"Missing permissions degrade, they never throw."})," A missing location\npermission yields ",(0,s.jsx)(d.code,{children:"ssid == null"}),"; the rest of the snapshot still arrives."]}),"\n",(0,s.jsxs)(d.li,{children:[(0,s.jsxs)(d.strong,{children:[(0,s.jsx)(d.code,{children:"includePorts"})," is ",(0,s.jsx)(d.code,{children:"false"})," by default"]})," in ",(0,s.jsx)(d.code,{children:"diagnose()"}),"."]}),"\n",(0,s.jsxs)(d.li,{children:[(0,s.jsxs)(d.strong,{children:[(0,s.jsx)(d.code,{children:"init()"})," is optional, but ",(0,s.jsx)(d.code,{children:"dispose()"})," only closes the client the plugin\nowns"]})," — an ",(0,s.jsx)(d.code,{children:"httpClient"})," you injected stays open, so close it yourself."]}),"\n"]}),"\n",(0,s.jsxs)(d.blockquote,{children:["\n",(0,s.jsxs)(d.p,{children:["Full source-level API docs live in the repo:\n",(0,s.jsx)(d.a,{href:"https://github.com/zero-labsco/zero_network_kit/blob/main/API.md",children:"API.md"}),"\n(English) and\n",(0,s.jsx)(d.a,{href:"https://github.com/zero-labsco/zero_network_kit/blob/main/API_zh.md",children:"API_zh.md"}),"\n(简体中文).\n完整源码级 API 文档见仓库内的\n",(0,s.jsx)(d.a,{href:"https://github.com/zero-labsco/zero_network_kit/blob/main/API.md",children:"API.md"}),"\n与 ",(0,s.jsx)(d.a,{href:"https://github.com/zero-labsco/zero_network_kit/blob/main/API_zh.md",children:"API_zh.md"}),"。"]}),"\n"]})]})},"/API-Reference",{filePath:"pages/API-Reference.md",timestamp:1789334081e3,pageMap:i.v,frontMatter:{},title:"API Reference / 接口参考"},"undefined"==typeof RemoteContent?c:RemoteContent.useTOC)},7080:function(e,n,d){"use strict";d.d(n,{v:function(){return s}});let s=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=9166)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Benchmark-5a9a84620f44f1ef.js b/docs/_next/static/chunks/pages/Benchmark-5a9a84620f44f1ef.js deleted file mode 100644 index 5b1fbc1..0000000 --- a/docs/_next/static/chunks/pages/Benchmark-5a9a84620f44f1ef.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[54],{2445:function(i,s,h){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Benchmark",function(){return h(4976)}])},4976:function(i,s,h){"use strict";h.r(s),h.d(s,{useTOC:function(){return r}});var e=h(5893),n=h(7812),t=h(7080),l=h(8925);function r(i){return[{value:"All at once / 一次性全跑",id:"all-at-once--一次性全跑",depth:2},{value:"Individual suites / 单个基准",id:"individual-suites--单个基准",depth:2},{value:"Result fields / 结果字段",id:"result-fields--结果字段",depth:2}]}s.default=(0,n.c)(function(i){let{toc:s=r(i)}=i,h={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",span:"span",...(0,l.a)(),...i.components};return(0,e.jsxs)(e.Fragment,{children:[(0,e.jsx)(h.h1,{children:"Benchmarks / 微基准测试"}),"\n",(0,e.jsxs)(h.p,{children:[(0,e.jsx)(h.code,{children:"NetworkBenchmark"})," measures how fast the diagnostics API itself runs — useful\r\nwhen deciding whether a diagnostic belongs on your startup path."]}),"\n",(0,e.jsxs)(h.p,{children:[(0,e.jsx)(h.code,{children:"NetworkBenchmark"})," 衡量诊断 API 自身的开销——可用在判断某项诊断能否放在启动路径上。"]}),"\n",(0,e.jsx)(h.h2,{id:s[0].id,children:s[0].value}),"\n",(0,e.jsx)(h.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,e.jsxs)(h.code,{children:[(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" suite "}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkBenchmark"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"runAll"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" iterations"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 20"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" warmupIterations"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 3"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" host"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '1.1.1.1'"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" dnsDomain"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'example.com'"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" port"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 443"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,e.jsx)(h.span,{children:(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,e.jsx)(h.span,{children:" "}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"for"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" result "}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"in"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" suite.results) {"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"result"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"testName"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"padRight"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"12"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'avg "}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${("}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"result"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"averageDuration"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"inMicroseconds"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" / "}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1000"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"2"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms '"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '\xb1 "}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${("}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"result"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"standardDeviation"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"inMicroseconds"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" / "}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1000"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"2"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms '"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"result"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"operationsPerSecond"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ops/s '"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'failures="}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"result"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"failures"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,e.jsx)(h.span,{children:(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})}),"\n",(0,e.jsx)(h.span,{children:" "}),"\n",(0,e.jsx)(h.span,{children:(0,e.jsx)(h.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Look up one benchmark by name / 按名称查单个结果"})}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(suite["}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'ping'"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"]"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"?"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".averageDuration);"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(suite.totalDuration);"})]})]})}),"\n",(0,e.jsx)(h.h2,{id:s[1].id,children:s[1].value}),"\n",(0,e.jsx)(h.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,e.jsxs)(h.code,{children:[(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkBenchmark"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"benchmarkConnection"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(iterations"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 20"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkBenchmark"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"benchmarkPing"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(iterations"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 20"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", host"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '1.1.1.1'"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkBenchmark"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"benchmarkDns"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(iterations"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 20"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", domain"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'example.com'"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkBenchmark"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"benchmarkPortCheck"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(iterations"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 20"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", port"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 443"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkBenchmark"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"benchmarkPlatformChannel"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(iterations"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 20"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})]})}),"\n",(0,e.jsx)(h.h2,{id:s[2].id,children:s[2].value}),"\n",(0,e.jsxs)(h.p,{children:[(0,e.jsx)(h.code,{children:"BenchmarkResult"}),": ",(0,e.jsx)(h.code,{children:"testName"}),", ",(0,e.jsx)(h.code,{children:"iterations"}),", ",(0,e.jsx)(h.code,{children:"totalDuration"}),", ",(0,e.jsx)(h.code,{children:"averageDuration"}),",\r\n",(0,e.jsx)(h.code,{children:"minDuration"}),", ",(0,e.jsx)(h.code,{children:"maxDuration"}),", ",(0,e.jsx)(h.code,{children:"standardDeviation"}),", ",(0,e.jsx)(h.code,{children:"operationsPerSecond"}),",\r\n",(0,e.jsx)(h.code,{children:"failures"}),", ",(0,e.jsx)(h.code,{children:"timestamp"}),"."]}),"\n",(0,e.jsxs)(h.p,{children:[(0,e.jsx)(h.code,{children:"BenchmarkSuiteResult"}),": ",(0,e.jsx)(h.code,{children:"suiteName"}),", ",(0,e.jsx)(h.code,{children:"results"}),", ",(0,e.jsx)(h.code,{children:"totalDuration"}),", ",(0,e.jsx)(h.code,{children:"timestamp"}),", and\r\n",(0,e.jsx)(h.code,{children:"suite['name']"}),"."]})]})},"/Benchmark",{filePath:"pages/Benchmark.md",pageMap:t.v,frontMatter:{},title:"Benchmarks / 微基准测试"},"undefined"==typeof RemoteContent?r:RemoteContent.useTOC)},7080:function(i,s,h){"use strict";h.d(s,{v:function(){return e}});let e=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=2445)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Benchmark-a292e8cb0a504f00.js b/docs/_next/static/chunks/pages/Benchmark-a292e8cb0a504f00.js new file mode 100644 index 0000000..92712e6 --- /dev/null +++ b/docs/_next/static/chunks/pages/Benchmark-a292e8cb0a504f00.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[54],{2445:function(i,s,h){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Benchmark",function(){return h(4976)}])},4976:function(i,s,h){"use strict";h.r(s),h.d(s,{useTOC:function(){return r}});var e=h(5893),n=h(7812),t=h(7080),l=h(8925);function r(i){return[{value:"All at once / 一次性全跑",id:"all-at-once--一次性全跑",depth:2},{value:"Individual suites / 单个基准",id:"individual-suites--单个基准",depth:2},{value:"Result fields / 结果字段",id:"result-fields--结果字段",depth:2}]}s.default=(0,n.c)(function(i){let{toc:s=r(i)}=i,h={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",span:"span",...(0,l.a)(),...i.components};return(0,e.jsxs)(e.Fragment,{children:[(0,e.jsx)(h.h1,{children:"Benchmarks / 微基准测试"}),"\n",(0,e.jsxs)(h.p,{children:[(0,e.jsx)(h.code,{children:"NetworkBenchmark"})," measures how fast the diagnostics API itself runs — useful\nwhen deciding whether a diagnostic belongs on your startup path."]}),"\n",(0,e.jsxs)(h.p,{children:[(0,e.jsx)(h.code,{children:"NetworkBenchmark"})," 衡量诊断 API 自身的开销——可用在判断某项诊断能否放在启动路径上。"]}),"\n",(0,e.jsx)(h.h2,{id:s[0].id,children:s[0].value}),"\n",(0,e.jsx)(h.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,e.jsxs)(h.code,{children:[(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" suite "}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkBenchmark"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"runAll"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" iterations"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 20"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" warmupIterations"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 3"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" host"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '1.1.1.1'"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" dnsDomain"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'example.com'"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" port"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 443"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,e.jsx)(h.span,{children:(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,e.jsx)(h.span,{children:" "}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"for"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" result "}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"in"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" suite.results) {"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"result"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"testName"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"padRight"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"12"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'avg "}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${("}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"result"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"averageDuration"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"inMicroseconds"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" / "}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1000"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"2"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms '"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '\xb1 "}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${("}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"result"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"standardDeviation"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"inMicroseconds"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" / "}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1000"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"2"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms '"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"result"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"operationsPerSecond"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ops/s '"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'failures="}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"result"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"failures"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,e.jsx)(h.span,{children:(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})}),"\n",(0,e.jsx)(h.span,{children:" "}),"\n",(0,e.jsx)(h.span,{children:(0,e.jsx)(h.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Look up one benchmark by name / 按名称查单个结果"})}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(suite["}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'ping'"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"]"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"?"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".averageDuration);"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(suite.totalDuration);"})]})]})}),"\n",(0,e.jsx)(h.h2,{id:s[1].id,children:s[1].value}),"\n",(0,e.jsx)(h.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,e.jsxs)(h.code,{children:[(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkBenchmark"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"benchmarkConnection"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(iterations"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 20"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkBenchmark"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"benchmarkPing"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(iterations"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 20"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", host"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '1.1.1.1'"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkBenchmark"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"benchmarkDns"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(iterations"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 20"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", domain"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'example.com'"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkBenchmark"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"benchmarkPortCheck"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(iterations"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 20"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", port"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 443"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,e.jsxs)(h.span,{children:[(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkBenchmark"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"benchmarkPlatformChannel"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(iterations"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 20"}),(0,e.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})]})}),"\n",(0,e.jsx)(h.h2,{id:s[2].id,children:s[2].value}),"\n",(0,e.jsxs)(h.p,{children:[(0,e.jsx)(h.code,{children:"BenchmarkResult"}),": ",(0,e.jsx)(h.code,{children:"testName"}),", ",(0,e.jsx)(h.code,{children:"iterations"}),", ",(0,e.jsx)(h.code,{children:"totalDuration"}),", ",(0,e.jsx)(h.code,{children:"averageDuration"}),",\n",(0,e.jsx)(h.code,{children:"minDuration"}),", ",(0,e.jsx)(h.code,{children:"maxDuration"}),", ",(0,e.jsx)(h.code,{children:"standardDeviation"}),", ",(0,e.jsx)(h.code,{children:"operationsPerSecond"}),",\n",(0,e.jsx)(h.code,{children:"failures"}),", ",(0,e.jsx)(h.code,{children:"timestamp"}),"."]}),"\n",(0,e.jsxs)(h.p,{children:[(0,e.jsx)(h.code,{children:"BenchmarkSuiteResult"}),": ",(0,e.jsx)(h.code,{children:"suiteName"}),", ",(0,e.jsx)(h.code,{children:"results"}),", ",(0,e.jsx)(h.code,{children:"totalDuration"}),", ",(0,e.jsx)(h.code,{children:"timestamp"}),", and\n",(0,e.jsx)(h.code,{children:"suite['name']"}),"."]})]})},"/Benchmark",{filePath:"pages/Benchmark.md",timestamp:1789334081e3,pageMap:t.v,frontMatter:{},title:"Benchmarks / 微基准测试"},"undefined"==typeof RemoteContent?r:RemoteContent.useTOC)},7080:function(i,s,h){"use strict";h.d(s,{v:function(){return e}});let e=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=2445)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Connectivity-f42171fa3a2a6178.js b/docs/_next/static/chunks/pages/Connectivity-f42171fa3a2a6178.js deleted file mode 100644 index 41cc365..0000000 --- a/docs/_next/static/chunks/pages/Connectivity-f42171fa3a2a6178.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[312],{3091:function(i,s,h){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Connectivity",function(){return h(3020)}])},3020:function(i,s,h){"use strict";h.r(s),h.d(s,{useTOC:function(){return r}});var n=h(5893),e=h(7812),l=h(7080),t=h(8925);function r(i){return[{value:"Snapshot / 快照",id:"snapshot--快照",depth:2},{value:"Parameters / 参数",id:"parameters--参数",depth:3},{value:"Change stream / 变化监听",id:"change-stream--变化监听",depth:2},{value:"Connectivity-only: minimal example / 仅连通性:最小示例",id:"connectivity-only-minimal-example--仅连通性最小示例",depth:3}]}s.default=(0,e.c)(function(i){let{toc:s=r(i)}=i,h={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,t.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(h.h1,{children:"Connectivity / 连通性"}),"\n",(0,n.jsxs)(h.p,{children:[(0,n.jsx)(h.code,{children:"NetworkDiagnostic.checkConnection()"})," captures a single snapshot of the current\r\nnetwork; ",(0,n.jsx)(h.code,{children:"onConnectivityChanged"})," emits a fresh snapshot on every transport\r\nchange."]}),"\n",(0,n.jsxs)(h.p,{children:[(0,n.jsx)(h.code,{children:"NetworkDiagnostic.checkConnection()"})," 捕获当前网络的一次快照;",(0,n.jsx)(h.code,{children:"onConnectivityChanged"}),"\r\n在每次传输方式变化时推送新快照。"]}),"\n",(0,n.jsx)(h.h2,{id:s[0].id,children:s[0].value}),"\n",(0,n.jsx)(h.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(h.code,{children:[(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" connection "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"checkConnection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsx)(h.span,{children:" "}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'type : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"type"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"label"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"); "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Wi-Fi / Mobile / Ethernet …"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'connected : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"isConnected"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'ipv4 : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ipAddress"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'ipv6 : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ipv6Address"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'gateway : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"gateway"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'ssid : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ssid"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'rssi : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"signalStrength"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" dBm'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'mac : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"macAddress"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'vpn : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"isVpn"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'timestamp : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"timestamp"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(h.table,{children:[(0,n.jsx)(h.thead,{children:(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.th,{children:"Field"}),(0,n.jsx)(h.th,{children:"Notes"})]})}),(0,n.jsxs)(h.tbody,{children:[(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"type"})}),(0,n.jsxs)(h.td,{children:[(0,n.jsx)(h.code,{children:"NetworkType"})," (",(0,n.jsx)(h.code,{children:"none"}),", ",(0,n.jsx)(h.code,{children:"wifi"}),", ",(0,n.jsx)(h.code,{children:"mobile"}),", ",(0,n.jsx)(h.code,{children:"ethernet"}),", ",(0,n.jsx)(h.code,{children:"vpn"}),", ",(0,n.jsx)(h.code,{children:"bluetooth"}),", ",(0,n.jsx)(h.code,{children:"other"}),")"]})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"isConnected"})}),(0,n.jsxs)(h.td,{children:[(0,n.jsx)(h.code,{children:"true"})," unless ",(0,n.jsx)(h.code,{children:"type"})," is ",(0,n.jsx)(h.code,{children:"none"})]})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsxs)(h.td,{children:[(0,n.jsx)(h.code,{children:"ipAddress"})," / ",(0,n.jsx)(h.code,{children:"ipv6Address"})]}),(0,n.jsxs)(h.td,{children:["Local IPv4 / IPv6 (Dart ",(0,n.jsx)(h.code,{children:"NetworkInterface"}),")"]})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsxs)(h.td,{children:[(0,n.jsx)(h.code,{children:"gateway"})," / ",(0,n.jsx)(h.code,{children:"macAddress"})]}),(0,n.jsxs)(h.td,{children:["Native; ",(0,n.jsx)(h.code,{children:"null"})," on desktop except Windows"]})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsxs)(h.td,{children:[(0,n.jsx)(h.code,{children:"ssid"})," / ",(0,n.jsx)(h.code,{children:"signalStrength"})]}),(0,n.jsxs)(h.td,{children:["Native; ",(0,n.jsxs)(h.strong,{children:["always ",(0,n.jsx)(h.code,{children:"null"})," on desktop"]})]})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"isVpn"})}),(0,n.jsx)(h.td,{children:"Native VPN detection"})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"isReachable"})}),(0,n.jsxs)(h.td,{children:["Only filled when ",(0,n.jsx)(h.code,{children:"probeReachability: true"})]})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"timestamp"})}),(0,n.jsx)(h.td,{children:"When the snapshot was taken"})]})]})]}),"\n",(0,n.jsxs)(h.blockquote,{children:["\n",(0,n.jsxs)(h.p,{children:["Use ",(0,n.jsx)(h.code,{children:"connection.type.label"})," / ",(0,n.jsx)(h.code,{children:"connection.type.id"}),". There is ",(0,n.jsx)(h.strong,{children:"no"}),"\r\n",(0,n.jsx)(h.code,{children:"displayName"}),".\r\n请使用 ",(0,n.jsx)(h.code,{children:"connection.type.label"})," / ",(0,n.jsx)(h.code,{children:"connection.type.id"}),",",(0,n.jsx)(h.strong,{children:"没有"})," ",(0,n.jsx)(h.code,{children:"displayName"}),"。"]}),"\n"]}),"\n",(0,n.jsx)(h.h3,{id:s[1].id,children:s[1].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(h.table,{children:[(0,n.jsx)(h.thead,{children:(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.th,{children:"Parameter"}),(0,n.jsx)(h.th,{children:"Default"}),(0,n.jsx)(h.th,{children:"Meaning"})]})}),(0,n.jsxs)(h.tbody,{children:[(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"includeNativeDetails"})}),(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"true"})}),(0,n.jsx)(h.td,{children:"Also read SSID / gateway / MAC / VPN from the native side"})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"probeReachability"})}),(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"false"})}),(0,n.jsxs)(h.td,{children:["Make a real request and fill ",(0,n.jsx)(h.code,{children:"isReachable"})]})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"probeTimeout"})}),(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"3s"})}),(0,n.jsx)(h.td,{children:"Timeout of that reachability probe"})]})]})]}),"\n",(0,n.jsx)(h.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(h.code,{children:[(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Skip the native channel (cheapest call — good on hot paths)."})}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" quick "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"checkConnection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(includeNativeDetails"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" false"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsx)(h.span,{children:" "}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Prove the internet is actually reachable, not just that a NIC is up."})}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" verified "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"checkConnection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" probeReachability"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" probeTimeout"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Duration"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(seconds"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"if"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (verified.isReachable "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" false"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:") {"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'Interface is up but the internet is unreachable.'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsx)(h.h2,{id:s[2].id,children:s[2].value}),"\n",(0,n.jsx)(h.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(h.code,{children:[(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" subscription "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".onConnectivityChanged."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"listen"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (info) "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'now on "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"info"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"type"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"id"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" \xb7 "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"info"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ipAddress"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Later:"})}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" subscription."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"cancel"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]})]})}),"\n",(0,n.jsx)(h.p,{children:"In a widget:"}),"\n",(0,n.jsx)(h.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(h.code,{children:[(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"StreamBuilder"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkConnectionInfo"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:">("})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" stream"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".onConnectivityChanged,"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" builder"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (context, snapshot) {"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" info "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" snapshot.data;"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" if"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (info "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" null"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:") "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"return"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'Checking…'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" return"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"info"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"type"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"label"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" \xb7 "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"info"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"isConnected"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" },"})}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:")"})})]})}),"\n",(0,n.jsx)(h.h3,{id:s[3].id,children:s[3].value}),"\n",(0,n.jsxs)(h.p,{children:["If all you need is “am I online, on what transport, what IP, and react to\r\nchanges”, you only need this page — ",(0,n.jsxs)(h.strong,{children:["no ",(0,n.jsx)(h.code,{children:"init()"})," required"]}),"."]}),"\n",(0,n.jsxs)(h.p,{children:["如果只需要「在不在線、走什么網络、IP 是多少、切换时通知」,只看本页即可——\r\n",(0,n.jsxs)(h.strong,{children:["无需 ",(0,n.jsx)(h.code,{children:"init()"})]}),"。"]}),"\n",(0,n.jsx)(h.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(h.code,{children:[(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"class"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ConnectivityScreen"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" extends"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" StatelessWidget"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ConnectivityScreen"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"({"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"super"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".key});"})]}),"\n",(0,n.jsx)(h.span,{children:" "}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Widget"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" build"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"BuildContext"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" context) {"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" return"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" StreamBuilder"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkConnectionInfo"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:">("})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" stream"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".onConnectivityChanged,"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" builder"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (context, snap) {"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" c "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" snap.data;"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" if"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (c "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" null"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:") {"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" return"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Center"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(child"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" CircularProgressIndicator"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"());"})]}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" return"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ListView"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" children"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ["})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ListTile"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(title"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'Type / 类型'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"), trailing"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(c.type.label)),"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ListTile"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(title"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'Online / 在线'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"), trailing"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"c"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"isConnected"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:")),"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ListTile"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(title"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'IPv4'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"), trailing"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(c.ipAddress "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"??"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '—'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:")),"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ListTile"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(title"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'IPv6'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"), trailing"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(c.ipv6Address "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"??"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '—'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:")),"})]}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ],"})}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" );"})}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" },"})}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" );"})}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})})]})},"/Connectivity",{filePath:"pages/Connectivity.md",pageMap:l.v,frontMatter:{},title:"Connectivity / 连通性"},"undefined"==typeof RemoteContent?r:RemoteContent.useTOC)},7080:function(i,s,h){"use strict";h.d(s,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=3091)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Connectivity-f9b385023ad97f07.js b/docs/_next/static/chunks/pages/Connectivity-f9b385023ad97f07.js new file mode 100644 index 0000000..ab23891 --- /dev/null +++ b/docs/_next/static/chunks/pages/Connectivity-f9b385023ad97f07.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[312],{3091:function(i,s,h){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Connectivity",function(){return h(3020)}])},3020:function(i,s,h){"use strict";h.r(s),h.d(s,{useTOC:function(){return r}});var n=h(5893),e=h(7812),l=h(7080),t=h(8925);function r(i){return[{value:"Snapshot / 快照",id:"snapshot--快照",depth:2},{value:"Parameters / 参数",id:"parameters--参数",depth:3},{value:"Change stream / 变化监听",id:"change-stream--变化监听",depth:2},{value:"Connectivity-only: minimal example / 仅连通性:最小示例",id:"connectivity-only-minimal-example--仅连通性最小示例",depth:3}]}s.default=(0,e.c)(function(i){let{toc:s=r(i)}=i,h={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,t.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(h.h1,{children:"Connectivity / 连通性"}),"\n",(0,n.jsxs)(h.p,{children:[(0,n.jsx)(h.code,{children:"NetworkDiagnostic.checkConnection()"})," captures a single snapshot of the current\nnetwork; ",(0,n.jsx)(h.code,{children:"onConnectivityChanged"})," emits a fresh snapshot on every transport\nchange."]}),"\n",(0,n.jsxs)(h.p,{children:[(0,n.jsx)(h.code,{children:"NetworkDiagnostic.checkConnection()"})," 捕获当前网络的一次快照;",(0,n.jsx)(h.code,{children:"onConnectivityChanged"}),"\n在每次传输方式变化时推送新快照。"]}),"\n",(0,n.jsx)(h.h2,{id:s[0].id,children:s[0].value}),"\n",(0,n.jsx)(h.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(h.code,{children:[(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" connection "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"checkConnection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsx)(h.span,{children:" "}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'type : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"type"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"label"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"); "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Wi-Fi / Mobile / Ethernet …"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'connected : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"isConnected"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'ipv4 : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ipAddress"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'ipv6 : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ipv6Address"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'gateway : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"gateway"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'ssid : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ssid"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'rssi : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"signalStrength"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" dBm'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'mac : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"macAddress"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'vpn : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"isVpn"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'timestamp : "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"timestamp"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(h.table,{children:[(0,n.jsx)(h.thead,{children:(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.th,{children:"Field"}),(0,n.jsx)(h.th,{children:"Notes"})]})}),(0,n.jsxs)(h.tbody,{children:[(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"type"})}),(0,n.jsxs)(h.td,{children:[(0,n.jsx)(h.code,{children:"NetworkType"})," (",(0,n.jsx)(h.code,{children:"none"}),", ",(0,n.jsx)(h.code,{children:"wifi"}),", ",(0,n.jsx)(h.code,{children:"mobile"}),", ",(0,n.jsx)(h.code,{children:"ethernet"}),", ",(0,n.jsx)(h.code,{children:"vpn"}),", ",(0,n.jsx)(h.code,{children:"bluetooth"}),", ",(0,n.jsx)(h.code,{children:"other"}),")"]})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"isConnected"})}),(0,n.jsxs)(h.td,{children:[(0,n.jsx)(h.code,{children:"true"})," unless ",(0,n.jsx)(h.code,{children:"type"})," is ",(0,n.jsx)(h.code,{children:"none"})]})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsxs)(h.td,{children:[(0,n.jsx)(h.code,{children:"ipAddress"})," / ",(0,n.jsx)(h.code,{children:"ipv6Address"})]}),(0,n.jsxs)(h.td,{children:["Local IPv4 / IPv6 (Dart ",(0,n.jsx)(h.code,{children:"NetworkInterface"}),")"]})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsxs)(h.td,{children:[(0,n.jsx)(h.code,{children:"gateway"})," / ",(0,n.jsx)(h.code,{children:"macAddress"})]}),(0,n.jsxs)(h.td,{children:["Native; ",(0,n.jsx)(h.code,{children:"null"})," on desktop except Windows"]})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsxs)(h.td,{children:[(0,n.jsx)(h.code,{children:"ssid"})," / ",(0,n.jsx)(h.code,{children:"signalStrength"})]}),(0,n.jsxs)(h.td,{children:["Native; ",(0,n.jsxs)(h.strong,{children:["always ",(0,n.jsx)(h.code,{children:"null"})," on desktop"]})]})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"isVpn"})}),(0,n.jsx)(h.td,{children:"Native VPN detection"})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"isReachable"})}),(0,n.jsxs)(h.td,{children:["Only filled when ",(0,n.jsx)(h.code,{children:"probeReachability: true"})]})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"timestamp"})}),(0,n.jsx)(h.td,{children:"When the snapshot was taken"})]})]})]}),"\n",(0,n.jsxs)(h.blockquote,{children:["\n",(0,n.jsxs)(h.p,{children:["Use ",(0,n.jsx)(h.code,{children:"connection.type.label"})," / ",(0,n.jsx)(h.code,{children:"connection.type.id"}),". There is ",(0,n.jsx)(h.strong,{children:"no"}),"\n",(0,n.jsx)(h.code,{children:"displayName"}),".\n请使用 ",(0,n.jsx)(h.code,{children:"connection.type.label"})," / ",(0,n.jsx)(h.code,{children:"connection.type.id"}),",",(0,n.jsx)(h.strong,{children:"没有"})," ",(0,n.jsx)(h.code,{children:"displayName"}),"。"]}),"\n"]}),"\n",(0,n.jsx)(h.h3,{id:s[1].id,children:s[1].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(h.table,{children:[(0,n.jsx)(h.thead,{children:(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.th,{children:"Parameter"}),(0,n.jsx)(h.th,{children:"Default"}),(0,n.jsx)(h.th,{children:"Meaning"})]})}),(0,n.jsxs)(h.tbody,{children:[(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"includeNativeDetails"})}),(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"true"})}),(0,n.jsx)(h.td,{children:"Also read SSID / gateway / MAC / VPN from the native side"})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"probeReachability"})}),(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"false"})}),(0,n.jsxs)(h.td,{children:["Make a real request and fill ",(0,n.jsx)(h.code,{children:"isReachable"})]})]}),(0,n.jsxs)(h.tr,{children:[(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"probeTimeout"})}),(0,n.jsx)(h.td,{children:(0,n.jsx)(h.code,{children:"3s"})}),(0,n.jsx)(h.td,{children:"Timeout of that reachability probe"})]})]})]}),"\n",(0,n.jsx)(h.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(h.code,{children:[(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Skip the native channel (cheapest call — good on hot paths)."})}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" quick "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"checkConnection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(includeNativeDetails"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" false"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsx)(h.span,{children:" "}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Prove the internet is actually reachable, not just that a NIC is up."})}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" verified "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"checkConnection"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" probeReachability"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" probeTimeout"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Duration"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(seconds"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"if"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (verified.isReachable "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" false"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:") {"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'Interface is up but the internet is unreachable.'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsx)(h.h2,{id:s[2].id,children:s[2].value}),"\n",(0,n.jsx)(h.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(h.code,{children:[(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" subscription "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".onConnectivityChanged."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"listen"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (info) "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'now on "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"info"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"type"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"id"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" \xb7 "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"info"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ipAddress"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Later:"})}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" subscription."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"cancel"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]})]})}),"\n",(0,n.jsx)(h.p,{children:"In a widget:"}),"\n",(0,n.jsx)(h.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(h.code,{children:[(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"StreamBuilder"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkConnectionInfo"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:">("})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" stream"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".onConnectivityChanged,"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" builder"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (context, snapshot) {"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" info "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" snapshot.data;"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" if"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (info "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" null"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:") "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"return"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'Checking…'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" return"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"info"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"type"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"label"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" \xb7 "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"info"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"isConnected"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" },"})}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:")"})})]})}),"\n",(0,n.jsx)(h.h3,{id:s[3].id,children:s[3].value}),"\n",(0,n.jsxs)(h.p,{children:["If all you need is “am I online, on what transport, what IP, and react to\nchanges”, you only need this page — ",(0,n.jsxs)(h.strong,{children:["no ",(0,n.jsx)(h.code,{children:"init()"})," required"]}),"."]}),"\n",(0,n.jsxs)(h.p,{children:["如果只需要「在不在線、走什么網络、IP 是多少、切换时通知」,只看本页即可——\n",(0,n.jsxs)(h.strong,{children:["无需 ",(0,n.jsx)(h.code,{children:"init()"})]}),"。"]}),"\n",(0,n.jsx)(h.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(h.code,{children:[(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"class"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ConnectivityScreen"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" extends"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" StatelessWidget"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ConnectivityScreen"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"({"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"super"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".key});"})]}),"\n",(0,n.jsx)(h.span,{children:" "}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Widget"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" build"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"BuildContext"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" context) {"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" return"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" StreamBuilder"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkConnectionInfo"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:">("})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" stream"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".onConnectivityChanged,"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" builder"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (context, snap) {"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" final"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" c "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" snap.data;"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" if"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (c "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=="}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" null"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:") {"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" return"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Center"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(child"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" CircularProgressIndicator"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"());"})]}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" return"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ListView"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" children"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ["})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ListTile"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(title"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'Type / 类型'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"), trailing"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(c.type.label)),"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ListTile"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(title"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'Online / 在线'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"), trailing"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"c"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"isConnected"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:")),"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ListTile"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(title"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'IPv4'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"), trailing"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(c.ipAddress "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"??"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '—'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:")),"})]}),"\n",(0,n.jsxs)(h.span,{children:[(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ListTile"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(title"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'IPv6'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"), trailing"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Text"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(c.ipv6Address "}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"??"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '—'"}),(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:")),"})]}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ],"})}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" );"})}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" },"})}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" );"})}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,n.jsx)(h.span,{children:(0,n.jsx)(h.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})})]})},"/Connectivity",{filePath:"pages/Connectivity.md",timestamp:1789334081e3,pageMap:l.v,frontMatter:{},title:"Connectivity / 连通性"},"undefined"==typeof RemoteContent?r:RemoteContent.useTOC)},7080:function(i,s,h){"use strict";h.d(s,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=3091)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/DNS-93340032eaa9ffdd.js b/docs/_next/static/chunks/pages/DNS-93340032eaa9ffdd.js new file mode 100644 index 0000000..09783ec --- /dev/null +++ b/docs/_next/static/chunks/pages/DNS-93340032eaa9ffdd.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[98],{5653:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/DNS",function(){return e(1746)}])},1746:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return r}});var h=e(5893),n=e(7812),t=e(7080),l=e(8925);function r(i){return[{value:"Basic / 基础",id:"basic--基础",depth:2},{value:"Pick the fastest / 挑出最快的",id:"pick-the-fastest--挑出最快的",depth:3}]}s.default=(0,n.c)(function(i){let{toc:s=r(i)}=i,e={code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,l.a)(),...i.components};return(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(e.h1,{children:"DNS / DNS 解析"}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"NetworkDiagnostic.resolve()"})," tests DNS resolution across multiple servers in\nparallel, so you can spot the fastest one. Each result is either the system\nresolver or a raw UDP query against an explicit server."]}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"NetworkDiagnostic.resolve()"})," 并行测试多台 DNS 服务器的解析表现,从而挑出最快的一台。\n每条结果要么来自系统解析器,要么是对指定服务器的原始 UDP 查询。"]}),"\n",(0,h.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" results "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"resolve"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" domain"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'example.com'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" dnsServers"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" <"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:">"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"["}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'1.1.1.1'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'8.8.8.8'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'114.114.114.114'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" timeout"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Duration"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(seconds"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" concurrent"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeSystemResolver"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,h.jsx)(e.span,{children:" "}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"for"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" r "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"in"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" results) {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" if"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (r.isSuccess) {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"server"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"padRight"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"16"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" → "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"resolvedIps"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"join"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:'", "'}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"responseTimeMs"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms)'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" } "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"else"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"server"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"padRight"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"16"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ✗ "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"errorMessage"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,h.jsxs)(e.table,{children:[(0,h.jsx)(e.thead,{children:(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.th,{children:"Parameter"}),(0,h.jsx)(e.th,{children:"Default"}),(0,h.jsx)(e.th,{children:"Meaning"})]})}),(0,h.jsxs)(e.tbody,{children:[(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"domain"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.dnsDomain"})}),(0,h.jsx)(e.td,{children:"Domain to resolve"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"dnsServers"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.dnsServers"})}),(0,h.jsx)(e.td,{children:"Servers queried in parallel (or in series)"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"timeout"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.dnsTimeout"})}),(0,h.jsx)(e.td,{children:"Timeout of one query"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"concurrent"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"true"})}),(0,h.jsx)(e.td,{children:"Query all servers at once"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"includeSystemResolver"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"false"})}),(0,h.jsxs)(e.td,{children:["Also add a ",(0,h.jsx)(e.code,{children:"system"})," row"]})]})]})]}),"\n",(0,h.jsx)(e.p,{children:"Notes / 说明:"}),"\n",(0,h.jsxs)(e.ul,{children:["\n",(0,h.jsxs)(e.li,{children:["A row with ",(0,h.jsx)(e.code,{children:"server == 'system'"})," comes from the OS resolver; the others are raw\nUDP queries against the listed IPs, encoded by the built-in ",(0,h.jsx)(e.code,{children:"DnsPacket"})," wire\ncodec.\n",(0,h.jsx)(e.code,{children:"server == 'system'"})," 的行来自系统解析器,其余是对指定 IP 的原始 UDP 查询,由内置\n",(0,h.jsx)(e.code,{children:"DnsPacket"})," 编解码。"]}),"\n",(0,h.jsxs)(e.li,{children:[(0,h.jsx)(e.code,{children:"includeSystemResolver"})," defaults to ",(0,h.jsx)(e.strong,{children:(0,h.jsx)(e.code,{children:"false"})})," at the facade level — pass\n",(0,h.jsx)(e.code,{children:"true"})," to include it.\n门面层默认",(0,h.jsx)(e.strong,{children:"不"}),"包含系统解析器,需显式传 ",(0,h.jsx)(e.code,{children:"true"}),"。"]}),"\n"]}),"\n",(0,h.jsx)(e.h3,{id:s[1].id,children:s[1].value}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" fastest "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" results"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"where"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"((r) "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" r.isSuccess)"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"reduce"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"((a, b) "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" a.responseTimeMs "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"<="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" b.responseTimeMs "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"?"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" a "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" b);"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'fastest resolver: "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"fastest"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"server"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})]})})]})},"/DNS",{filePath:"pages/DNS.md",timestamp:1789334081e3,pageMap:t.v,frontMatter:{},title:"DNS / DNS 解析"},"undefined"==typeof RemoteContent?r:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return h}});let h=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=5653)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/DNS-9c89ec32dcd86fa0.js b/docs/_next/static/chunks/pages/DNS-9c89ec32dcd86fa0.js deleted file mode 100644 index 7340a8f..0000000 --- a/docs/_next/static/chunks/pages/DNS-9c89ec32dcd86fa0.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[98],{5653:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/DNS",function(){return e(1746)}])},1746:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return r}});var h=e(5893),n=e(7812),l=e(7080),t=e(8925);function r(i){return[{value:"Basic / 基础",id:"basic--基础",depth:2},{value:"Pick the fastest / 挑出最快的",id:"pick-the-fastest--挑出最快的",depth:3}]}s.default=(0,n.c)(function(i){let{toc:s=r(i)}=i,e={code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,t.a)(),...i.components};return(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(e.h1,{children:"DNS / DNS 解析"}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"NetworkDiagnostic.resolve()"})," tests DNS resolution across multiple servers in\r\nparallel, so you can spot the fastest one. Each result is either the system\r\nresolver or a raw UDP query against an explicit server."]}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"NetworkDiagnostic.resolve()"})," 并行测试多台 DNS 服务器的解析表现,从而挑出最快的一台。\r\n每条结果要么来自系统解析器,要么是对指定服务器的原始 UDP 查询。"]}),"\n",(0,h.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" results "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"resolve"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" domain"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'example.com'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" dnsServers"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" <"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:">"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"["}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'1.1.1.1'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'8.8.8.8'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'114.114.114.114'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" timeout"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Duration"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(seconds"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" concurrent"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeSystemResolver"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,h.jsx)(e.span,{children:" "}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"for"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" r "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"in"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" results) {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" if"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (r.isSuccess) {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"server"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"padRight"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"16"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" → "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"resolvedIps"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"join"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:'", "'}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"responseTimeMs"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms)'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" } "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"else"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"server"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"padRight"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"16"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ✗ "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"errorMessage"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,h.jsxs)(e.table,{children:[(0,h.jsx)(e.thead,{children:(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.th,{children:"Parameter"}),(0,h.jsx)(e.th,{children:"Default"}),(0,h.jsx)(e.th,{children:"Meaning"})]})}),(0,h.jsxs)(e.tbody,{children:[(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"domain"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.dnsDomain"})}),(0,h.jsx)(e.td,{children:"Domain to resolve"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"dnsServers"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.dnsServers"})}),(0,h.jsx)(e.td,{children:"Servers queried in parallel (or in series)"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"timeout"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.dnsTimeout"})}),(0,h.jsx)(e.td,{children:"Timeout of one query"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"concurrent"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"true"})}),(0,h.jsx)(e.td,{children:"Query all servers at once"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"includeSystemResolver"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"false"})}),(0,h.jsxs)(e.td,{children:["Also add a ",(0,h.jsx)(e.code,{children:"system"})," row"]})]})]})]}),"\n",(0,h.jsx)(e.p,{children:"Notes / 说明:"}),"\n",(0,h.jsxs)(e.ul,{children:["\n",(0,h.jsxs)(e.li,{children:["A row with ",(0,h.jsx)(e.code,{children:"server == 'system'"})," comes from the OS resolver; the others are raw\r\nUDP queries against the listed IPs, encoded by the built-in ",(0,h.jsx)(e.code,{children:"DnsPacket"})," wire\r\ncodec.\r\n",(0,h.jsx)(e.code,{children:"server == 'system'"})," 的行来自系统解析器,其余是对指定 IP 的原始 UDP 查询,由内置\r\n",(0,h.jsx)(e.code,{children:"DnsPacket"})," 编解码。"]}),"\n",(0,h.jsxs)(e.li,{children:[(0,h.jsx)(e.code,{children:"includeSystemResolver"})," defaults to ",(0,h.jsx)(e.strong,{children:(0,h.jsx)(e.code,{children:"false"})})," at the facade level — pass\r\n",(0,h.jsx)(e.code,{children:"true"})," to include it.\r\n门面层默认",(0,h.jsx)(e.strong,{children:"不"}),"包含系统解析器,需显式传 ",(0,h.jsx)(e.code,{children:"true"}),"。"]}),"\n"]}),"\n",(0,h.jsx)(e.h3,{id:s[1].id,children:s[1].value}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" fastest "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" results"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"where"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"((r) "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" r.isSuccess)"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"reduce"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"((a, b) "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" a.responseTimeMs "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"<="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" b.responseTimeMs "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"?"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" a "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" b);"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'fastest resolver: "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"fastest"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"server"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})]})})]})},"/DNS",{filePath:"pages/DNS.md",pageMap:l.v,frontMatter:{},title:"DNS / DNS 解析"},"undefined"==typeof RemoteContent?r:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return h}});let h=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=5653)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/FAQ-c14e0ebd2147b3f8.js b/docs/_next/static/chunks/pages/FAQ-c14e0ebd2147b3f8.js new file mode 100644 index 0000000..528a020 --- /dev/null +++ b/docs/_next/static/chunks/pages/FAQ-c14e0ebd2147b3f8.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[210],{9238:function(e,t,n){(window.__NEXT_P=window.__NEXT_P||[]).push(["/FAQ",function(){return n(5797)}])},5797:function(e,t,n){"use strict";n.r(t),n.d(t,{useTOC:function(){return d}});var i=n(5893),r=n(7812),o=n(7080),s=n(8925);function d(e){let t={code:"code",...(0,s.a)()};return[{value:(0,i.jsxs)(i.Fragment,{children:["Do I need to call ",(0,i.jsx)(t.code,{children:"init()"}),"? / 需要调用 ",(0,i.jsx)(t.code,{children:"init()"})," 吗?"]}),id:"do-i-need-to-call-init--需要调用-init-吗",depth:3},{value:"Which platforms are supported? / 支持哪些平台?",id:"which-platforms-are-supported--支持哪些平台",depth:3},{value:(0,i.jsxs)(i.Fragment,{children:["Why is ",(0,i.jsx)(t.code,{children:"ssid"})," / ",(0,i.jsx)(t.code,{children:"signalStrength"})," ",(0,i.jsx)(t.code,{children:"null"})," on desktop? / 为什么桌面上的 ssid/信号强度是 null?"]}),id:"why-is-ssid--signalstrength-null-on-desktop--为什么桌面上的-ssid信号强度是-null",depth:3},{value:(0,i.jsxs)(i.Fragment,{children:["Why does ",(0,i.jsx)(t.code,{children:"getNativeNetworkDetails()"})," return ",(0,i.jsx)(t.code,{children:"null"}),"? / 为什么 getNativeNetworkDetails 返回 null?"]}),id:"why-does-getnativenetworkdetails-return-null--为什么-getnativenetworkdetails-返回-null",depth:3},{value:"Does the speed test use my bandwidth? / 测速会消耗我的流量吗?",id:"does-the-speed-test-use-my-bandwidth--测速会消耗我的流量吗",depth:3},{value:"How do I test my integration without the network? / 如何脱离网络测试我的集成?",id:"how-do-i-test-my-integration-without-the-network--如何脱离网络测试我的集成",depth:3},{value:"How is this licensed? / 采用什么许可证?",id:"how-is-this-licensed--采用什么许可证",depth:3}]}t.default=(0,r.c)(function(e){let{toc:t=d(e)}=e,n={a:"a",code:"code",h1:"h1",h3:"h3",p:"p",strong:"strong",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{children:"FAQ / 常见问题"}),"\n",(0,i.jsx)(n.h3,{id:t[0].id,children:t[0].value}),"\n",(0,i.jsxs)(n.p,{children:["No. Every API falls back to built-in defaults. Call ",(0,i.jsx)(n.code,{children:"ZeroNetworkKit.init()"})," only\nwhen you want to override defaults (e.g. a custom reachability host or DNS\nservers). Connectivity alone works with zero setup."]}),"\n",(0,i.jsxs)(n.p,{children:["不需要。每个 API 都走内置默认值。只有在想覆盖默认参数(如自定义可达性主机或 DNS\n服务器)时才调用 ",(0,i.jsx)(n.code,{children:"ZeroNetworkKit.init()"}),"。单用连通性完全零配置。"]}),"\n",(0,i.jsx)(n.h3,{id:t[1].id,children:t[1].value}),"\n",(0,i.jsxs)(n.p,{children:["Android, iOS, macOS, Windows and Linux. Web is ",(0,i.jsx)(n.strong,{children:"not"})," supported."]}),"\n",(0,i.jsxs)(n.p,{children:["支持 Android、iOS、macOS、Windows 与 Linux。Web ",(0,i.jsx)(n.strong,{children:"不支持"}),"。详见\n",(0,i.jsx)(n.a,{href:"Platform-Support",children:"Platform Support"}),"。"]}),"\n",(0,i.jsx)(n.h3,{id:t[2].id,children:t[2].value}),"\n",(0,i.jsxs)(n.p,{children:["Desktop uses tier A: SSID and RSSI require system APIs that aren’t exposed on\nmacOS/Linux/Windows the same way. They are always ",(0,i.jsx)(n.code,{children:"null"})," on desktop; Windows\nadditionally provides gateway / MAC / DNS / VPN via ",(0,i.jsx)(n.code,{children:"GetAdaptersAddresses"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["桌面采用 A 档:SSID 与 RSSI 依赖系统 API,在桌面上不以同样方式暴露,因此恒为 ",(0,i.jsx)(n.code,{children:"null"}),";\nWindows 额外通过 ",(0,i.jsx)(n.code,{children:"GetAdaptersAddresses"})," 提供网关 / MAC / DNS / VPN。"]}),"\n",(0,i.jsx)(n.h3,{id:t[3].id,children:t[3].value}),"\n",(0,i.jsx)(n.p,{children:"Either the platform has no such data (e.g. desktop tier A), or the required\npermission is missing (e.g. location for Wi-Fi SSID on Android/iOS). The call\nnever throws — it degrades gracefully."}),"\n",(0,i.jsx)(n.p,{children:"要么是平台没有该数据(如桌面 A 档),要么是缺权限(如 Android/iOS 上读取 Wi-Fi SSID\n需定位权限)。该调用绝不抛异常,会优雅降级。"}),"\n",(0,i.jsx)(n.h3,{id:t[4].id,children:t[4].value}),"\n",(0,i.jsxs)(n.p,{children:["Yes — the default endpoints are Cloudflare’s public service and download ≈25 MB\nby default. Ask for consent on metered connections and override ",(0,i.jsx)(n.code,{children:"downloadUrl"})," /\n",(0,i.jsx)(n.code,{children:"uploadUrl"})," for production."]}),"\n",(0,i.jsxs)(n.p,{children:["会——默认端点指向 Cloudflare 公共服务,默认下载约 25 MB。在按量计费网络上请征得同意,\n生产环境请替换 ",(0,i.jsx)(n.code,{children:"downloadUrl"})," / ",(0,i.jsx)(n.code,{children:"uploadUrl"}),"。"]}),"\n",(0,i.jsx)(n.h3,{id:t[5].id,children:t[5].value}),"\n",(0,i.jsxs)(n.p,{children:["Every service is injectable. Implement ",(0,i.jsx)(n.code,{children:"ConnectivityAdapter"})," (or pass fake\nservice instances) and call ",(0,i.jsx)(n.code,{children:"NetworkDiagnostic.configure(...)"}),", then\n",(0,i.jsx)(n.code,{children:"NetworkDiagnostic.reset()"})," to restore defaults. See\n",(0,i.jsx)(n.a,{href:"Usage#dependency-injection--tests",children:"Usage → Dependency injection"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["每个服务都可注入。实现 ",(0,i.jsx)(n.code,{children:"ConnectivityAdapter"}),"(或直接传入假服务实例)后调用\n",(0,i.jsx)(n.code,{children:"NetworkDiagnostic.configure(...)"}),",再用 ",(0,i.jsx)(n.code,{children:"NetworkDiagnostic.reset()"})," 恢复默认。详见\n",(0,i.jsx)(n.a,{href:"Usage#dependency-injection--tests",children:"用法 → 依赖注入"}),"。"]}),"\n",(0,i.jsx)(n.h3,{id:t[6].id,children:t[6].value}),"\n",(0,i.jsxs)(n.p,{children:["MPL-2.0. See the repository ",(0,i.jsx)(n.a,{href:"https://github.com/zero-labsco/zero_network_kit/blob/main/LICENSE",children:"LICENSE"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["采用 MPL-2.0。详见仓库 ",(0,i.jsx)(n.a,{href:"https://github.com/zero-labsco/zero_network_kit/blob/main/LICENSE",children:"LICENSE"}),"。"]})]})},"/FAQ",{filePath:"pages/FAQ.md",timestamp:1789334081e3,pageMap:o.v,frontMatter:{},title:"FAQ / 常见问题"},"undefined"==typeof RemoteContent?d:RemoteContent.useTOC)},7080:function(e,t,n){"use strict";n.d(t,{v:function(){return i}});let i=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=9238)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/FAQ-fc88c8a22ac8a489.js b/docs/_next/static/chunks/pages/FAQ-fc88c8a22ac8a489.js deleted file mode 100644 index 931d518..0000000 --- a/docs/_next/static/chunks/pages/FAQ-fc88c8a22ac8a489.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[210],{9238:function(e,t,n){(window.__NEXT_P=window.__NEXT_P||[]).push(["/FAQ",function(){return n(5797)}])},5797:function(e,t,n){"use strict";n.r(t),n.d(t,{useTOC:function(){return d}});var r=n(5893),i=n(7812),o=n(7080),s=n(8925);function d(e){let t={code:"code",...(0,s.a)()};return[{value:(0,r.jsxs)(r.Fragment,{children:["Do I need to call ",(0,r.jsx)(t.code,{children:"init()"}),"? / 需要调用 ",(0,r.jsx)(t.code,{children:"init()"})," 吗?"]}),id:"do-i-need-to-call-init--需要调用-init-吗",depth:3},{value:"Which platforms are supported? / 支持哪些平台?",id:"which-platforms-are-supported--支持哪些平台",depth:3},{value:(0,r.jsxs)(r.Fragment,{children:["Why is ",(0,r.jsx)(t.code,{children:"ssid"})," / ",(0,r.jsx)(t.code,{children:"signalStrength"})," ",(0,r.jsx)(t.code,{children:"null"})," on desktop? / 为什么桌面上的 ssid/信号强度是 null?"]}),id:"why-is-ssid--signalstrength-null-on-desktop--为什么桌面上的-ssid信号强度是-null",depth:3},{value:(0,r.jsxs)(r.Fragment,{children:["Why does ",(0,r.jsx)(t.code,{children:"getNativeNetworkDetails()"})," return ",(0,r.jsx)(t.code,{children:"null"}),"? / 为什么 getNativeNetworkDetails 返回 null?"]}),id:"why-does-getnativenetworkdetails-return-null--为什么-getnativenetworkdetails-返回-null",depth:3},{value:"Does the speed test use my bandwidth? / 测速会消耗我的流量吗?",id:"does-the-speed-test-use-my-bandwidth--测速会消耗我的流量吗",depth:3},{value:"How do I test my integration without the network? / 如何脱离网络测试我的集成?",id:"how-do-i-test-my-integration-without-the-network--如何脱离网络测试我的集成",depth:3},{value:"How is this licensed? / 采用什么许可证?",id:"how-is-this-licensed--采用什么许可证",depth:3}]}t.default=(0,i.c)(function(e){let{toc:t=d(e)}=e,n={a:"a",code:"code",h1:"h1",h3:"h3",p:"p",strong:"strong",...(0,s.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{children:"FAQ / 常见问题"}),"\n",(0,r.jsx)(n.h3,{id:t[0].id,children:t[0].value}),"\n",(0,r.jsxs)(n.p,{children:["No. Every API falls back to built-in defaults. Call ",(0,r.jsx)(n.code,{children:"ZeroNetworkKit.init()"})," only\r\nwhen you want to override defaults (e.g. a custom reachability host or DNS\r\nservers). Connectivity alone works with zero setup."]}),"\n",(0,r.jsxs)(n.p,{children:["不需要。每个 API 都走内置默认值。只有在想覆盖默认参数(如自定义可达性主机或 DNS\r\n服务器)时才调用 ",(0,r.jsx)(n.code,{children:"ZeroNetworkKit.init()"}),"。单用连通性完全零配置。"]}),"\n",(0,r.jsx)(n.h3,{id:t[1].id,children:t[1].value}),"\n",(0,r.jsxs)(n.p,{children:["Android, iOS, macOS, Windows and Linux. Web is ",(0,r.jsx)(n.strong,{children:"not"})," supported."]}),"\n",(0,r.jsxs)(n.p,{children:["支持 Android、iOS、macOS、Windows 与 Linux。Web ",(0,r.jsx)(n.strong,{children:"不支持"}),"。详见\r\n",(0,r.jsx)(n.a,{href:"Platform-Support",children:"Platform Support"}),"。"]}),"\n",(0,r.jsx)(n.h3,{id:t[2].id,children:t[2].value}),"\n",(0,r.jsxs)(n.p,{children:["Desktop uses tier A: SSID and RSSI require system APIs that aren’t exposed on\r\nmacOS/Linux/Windows the same way. They are always ",(0,r.jsx)(n.code,{children:"null"})," on desktop; Windows\r\nadditionally provides gateway / MAC / DNS / VPN via ",(0,r.jsx)(n.code,{children:"GetAdaptersAddresses"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:["桌面采用 A 档:SSID 与 RSSI 依赖系统 API,在桌面上不以同样方式暴露,因此恒为 ",(0,r.jsx)(n.code,{children:"null"}),";\r\nWindows 额外通过 ",(0,r.jsx)(n.code,{children:"GetAdaptersAddresses"})," 提供网关 / MAC / DNS / VPN。"]}),"\n",(0,r.jsx)(n.h3,{id:t[3].id,children:t[3].value}),"\n",(0,r.jsx)(n.p,{children:"Either the platform has no such data (e.g. desktop tier A), or the required\r\npermission is missing (e.g. location for Wi-Fi SSID on Android/iOS). The call\r\nnever throws — it degrades gracefully."}),"\n",(0,r.jsx)(n.p,{children:"要么是平台没有该数据(如桌面 A 档),要么是缺权限(如 Android/iOS 上读取 Wi-Fi SSID\r\n需定位权限)。该调用绝不抛异常,会优雅降级。"}),"\n",(0,r.jsx)(n.h3,{id:t[4].id,children:t[4].value}),"\n",(0,r.jsxs)(n.p,{children:["Yes — the default endpoints are Cloudflare’s public service and download ≈25 MB\r\nby default. Ask for consent on metered connections and override ",(0,r.jsx)(n.code,{children:"downloadUrl"})," /\r\n",(0,r.jsx)(n.code,{children:"uploadUrl"})," for production."]}),"\n",(0,r.jsxs)(n.p,{children:["会——默认端点指向 Cloudflare 公共服务,默认下载约 25 MB。在按量计费网络上请征得同意,\r\n生产环境请替换 ",(0,r.jsx)(n.code,{children:"downloadUrl"})," / ",(0,r.jsx)(n.code,{children:"uploadUrl"}),"。"]}),"\n",(0,r.jsx)(n.h3,{id:t[5].id,children:t[5].value}),"\n",(0,r.jsxs)(n.p,{children:["Every service is injectable. Implement ",(0,r.jsx)(n.code,{children:"ConnectivityAdapter"})," (or pass fake\r\nservice instances) and call ",(0,r.jsx)(n.code,{children:"NetworkDiagnostic.configure(...)"}),", then\r\n",(0,r.jsx)(n.code,{children:"NetworkDiagnostic.reset()"})," to restore defaults. See\r\n",(0,r.jsx)(n.a,{href:"Usage#dependency-injection--tests",children:"Usage → Dependency injection"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:["每个服务都可注入。实现 ",(0,r.jsx)(n.code,{children:"ConnectivityAdapter"}),"(或直接传入假服务实例)后调用\r\n",(0,r.jsx)(n.code,{children:"NetworkDiagnostic.configure(...)"}),",再用 ",(0,r.jsx)(n.code,{children:"NetworkDiagnostic.reset()"})," 恢复默认。详见\r\n",(0,r.jsx)(n.a,{href:"Usage#dependency-injection--tests",children:"用法 → 依赖注入"}),"。"]}),"\n",(0,r.jsx)(n.h3,{id:t[6].id,children:t[6].value}),"\n",(0,r.jsxs)(n.p,{children:["MPL-2.0. See the repository ",(0,r.jsx)(n.a,{href:"https://github.com/zero-labsco/zero_network_kit/blob/main/LICENSE",children:"LICENSE"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:["采用 MPL-2.0。详见仓库 ",(0,r.jsx)(n.a,{href:"https://github.com/zero-labsco/zero_network_kit/blob/main/LICENSE",children:"LICENSE"}),"。"]})]})},"/FAQ",{filePath:"pages/FAQ.md",pageMap:o.v,frontMatter:{},title:"FAQ / 常见问题"},"undefined"==typeof RemoteContent?d:RemoteContent.useTOC)},7080:function(e,t,n){"use strict";n.d(t,{v:function(){return r}});let r=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=9238)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Full-Report-5051e1f889df2f3a.js b/docs/_next/static/chunks/pages/Full-Report-5051e1f889df2f3a.js deleted file mode 100644 index 6cffbc2..0000000 --- a/docs/_next/static/chunks/pages/Full-Report-5051e1f889df2f3a.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[390],{406:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Full-Report",function(){return e(6037)}])},6037:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return h}});var n=e(5893),t=e(7812),r=e(7080),l=e(8925);function h(i){return[{value:"Basic / 基础",id:"basic--基础",depth:2}]}s.default=(0,t.c)(function(i){let{toc:s=h(i)}=i,e={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",span:"span",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,l.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{children:"Full Report / 汇总报告"}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"NetworkDiagnostic.diagnose()"})," runs every probe you ask for and aggregates them\r\ninto one ",(0,n.jsx)(e.code,{children:"NetworkDiagnosticReport"}),". A failing sub-test never aborts the run — its\r\nfield simply stays empty/",(0,n.jsx)(e.code,{children:"null"}),"."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"NetworkDiagnostic.diagnose()"})," 运行你指定的各项探测,并汇总为一份\r\n",(0,n.jsx)(e.code,{children:"NetworkDiagnosticReport"}),"。任何子项失败都不会中断整体流程,对应字段保持空。"]}),"\n",(0,n.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" report "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"diagnose"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includePing"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeDns"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includePorts"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeSpeedTest"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeUpload"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" host"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '1.1.1.1'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" dnsDomain"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'example.com'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" dnsServers"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" <"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:">"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'1.1.1.1'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'8.8.8.8'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ports"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" <"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"int"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:">"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"80"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"443"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(report); "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// one-line summary"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(report.connection.type.label);"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(report.ping"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"?"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".averageTime);"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(report.dnsResults.length);"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(report.portResults."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"where"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"((p) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" p.isOpen).length);"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(report.speedTest"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"?"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".downloadSpeed);"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(report.quality.level.label);"})]})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"Parameter"}),(0,n.jsx)(e.th,{children:"Default"}),(0,n.jsx)(e.th,{children:"Meaning"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includePing"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"true"})}),(0,n.jsx)(e.td,{children:"Sample latency / jitter / loss"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includeDns"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"true"})}),(0,n.jsx)(e.td,{children:"Sample DNS latency"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includePorts"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"false"})}),(0,n.jsx)(e.td,{children:"Scan ports (off by default)"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includeSpeedTest"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"true"})}),(0,n.jsx)(e.td,{children:"Sample download / upload"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includeUpload"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"true"})}),(0,n.jsx)(e.td,{children:"Include the upload metric"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"host"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"config.pingHost"})}),(0,n.jsx)(e.td,{children:"Latency / port target"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"dnsDomain"})," / ",(0,n.jsx)(e.code,{children:"dnsServers"})]}),(0,n.jsx)(e.td,{children:"from config"}),(0,n.jsx)(e.td,{children:"DNS target"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"ports"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"config.probePorts"})}),(0,n.jsxs)(e.td,{children:["Ports scanned when ",(0,n.jsx)(e.code,{children:"includePorts"})," is ",(0,n.jsx)(e.code,{children:"true"})]})]})]})]}),"\n",(0,n.jsxs)(e.blockquote,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"includePorts"})," defaults to ",(0,n.jsx)(e.code,{children:"false"}),", so a default run does not scan ports.\r\n",(0,n.jsx)(e.code,{children:"includePorts"})," 默认 ",(0,n.jsx)(e.code,{children:"false"}),",默认运行不会扫描端口。"]}),"\n"]}),"\n",(0,n.jsxs)(e.p,{children:["The report is JSON-encodable via ",(0,n.jsx)(e.code,{children:"report.toMap()"}),".\r\n报告可通过 ",(0,n.jsx)(e.code,{children:"report.toMap()"})," 序列化为 JSON。"]})]})},"/Full-Report",{filePath:"pages/Full-Report.md",pageMap:r.v,frontMatter:{},title:"Full Report / 汇总报告"},"undefined"==typeof RemoteContent?h:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=406)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Full-Report-8fdda01136483e9e.js b/docs/_next/static/chunks/pages/Full-Report-8fdda01136483e9e.js new file mode 100644 index 0000000..8b076ef --- /dev/null +++ b/docs/_next/static/chunks/pages/Full-Report-8fdda01136483e9e.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[390],{406:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Full-Report",function(){return e(6037)}])},6037:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return h}});var n=e(5893),t=e(7812),r=e(7080),l=e(8925);function h(i){return[{value:"Basic / 基础",id:"basic--基础",depth:2}]}s.default=(0,t.c)(function(i){let{toc:s=h(i)}=i,e={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",span:"span",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,l.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{children:"Full Report / 汇总报告"}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"NetworkDiagnostic.diagnose()"})," runs every probe you ask for and aggregates them\ninto one ",(0,n.jsx)(e.code,{children:"NetworkDiagnosticReport"}),". A failing sub-test never aborts the run — its\nfield simply stays empty/",(0,n.jsx)(e.code,{children:"null"}),"."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"NetworkDiagnostic.diagnose()"})," 运行你指定的各项探测,并汇总为一份\n",(0,n.jsx)(e.code,{children:"NetworkDiagnosticReport"}),"。任何子项失败都不会中断整体流程,对应字段保持空。"]}),"\n",(0,n.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" report "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"diagnose"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includePing"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeDns"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includePorts"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeSpeedTest"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeUpload"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" host"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '1.1.1.1'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" dnsDomain"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'example.com'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" dnsServers"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" <"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:">"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'1.1.1.1'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'8.8.8.8'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ports"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" <"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"int"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:">"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"80"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"443"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(report); "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// one-line summary"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(report.connection.type.label);"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(report.ping"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"?"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".averageTime);"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(report.dnsResults.length);"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(report.portResults."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"where"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"((p) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" p.isOpen).length);"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(report.speedTest"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"?"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".downloadSpeed);"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(report.quality.level.label);"})]})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"Parameter"}),(0,n.jsx)(e.th,{children:"Default"}),(0,n.jsx)(e.th,{children:"Meaning"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includePing"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"true"})}),(0,n.jsx)(e.td,{children:"Sample latency / jitter / loss"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includeDns"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"true"})}),(0,n.jsx)(e.td,{children:"Sample DNS latency"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includePorts"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"false"})}),(0,n.jsx)(e.td,{children:"Scan ports (off by default)"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includeSpeedTest"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"true"})}),(0,n.jsx)(e.td,{children:"Sample download / upload"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includeUpload"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"true"})}),(0,n.jsx)(e.td,{children:"Include the upload metric"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"host"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"config.pingHost"})}),(0,n.jsx)(e.td,{children:"Latency / port target"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"dnsDomain"})," / ",(0,n.jsx)(e.code,{children:"dnsServers"})]}),(0,n.jsx)(e.td,{children:"from config"}),(0,n.jsx)(e.td,{children:"DNS target"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"ports"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"config.probePorts"})}),(0,n.jsxs)(e.td,{children:["Ports scanned when ",(0,n.jsx)(e.code,{children:"includePorts"})," is ",(0,n.jsx)(e.code,{children:"true"})]})]})]})]}),"\n",(0,n.jsxs)(e.blockquote,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"includePorts"})," defaults to ",(0,n.jsx)(e.code,{children:"false"}),", so a default run does not scan ports.\n",(0,n.jsx)(e.code,{children:"includePorts"})," 默认 ",(0,n.jsx)(e.code,{children:"false"}),",默认运行不会扫描端口。"]}),"\n"]}),"\n",(0,n.jsxs)(e.p,{children:["The report is JSON-encodable via ",(0,n.jsx)(e.code,{children:"report.toMap()"}),".\n报告可通过 ",(0,n.jsx)(e.code,{children:"report.toMap()"})," 序列化为 JSON。"]})]})},"/Full-Report",{filePath:"pages/Full-Report.md",timestamp:1789334081e3,pageMap:r.v,frontMatter:{},title:"Full Report / 汇总报告"},"undefined"==typeof RemoteContent?h:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=406)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Getting-Started-51c49bf7439b90f4.js b/docs/_next/static/chunks/pages/Getting-Started-0b9a79d0ebc87cdf.js similarity index 51% rename from docs/_next/static/chunks/pages/Getting-Started-51c49bf7439b90f4.js rename to docs/_next/static/chunks/pages/Getting-Started-0b9a79d0ebc87cdf.js index a590c6b..95239b4 100644 --- a/docs/_next/static/chunks/pages/Getting-Started-51c49bf7439b90f4.js +++ b/docs/_next/static/chunks/pages/Getting-Started-0b9a79d0ebc87cdf.js @@ -1 +1 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[796],{9364:function(i,e,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Getting-Started",function(){return s(1028)}])},1028:function(i,e,s){"use strict";s.r(e),s.d(e,{useTOC:function(){return h}});var n=s(5893),t=s(7812),r=s(7080),l=s(8925);function h(i){return[{value:"Quick Start / 快速开始",id:"quick-start--快速开始",depth:2},{value:"What you get / 你能得到什么",id:"what-you-get--你能得到什么",depth:2},{value:"Lifecycle / 生命周期",id:"lifecycle--生命周期",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}e.default=(0,t.c)(function(i){let{toc:e=h(i)}=i,s={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,l.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.h1,{children:"Getting Started / 快速开始"}),"\n",(0,n.jsx)(s.h2,{id:e[0].id,children:e[0].value}),"\n",(0,n.jsxs)(s.p,{children:["Import the package and start diagnosing — no ",(0,n.jsx)(s.code,{children:"init()"})," required:"]}),"\n",(0,n.jsxs)(s.p,{children:["导入包即可开始诊断,无需 ",(0,n.jsx)(s.code,{children:"init()"}),":"]}),"\n",(0,n.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'package:flutter/material.dart'"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'package:zero_network_kit/zero_network_kit.dart'"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),"\n",(0,n.jsx)(s.span,{children:" "}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"void"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" main"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"() {"})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" // Optional: apply your own global defaults once."})}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" // 可选:全局定制一次默认参数。"})}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ZeroNetworkKit"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"init"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" config"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnosticConfig"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(pingHost"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '1.1.1.1'"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" );"})}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" runApp"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"const"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" MyApp"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"());"})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsxs)(s.p,{children:["If you only need connectivity, you don’t even need ",(0,n.jsx)(s.code,{children:"init()"}),":"]}),"\n",(0,n.jsxs)(s.p,{children:["如果只需要连通性,连 ",(0,n.jsx)(s.code,{children:"init()"})," 都不需要:"]}),"\n",(0,n.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" connection "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"checkConnection"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"type"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"label"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" \xb7 "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ipAddress"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})]})}),"\n",(0,n.jsx)(s.h2,{id:e[1].id,children:e[1].value}),"\n",(0,n.jsxs)(s.p,{children:["Every method is a static, non-blocking call on the ",(0,n.jsx)(s.code,{children:"NetworkDiagnostic"})," facade.\r\nThe plugin is pure Dart under the hood, so it is fully injectable and testable\r\nwithout touching the network."]}),"\n",(0,n.jsxs)(s.p,{children:["每个方法都是 ",(0,n.jsx)(s.code,{children:"NetworkDiagnostic"})," 门面上的静态、非阻塞调用。插件内核是纯 Dart,\r\n因此完全可注入、可脱离网络做测试。"]}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(s.table,{children:[(0,n.jsx)(s.thead,{children:(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.th,{children:"Need"}),(0,n.jsx)(s.th,{children:"Call"})]})}),(0,n.jsxs)(s.tbody,{children:[(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Am I online, on what transport?"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"NetworkDiagnostic.checkConnection()"})})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"React to Wi-Fi ⇄ cellular switches"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"NetworkDiagnostic.onConnectivityChanged"})})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Latency, jitter, packet loss"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"NetworkDiagnostic.ping()"})})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Is DNS slow or broken?"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"NetworkDiagnostic.resolve()"})})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsxs)(s.td,{children:["Is ",(0,n.jsx)(s.code,{children:"host:port"})," reachable?"]}),(0,n.jsxs)(s.td,{children:[(0,n.jsx)(s.code,{children:"NetworkDiagnostic.checkPort()"})," / ",(0,n.jsx)(s.code,{children:"isPortOpen()"})]})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"How fast is down/up?"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"NetworkDiagnostic.runSpeedTest()"})})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"One number for “good or bad”"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"NetworkDiagnostic.evaluateQuality()"})})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Everything at once"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"NetworkDiagnostic.diagnose()"})})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Native version / SSID / gateway / MAC"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"ZeroNetworkKit.getNativeNetworkDetails()"})})]})]})]}),"\n",(0,n.jsxs)(s.p,{children:["See ",(0,n.jsx)(s.a,{href:"Usage#which-api-do-i-need",children:"Which API do I need?"})," for the full map."]}),"\n",(0,n.jsx)(s.h2,{id:e[2].id,children:e[2].value}),"\n",(0,n.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ZeroNetworkKit"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".isInitialized; "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// false until init() runs"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ZeroNetworkKit"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".config; "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// the effective NetworkDiagnosticConfig"})]}),"\n",(0,n.jsx)(s.span,{children:" "}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ZeroNetworkKit"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"dispose"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// releases the HTTP client the plugin owns"})]})]})}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"dispose()"})," only closes the HTTP client the plugin created itself. An\r\n",(0,n.jsx)(s.code,{children:"http.Client"})," you injected stays open — close it yourself."]}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"dispose()"})," 只会关闭插件自己创建的 HTTP 客户端;你注入的 ",(0,n.jsx)(s.code,{children:"http.Client"})," 不会被关闭。"]}),"\n",(0,n.jsx)(s.h2,{id:e[3].id,children:e[3].value}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.a,{href:"Installation",children:"Installation"})," — Detailed installation methods / 详细安装方式"]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.a,{href:"Usage",children:"Usage"})," — Global config & dependency injection / 全局配置与依赖注入"]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.a,{href:"Platform-Support",children:"Platform Support"})," — Capability matrix / 能力矩阵"]}),"\n"]})]})},"/Getting-Started",{filePath:"pages/Getting-Started.md",pageMap:r.v,frontMatter:{},title:"Getting Started / 快速开始"},"undefined"==typeof RemoteContent?h:RemoteContent.useTOC)},7080:function(i,e,s){"use strict";s.d(e,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=9364)}),_N_E=i.O()}]); \ No newline at end of file +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[796],{9364:function(i,e,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Getting-Started",function(){return s(1028)}])},1028:function(i,e,s){"use strict";s.r(e),s.d(e,{useTOC:function(){return h}});var n=s(5893),t=s(7812),r=s(7080),l=s(8925);function h(i){return[{value:"Quick Start / 快速开始",id:"quick-start--快速开始",depth:2},{value:"What you get / 你能得到什么",id:"what-you-get--你能得到什么",depth:2},{value:"Lifecycle / 生命周期",id:"lifecycle--生命周期",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}e.default=(0,t.c)(function(i){let{toc:e=h(i)}=i,s={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,l.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.h1,{children:"Getting Started / 快速开始"}),"\n",(0,n.jsx)(s.h2,{id:e[0].id,children:e[0].value}),"\n",(0,n.jsxs)(s.p,{children:["Import the package and start diagnosing — no ",(0,n.jsx)(s.code,{children:"init()"})," required:"]}),"\n",(0,n.jsxs)(s.p,{children:["导入包即可开始诊断,无需 ",(0,n.jsx)(s.code,{children:"init()"}),":"]}),"\n",(0,n.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'package:flutter/material.dart'"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'package:zero_network_kit/zero_network_kit.dart'"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),"\n",(0,n.jsx)(s.span,{children:" "}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"void"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" main"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"() {"})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" // Optional: apply your own global defaults once."})}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:" // 可选:全局定制一次默认参数。"})}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ZeroNetworkKit"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"init"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" config"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnosticConfig"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(pingHost"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '1.1.1.1'"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" );"})}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" runApp"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"const"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" MyApp"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"());"})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsxs)(s.p,{children:["If you only need connectivity, you don’t even need ",(0,n.jsx)(s.code,{children:"init()"}),":"]}),"\n",(0,n.jsxs)(s.p,{children:["如果只需要连通性,连 ",(0,n.jsx)(s.code,{children:"init()"})," 都不需要:"]}),"\n",(0,n.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" connection "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"checkConnection"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"type"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"label"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" \xb7 "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"connection"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ipAddress"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})]})}),"\n",(0,n.jsx)(s.h2,{id:e[1].id,children:e[1].value}),"\n",(0,n.jsxs)(s.p,{children:["Every method is a static, non-blocking call on the ",(0,n.jsx)(s.code,{children:"NetworkDiagnostic"})," facade.\nThe plugin is pure Dart under the hood, so it is fully injectable and testable\nwithout touching the network."]}),"\n",(0,n.jsxs)(s.p,{children:["每个方法都是 ",(0,n.jsx)(s.code,{children:"NetworkDiagnostic"})," 门面上的静态、非阻塞调用。插件内核是纯 Dart,\n因此完全可注入、可脱离网络做测试。"]}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(s.table,{children:[(0,n.jsx)(s.thead,{children:(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.th,{children:"Need"}),(0,n.jsx)(s.th,{children:"Call"})]})}),(0,n.jsxs)(s.tbody,{children:[(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Am I online, on what transport?"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"NetworkDiagnostic.checkConnection()"})})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"React to Wi-Fi ⇄ cellular switches"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"NetworkDiagnostic.onConnectivityChanged"})})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Latency, jitter, packet loss"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"NetworkDiagnostic.ping()"})})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Is DNS slow or broken?"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"NetworkDiagnostic.resolve()"})})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsxs)(s.td,{children:["Is ",(0,n.jsx)(s.code,{children:"host:port"})," reachable?"]}),(0,n.jsxs)(s.td,{children:[(0,n.jsx)(s.code,{children:"NetworkDiagnostic.checkPort()"})," / ",(0,n.jsx)(s.code,{children:"isPortOpen()"})]})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"How fast is down/up?"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"NetworkDiagnostic.runSpeedTest()"})})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"One number for “good or bad”"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"NetworkDiagnostic.evaluateQuality()"})})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Everything at once"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"NetworkDiagnostic.diagnose()"})})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Native version / SSID / gateway / MAC"}),(0,n.jsx)(s.td,{children:(0,n.jsx)(s.code,{children:"ZeroNetworkKit.getNativeNetworkDetails()"})})]})]})]}),"\n",(0,n.jsxs)(s.p,{children:["See ",(0,n.jsx)(s.a,{href:"Usage#which-api-do-i-need",children:"Which API do I need?"})," for the full map."]}),"\n",(0,n.jsx)(s.h2,{id:e[2].id,children:e[2].value}),"\n",(0,n.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ZeroNetworkKit"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".isInitialized; "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// false until init() runs"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ZeroNetworkKit"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".config; "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// the effective NetworkDiagnosticConfig"})]}),"\n",(0,n.jsx)(s.span,{children:" "}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ZeroNetworkKit"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"dispose"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// releases the HTTP client the plugin owns"})]})]})}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"dispose()"})," only closes the HTTP client the plugin created itself. An\n",(0,n.jsx)(s.code,{children:"http.Client"})," you injected stays open — close it yourself."]}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"dispose()"})," 只会关闭插件自己创建的 HTTP 客户端;你注入的 ",(0,n.jsx)(s.code,{children:"http.Client"})," 不会被关闭。"]}),"\n",(0,n.jsx)(s.h2,{id:e[3].id,children:e[3].value}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.a,{href:"Installation",children:"Installation"})," — Detailed installation methods / 详细安装方式"]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.a,{href:"Usage",children:"Usage"})," — Global config & dependency injection / 全局配置与依赖注入"]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.a,{href:"Platform-Support",children:"Platform Support"})," — Capability matrix / 能力矩阵"]}),"\n"]})]})},"/Getting-Started",{filePath:"pages/Getting-Started.md",timestamp:1789334081e3,pageMap:r.v,frontMatter:{},title:"Getting Started / 快速开始"},"undefined"==typeof RemoteContent?h:RemoteContent.useTOC)},7080:function(i,e,s){"use strict";s.d(e,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=9364)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Installation-43ade467e1e7ca4a.js b/docs/_next/static/chunks/pages/Installation-43ade467e1e7ca4a.js new file mode 100644 index 0000000..b653e6c --- /dev/null +++ b/docs/_next/static/chunks/pages/Installation-43ade467e1e7ca4a.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[139],{9720:function(e,i,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Installation",function(){return t(1220)}])},1220:function(e,i,t){"use strict";t.r(i),t.d(i,{useTOC:function(){return l}});var n=t(5893),s=t(7812),r=t(7080),d=t(8925),a=t(5192);function l(e){return[{value:"From pub.dev (Recommended) / 从 pub.dev 安装(推荐)",id:"from-pubdev-recommended--从-pubdev-安装推荐",depth:2},{value:"From GitHub / 从 GitHub 安装",id:"from-github--从-github-安装",depth:2},{value:"Platform Setup / 平台配置",id:"platform-setup--平台配置",depth:2},{value:"Android",id:"android",depth:3},{value:"iOS",id:"ios",depth:3},{value:"macOS / Windows / Linux",id:"macos--windows--linux",depth:3},{value:"Import / 导入",id:"import--导入",depth:2},{value:"Requirements / 环境要求",id:"requirements--环境要求",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}i.default=(0,s.c)(function(e){let{toc:i=l(e)}=e,t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,d.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{children:"Installation / 安装"}),"\n",(0,n.jsx)(t.h2,{id:i[0].id,children:i[0].value}),"\n",(0,n.jsxs)(t.p,{children:["Add the following to your ",(0,n.jsx)(t.code,{children:"pubspec.yaml"}),":"]}),"\n",(0,n.jsxs)(t.p,{children:["在 ",(0,n.jsx)(t.code,{children:"pubspec.yaml"})," 中添加以下依赖:"]}),"\n",(0,n.jsx)(t.pre,{tabIndex:"0","data-language":"yaml","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(t.code,{children:[(0,n.jsxs)(t.span,{children:[(0,n.jsx)(t.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:"dependencies"}),(0,n.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:":"})]}),"\n",(0,n.jsxs)(t.span,{children:[(0,n.jsx)(t.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" zero_network_kit"}),(0,n.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(t.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"^1.0.1"})]})]})}),"\n",(0,n.jsx)(t.p,{children:"Then run:"}),"\n",(0,n.jsx)(t.p,{children:"然后运行:"}),"\n",(0,n.jsx)(t.pre,{icon:a.Fx,tabIndex:"0","data-language":"bash","data-word-wrap":"","data-copy":"",children:(0,n.jsx)(t.code,{children:(0,n.jsxs)(t.span,{children:[(0,n.jsx)(t.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"flutter"}),(0,n.jsx)(t.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" pub"}),(0,n.jsx)(t.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" get"})]})})}),"\n",(0,n.jsx)(t.h2,{id:i[1].id,children:i[1].value}),"\n",(0,n.jsx)(t.p,{children:"Alternatively, install from GitHub:"}),"\n",(0,n.jsx)(t.p,{children:"或者从 GitHub 安装:"}),"\n",(0,n.jsx)(t.pre,{tabIndex:"0","data-language":"yaml","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(t.code,{children:[(0,n.jsxs)(t.span,{children:[(0,n.jsx)(t.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:"dependencies"}),(0,n.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:":"})]}),"\n",(0,n.jsxs)(t.span,{children:[(0,n.jsx)(t.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" zero_network_kit"}),(0,n.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:":"})]}),"\n",(0,n.jsxs)(t.span,{children:[(0,n.jsx)(t.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" git"}),(0,n.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:":"})]}),"\n",(0,n.jsxs)(t.span,{children:[(0,n.jsx)(t.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" url"}),(0,n.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(t.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"https://github.com/zero-labsco/zero_network_kit.git"})]}),"\n",(0,n.jsxs)(t.span,{children:[(0,n.jsx)(t.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" ref"}),(0,n.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(t.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"release/v1.0.1"})]})]})}),"\n",(0,n.jsx)(t.h2,{id:i[2].id,children:i[2].value}),"\n",(0,n.jsx)(t.h3,{id:i[3].id,children:i[3].value}),"\n",(0,n.jsxs)(t.p,{children:["The plugin manifest already declares ",(0,n.jsx)(t.code,{children:"INTERNET"}),", ",(0,n.jsx)(t.code,{children:"ACCESS_NETWORK_STATE"})," and\n",(0,n.jsx)(t.code,{children:"ACCESS_WIFI_STATE"}),". Reading the Wi-Fi ",(0,n.jsx)(t.strong,{children:"SSID"})," additionally requires the\nlocation permission (",(0,n.jsx)(t.code,{children:"ACCESS_FINE_LOCATION"}),") on Android 8.1+, otherwise the\nsnapshot reports ",(0,n.jsx)(t.code,{children:"ssid: null"}),"."]}),"\n",(0,n.jsxs)(t.p,{children:["插件清单已声明 ",(0,n.jsx)(t.code,{children:"INTERNET"}),"、",(0,n.jsx)(t.code,{children:"ACCESS_NETWORK_STATE"})," 与 ",(0,n.jsx)(t.code,{children:"ACCESS_WIFI_STATE"}),"。读取 Wi-Fi\n",(0,n.jsx)(t.strong,{children:"SSID"})," 还需在 Android 8.1+ 申请定位权限(",(0,n.jsx)(t.code,{children:"ACCESS_FINE_LOCATION"}),"),否则快照中\n",(0,n.jsx)(t.code,{children:"ssid"})," 为 ",(0,n.jsx)(t.code,{children:"null"}),"。"]}),"\n",(0,n.jsx)(t.h3,{id:i[4].id,children:i[4].value}),"\n",(0,n.jsxs)(t.p,{children:["No additional configuration needed. Reading the Wi-Fi ",(0,n.jsx)(t.strong,{children:"SSID"})," additionally\nrequires the ",(0,n.jsx)(t.em,{children:"Access WiFi Information"})," capability plus location authorisation."]}),"\n",(0,n.jsxs)(t.p,{children:["无需额外配置。读取 Wi-Fi ",(0,n.jsx)(t.strong,{children:"SSID"})," 还需开启 ",(0,n.jsx)(t.em,{children:"Access WiFi Information"})," 能力并授权定位。"]}),"\n",(0,n.jsx)(t.h3,{id:i[5].id,children:i[5].value}),"\n",(0,n.jsxs)(t.p,{children:["The plugin is declared on all three desktop platforms. On desktop, native\ndetails such as SSID / RSSI are ",(0,n.jsxs)(t.strong,{children:["always ",(0,n.jsx)(t.code,{children:"null"})]})," (tier A). Windows additionally\nprovides gateway / MAC / DNS / VPN through ",(0,n.jsx)(t.code,{children:"GetAdaptersAddresses"}),"; macOS and\nLinux report only the Dart-side IP/IPv6. See\n",(0,n.jsx)(t.a,{href:"Platform-Support",children:"Platform Support"})," for the full matrix."]}),"\n",(0,n.jsxs)(t.p,{children:["插件已在三个桌面平台声明。桌面上 SSID / 信号强度等原生详情",(0,n.jsxs)(t.strong,{children:["恒为 ",(0,n.jsx)(t.code,{children:"null"})]}),"(A 档)。\nWindows 额外通过 ",(0,n.jsx)(t.code,{children:"GetAdaptersAddresses"})," 提供网关 / MAC / DNS / VPN;macOS 与 Linux\n仅提供 Dart 侧的 IP/IPv6。完整矩阵见",(0,n.jsx)(t.a,{href:"Platform-Support",children:"平台支持"}),"。"]}),"\n",(0,n.jsx)(t.h2,{id:i[6].id,children:i[6].value}),"\n",(0,n.jsx)(t.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsx)(t.code,{children:(0,n.jsxs)(t.span,{children:[(0,n.jsx)(t.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,n.jsx)(t.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'package:zero_network_kit/zero_network_kit.dart'"}),(0,n.jsx)(t.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]})})}),"\n",(0,n.jsx)(t.h2,{id:i[7].id,children:i[7].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(t.table,{children:[(0,n.jsx)(t.thead,{children:(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.th,{children:"Requirement"}),(0,n.jsx)(t.th,{children:"Version"})]})}),(0,n.jsxs)(t.tbody,{children:[(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{children:"Flutter"}),(0,n.jsx)(t.td,{children:">= 3.3.0"})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{children:"Dart SDK"}),(0,n.jsx)(t.td,{children:">= 3.11.0 < 4.0.0"})]})]})]}),"\n",(0,n.jsx)(t.h2,{id:i[8].id,children:i[8].value}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.a,{href:"Getting-Started",children:"Getting Started"})," — Quick start guide / 快速开始"]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.a,{href:"Usage",children:"Usage"})," — Full usage guide / 完整使用指南"]}),"\n"]})]})},"/Installation",{filePath:"pages/Installation.md",timestamp:1789334081e3,pageMap:r.v,frontMatter:{},title:"Installation / 安装"},"undefined"==typeof RemoteContent?l:RemoteContent.useTOC)},7080:function(e,i,t){"use strict";t.d(i,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=9720)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Installation-b38e40fcafc59c1e.js b/docs/_next/static/chunks/pages/Installation-b38e40fcafc59c1e.js deleted file mode 100644 index 20610a2..0000000 --- a/docs/_next/static/chunks/pages/Installation-b38e40fcafc59c1e.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[139],{9720:function(e,i,n){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Installation",function(){return n(1220)}])},1220:function(e,i,n){"use strict";n.r(i),n.d(i,{useTOC:function(){return l}});var t=n(5893),r=n(7812),s=n(7080),d=n(8925),a=n(5192);function l(e){return[{value:"From pub.dev (Recommended) / 从 pub.dev 安装(推荐)",id:"from-pubdev-recommended--从-pubdev-安装推荐",depth:2},{value:"From GitHub / 从 GitHub 安装",id:"from-github--从-github-安装",depth:2},{value:"Platform Setup / 平台配置",id:"platform-setup--平台配置",depth:2},{value:"Android",id:"android",depth:3},{value:"iOS",id:"ios",depth:3},{value:"macOS / Windows / Linux",id:"macos--windows--linux",depth:3},{value:"Import / 导入",id:"import--导入",depth:2},{value:"Requirements / 环境要求",id:"requirements--环境要求",depth:2},{value:"Next Steps / 下一步",id:"next-steps--下一步",depth:2}]}i.default=(0,r.c)(function(e){let{toc:i=l(e)}=e,n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,d.a)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{children:"Installation / 安装"}),"\n",(0,t.jsx)(n.h2,{id:i[0].id,children:i[0].value}),"\n",(0,t.jsxs)(n.p,{children:["Add the following to your ",(0,t.jsx)(n.code,{children:"pubspec.yaml"}),":"]}),"\n",(0,t.jsxs)(n.p,{children:["在 ",(0,t.jsx)(n.code,{children:"pubspec.yaml"})," 中添加以下依赖:"]}),"\n",(0,t.jsx)(n.pre,{tabIndex:"0","data-language":"yaml","data-word-wrap":"","data-copy":"",children:(0,t.jsxs)(n.code,{children:[(0,t.jsxs)(n.span,{children:[(0,t.jsx)(n.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:"dependencies"}),(0,t.jsx)(n.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:":"})]}),"\n",(0,t.jsxs)(n.span,{children:[(0,t.jsx)(n.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" zero_network_kit"}),(0,t.jsx)(n.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,t.jsx)(n.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"^1.0.0"})]})]})}),"\n",(0,t.jsx)(n.p,{children:"Then run:"}),"\n",(0,t.jsx)(n.p,{children:"然后运行:"}),"\n",(0,t.jsx)(n.pre,{icon:a.Fx,tabIndex:"0","data-language":"bash","data-word-wrap":"","data-copy":"",children:(0,t.jsx)(n.code,{children:(0,t.jsxs)(n.span,{children:[(0,t.jsx)(n.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"flutter"}),(0,t.jsx)(n.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" pub"}),(0,t.jsx)(n.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" get"})]})})}),"\n",(0,t.jsx)(n.h2,{id:i[1].id,children:i[1].value}),"\n",(0,t.jsx)(n.p,{children:"Alternatively, install from GitHub:"}),"\n",(0,t.jsx)(n.p,{children:"或者从 GitHub 安装:"}),"\n",(0,t.jsx)(n.pre,{tabIndex:"0","data-language":"yaml","data-word-wrap":"","data-copy":"",children:(0,t.jsxs)(n.code,{children:[(0,t.jsxs)(n.span,{children:[(0,t.jsx)(n.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:"dependencies"}),(0,t.jsx)(n.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:":"})]}),"\n",(0,t.jsxs)(n.span,{children:[(0,t.jsx)(n.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" zero_network_kit"}),(0,t.jsx)(n.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:":"})]}),"\n",(0,t.jsxs)(n.span,{children:[(0,t.jsx)(n.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" git"}),(0,t.jsx)(n.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:":"})]}),"\n",(0,t.jsxs)(n.span,{children:[(0,t.jsx)(n.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" url"}),(0,t.jsx)(n.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,t.jsx)(n.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"https://github.com/zero-labsco/zero_network_kit.git"})]}),"\n",(0,t.jsxs)(n.span,{children:[(0,t.jsx)(n.span,{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"},children:" ref"}),(0,t.jsx)(n.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,t.jsx)(n.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"release/v1.0.0"})]})]})}),"\n",(0,t.jsx)(n.h2,{id:i[2].id,children:i[2].value}),"\n",(0,t.jsx)(n.h3,{id:i[3].id,children:i[3].value}),"\n",(0,t.jsxs)(n.p,{children:["The plugin manifest already declares ",(0,t.jsx)(n.code,{children:"INTERNET"}),", ",(0,t.jsx)(n.code,{children:"ACCESS_NETWORK_STATE"})," and\r\n",(0,t.jsx)(n.code,{children:"ACCESS_WIFI_STATE"}),". Reading the Wi-Fi ",(0,t.jsx)(n.strong,{children:"SSID"})," additionally requires the\r\nlocation permission (",(0,t.jsx)(n.code,{children:"ACCESS_FINE_LOCATION"}),") on Android 8.1+, otherwise the\r\nsnapshot reports ",(0,t.jsx)(n.code,{children:"ssid: null"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["插件清单已声明 ",(0,t.jsx)(n.code,{children:"INTERNET"}),"、",(0,t.jsx)(n.code,{children:"ACCESS_NETWORK_STATE"})," 与 ",(0,t.jsx)(n.code,{children:"ACCESS_WIFI_STATE"}),"。读取 Wi-Fi\r\n",(0,t.jsx)(n.strong,{children:"SSID"})," 还需在 Android 8.1+ 申请定位权限(",(0,t.jsx)(n.code,{children:"ACCESS_FINE_LOCATION"}),"),否则快照中\r\n",(0,t.jsx)(n.code,{children:"ssid"})," 为 ",(0,t.jsx)(n.code,{children:"null"}),"。"]}),"\n",(0,t.jsx)(n.h3,{id:i[4].id,children:i[4].value}),"\n",(0,t.jsxs)(n.p,{children:["No additional configuration needed. Reading the Wi-Fi ",(0,t.jsx)(n.strong,{children:"SSID"})," additionally\r\nrequires the ",(0,t.jsx)(n.em,{children:"Access WiFi Information"})," capability plus location authorisation."]}),"\n",(0,t.jsxs)(n.p,{children:["无需额外配置。读取 Wi-Fi ",(0,t.jsx)(n.strong,{children:"SSID"})," 还需开启 ",(0,t.jsx)(n.em,{children:"Access WiFi Information"})," 能力并授权定位。"]}),"\n",(0,t.jsx)(n.h3,{id:i[5].id,children:i[5].value}),"\n",(0,t.jsxs)(n.p,{children:["The plugin is declared on all three desktop platforms. On desktop, native\r\ndetails such as SSID / RSSI are ",(0,t.jsxs)(n.strong,{children:["always ",(0,t.jsx)(n.code,{children:"null"})]})," (tier A). Windows additionally\r\nprovides gateway / MAC / DNS / VPN through ",(0,t.jsx)(n.code,{children:"GetAdaptersAddresses"}),"; macOS and\r\nLinux report only the Dart-side IP/IPv6. See\r\n",(0,t.jsx)(n.a,{href:"Platform-Support",children:"Platform Support"})," for the full matrix."]}),"\n",(0,t.jsxs)(n.p,{children:["插件已在三个桌面平台声明。桌面上 SSID / 信号强度等原生详情",(0,t.jsxs)(n.strong,{children:["恒为 ",(0,t.jsx)(n.code,{children:"null"})]}),"(A 档)。\r\nWindows 额外通过 ",(0,t.jsx)(n.code,{children:"GetAdaptersAddresses"})," 提供网关 / MAC / DNS / VPN;macOS 与 Linux\r\n仅提供 Dart 侧的 IP/IPv6。完整矩阵见",(0,t.jsx)(n.a,{href:"Platform-Support",children:"平台支持"}),"。"]}),"\n",(0,t.jsx)(n.h2,{id:i[6].id,children:i[6].value}),"\n",(0,t.jsx)(n.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,t.jsx)(n.code,{children:(0,t.jsxs)(n.span,{children:[(0,t.jsx)(n.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,t.jsx)(n.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'package:zero_network_kit/zero_network_kit.dart'"}),(0,t.jsx)(n.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]})})}),"\n",(0,t.jsx)(n.h2,{id:i[7].id,children:i[7].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,t.jsxs)(n.table,{children:[(0,t.jsx)(n.thead,{children:(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.th,{children:"Requirement"}),(0,t.jsx)(n.th,{children:"Version"})]})}),(0,t.jsxs)(n.tbody,{children:[(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"Flutter"}),(0,t.jsx)(n.td,{children:">= 3.3.0"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"Dart SDK"}),(0,t.jsx)(n.td,{children:">= 3.11.0 < 4.0.0"})]})]})]}),"\n",(0,t.jsx)(n.h2,{id:i[8].id,children:i[8].value}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"Getting-Started",children:"Getting Started"})," — Quick start guide / 快速开始"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"Usage",children:"Usage"})," — Full usage guide / 完整使用指南"]}),"\n"]})]})},"/Installation",{filePath:"pages/Installation.md",pageMap:s.v,frontMatter:{},title:"Installation / 安装"},"undefined"==typeof RemoteContent?l:RemoteContent.useTOC)},7080:function(e,i,n){"use strict";n.d(i,{v:function(){return t}});let t=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=9720)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Ping-e7614d3667bef7af.js b/docs/_next/static/chunks/pages/Ping-e7614d3667bef7af.js new file mode 100644 index 0000000..f004f99 --- /dev/null +++ b/docs/_next/static/chunks/pages/Ping-e7614d3667bef7af.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[811],{2357:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Ping",function(){return e(4804)}])},4804:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return r}});var h=e(5893),n=e(7812),t=e(7080),l=e(8925);function r(i){return[{value:"Basic / 基础",id:"basic--基础",depth:2},{value:"TCP vs ICMP / TCP 与 ICMP",id:"tcp-vs-icmp--tcp-与-icmp",depth:2}]}s.default=(0,n.c)(function(i){let{toc:s=r(i)}=i,e={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,l.a)(),...i.components};return(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(e.h1,{children:"Latency / Ping / 延迟探测"}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"NetworkDiagnostic.ping()"})," measures round-trip time towards a target host and\nreports sent / received counts, packet loss, min/avg/max and jitter."]}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"NetworkDiagnostic.ping()"})," 测量到目标主机的往返时间,并给出发送/接收次数、丢包率、\n最小/平均/最大耗时与抖动。"]}),"\n",(0,h.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ping "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" host"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '1.1.1.1'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" count"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" timeout"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Duration"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(seconds"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 2"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" interval"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Duration"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(milliseconds"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 200"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" port"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 443"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,h.jsx)(e.span,{children:" "}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'received : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"received"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"/"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"sent"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'loss : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"packetLoss"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" %'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'min/avg/max: "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"minTime"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" / '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"averageTime"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" / '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"maxTime"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'jitter : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"jitter"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"2"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'samples : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"times"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,h.jsxs)(e.table,{children:[(0,h.jsx)(e.thead,{children:(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.th,{children:"Parameter"}),(0,h.jsx)(e.th,{children:"Default"}),(0,h.jsx)(e.th,{children:"Meaning"})]})}),(0,h.jsxs)(e.tbody,{children:[(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"host"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.pingHost"})}),(0,h.jsx)(e.td,{children:"Target host"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"count"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.pingCount"})}),(0,h.jsx)(e.td,{children:"Number of probes"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"timeout"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.pingTimeout"})}),(0,h.jsx)(e.td,{children:"Per-probe timeout"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"interval"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.pingInterval"})}),(0,h.jsx)(e.td,{children:"Delay between probes"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"port"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.pingPort"})}),(0,h.jsxs)(e.td,{children:["TCP port probed in ",(0,h.jsx)(e.code,{children:"PingMode.tcp"})]})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"mode"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"PingMode.tcp"})}),(0,h.jsxs)(e.td,{children:[(0,h.jsx)(e.code,{children:"PingMode.tcp"})," or ",(0,h.jsx)(e.code,{children:"PingMode.icmp"})]})]})]})]}),"\n",(0,h.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"PingMode.tcp"})," performs a TCP handshake to ",(0,h.jsx)(e.code,{children:"host:port"})," — the portable equivalent\nof ICMP and the ",(0,h.jsx)(e.strong,{children:"only mode available on Android/iOS"}),"."]}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"PingMode.tcp"})," 通过 TCP 握手到 ",(0,h.jsx)(e.code,{children:"host:port"})," 测量往返,是移动端",(0,h.jsx)(e.strong,{children:"唯一可用的模式"}),"。"]}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Desktop only — falls back gracefully if the `ping` binary is unavailable."})}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(host"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '1.1.1.1'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", count"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 4"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", mode"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" PingMode"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".icmp);"})]})]})}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"ping.isSuccess"})," is ",(0,h.jsx)(e.code,{children:"true"})," when at least one probe answered; check it before\ntrusting the averages."]}),"\n",(0,h.jsxs)(e.p,{children:["至少一次成功响应时 ",(0,h.jsx)(e.code,{children:"isSuccess"})," 为 ",(0,h.jsx)(e.code,{children:"true"}),",读平均值前建议先判断它。"]}),"\n",(0,h.jsxs)(e.blockquote,{children:["\n",(0,h.jsxs)(e.p,{children:["A TCP ping needs a ",(0,h.jsx)(e.strong,{children:"listening port"}),". Probing ",(0,h.jsx)(e.code,{children:"host"})," with ",(0,h.jsx)(e.code,{children:"port: 443"})," fails if\nthat host does not accept TCP/443 — that is “filtered”, not “offline”. Use\n",(0,h.jsx)(e.code,{children:"mode: PingMode.icmp"})," on desktop to get closer to real ICMP.\nTCP 探测需要一个",(0,h.jsx)(e.strong,{children:"在监听的端口"}),"。对不接受 TCP/443 的主机探测 ",(0,h.jsx)(e.code,{children:"port: 443"})," 会失败——\n那是“被过滤”,不是“离线”。在桌面上用 ",(0,h.jsx)(e.code,{children:"PingMode.icmp"})," 更接近真实 ICMP。"]}),"\n"]})]})},"/Ping",{filePath:"pages/Ping.md",timestamp:1789334081e3,pageMap:t.v,frontMatter:{},title:"Latency / Ping / 延迟探测"},"undefined"==typeof RemoteContent?r:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return h}});let h=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=2357)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Ping-ffd9c666caab5ae7.js b/docs/_next/static/chunks/pages/Ping-ffd9c666caab5ae7.js deleted file mode 100644 index 50efbe4..0000000 --- a/docs/_next/static/chunks/pages/Ping-ffd9c666caab5ae7.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[811],{2357:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Ping",function(){return e(4804)}])},4804:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return r}});var h=e(5893),n=e(7812),t=e(7080),l=e(8925);function r(i){return[{value:"Basic / 基础",id:"basic--基础",depth:2},{value:"TCP vs ICMP / TCP 与 ICMP",id:"tcp-vs-icmp--tcp-与-icmp",depth:2}]}s.default=(0,n.c)(function(i){let{toc:s=r(i)}=i,e={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,l.a)(),...i.components};return(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(e.h1,{children:"Latency / Ping / 延迟探测"}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"NetworkDiagnostic.ping()"})," measures round-trip time towards a target host and\r\nreports sent / received counts, packet loss, min/avg/max and jitter."]}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"NetworkDiagnostic.ping()"})," 测量到目标主机的往返时间,并给出发送/接收次数、丢包率、\r\n最小/平均/最大耗时与抖动。"]}),"\n",(0,h.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ping "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" host"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '1.1.1.1'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" count"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" timeout"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Duration"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(seconds"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 2"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" interval"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Duration"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(milliseconds"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 200"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" port"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 443"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,h.jsx)(e.span,{children:" "}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'received : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"received"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"/"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"sent"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'loss : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"packetLoss"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" %'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'min/avg/max: "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"minTime"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" / '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"averageTime"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" / '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"maxTime"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'jitter : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"jitter"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"2"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'samples : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"times"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,h.jsxs)(e.table,{children:[(0,h.jsx)(e.thead,{children:(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.th,{children:"Parameter"}),(0,h.jsx)(e.th,{children:"Default"}),(0,h.jsx)(e.th,{children:"Meaning"})]})}),(0,h.jsxs)(e.tbody,{children:[(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"host"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.pingHost"})}),(0,h.jsx)(e.td,{children:"Target host"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"count"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.pingCount"})}),(0,h.jsx)(e.td,{children:"Number of probes"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"timeout"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.pingTimeout"})}),(0,h.jsx)(e.td,{children:"Per-probe timeout"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"interval"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.pingInterval"})}),(0,h.jsx)(e.td,{children:"Delay between probes"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"port"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.pingPort"})}),(0,h.jsxs)(e.td,{children:["TCP port probed in ",(0,h.jsx)(e.code,{children:"PingMode.tcp"})]})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"mode"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"PingMode.tcp"})}),(0,h.jsxs)(e.td,{children:[(0,h.jsx)(e.code,{children:"PingMode.tcp"})," or ",(0,h.jsx)(e.code,{children:"PingMode.icmp"})]})]})]})]}),"\n",(0,h.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"PingMode.tcp"})," performs a TCP handshake to ",(0,h.jsx)(e.code,{children:"host:port"})," — the portable equivalent\r\nof ICMP and the ",(0,h.jsx)(e.strong,{children:"only mode available on Android/iOS"}),"."]}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"PingMode.tcp"})," 通过 TCP 握手到 ",(0,h.jsx)(e.code,{children:"host:port"})," 测量往返,是移动端",(0,h.jsx)(e.strong,{children:"唯一可用的模式"}),"。"]}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Desktop only — falls back gracefully if the `ping` binary is unavailable."})}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(host"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '1.1.1.1'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", count"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 4"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", mode"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" PingMode"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".icmp);"})]})]})}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"ping.isSuccess"})," is ",(0,h.jsx)(e.code,{children:"true"})," when at least one probe answered; check it before\r\ntrusting the averages."]}),"\n",(0,h.jsxs)(e.p,{children:["至少一次成功响应时 ",(0,h.jsx)(e.code,{children:"isSuccess"})," 为 ",(0,h.jsx)(e.code,{children:"true"}),",读平均值前建议先判断它。"]}),"\n",(0,h.jsxs)(e.blockquote,{children:["\n",(0,h.jsxs)(e.p,{children:["A TCP ping needs a ",(0,h.jsx)(e.strong,{children:"listening port"}),". Probing ",(0,h.jsx)(e.code,{children:"host"})," with ",(0,h.jsx)(e.code,{children:"port: 443"})," fails if\r\nthat host does not accept TCP/443 — that is “filtered”, not “offline”. Use\r\n",(0,h.jsx)(e.code,{children:"mode: PingMode.icmp"})," on desktop to get closer to real ICMP.\r\nTCP 探测需要一个",(0,h.jsx)(e.strong,{children:"在监听的端口"}),"。对不接受 TCP/443 的主机探测 ",(0,h.jsx)(e.code,{children:"port: 443"})," 会失败——\r\n那是“被过滤”,不是“离线”。在桌面上用 ",(0,h.jsx)(e.code,{children:"PingMode.icmp"})," 更接近真实 ICMP。"]}),"\n"]})]})},"/Ping",{filePath:"pages/Ping.md",pageMap:t.v,frontMatter:{},title:"Latency / Ping / 延迟探测"},"undefined"==typeof RemoteContent?r:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return h}});let h=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=2357)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Platform-Support-2f4f155ba23a4f83.js b/docs/_next/static/chunks/pages/Platform-Support-2f4f155ba23a4f83.js deleted file mode 100644 index cb8a108..0000000 --- a/docs/_next/static/chunks/pages/Platform-Support-2f4f155ba23a4f83.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[397],{9502:function(i,e,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Platform-Support",function(){return s(622)}])},622:function(i,e,s){"use strict";s.r(e),s.d(e,{useTOC:function(){return d}});var n=s(5893),t=s(7812),r=s(7080),l=s(8925);function d(i){let e={code:"code",...(0,l.a)()};return[{value:"Capability matrix / 能力矩阵",id:"capability-matrix--能力矩阵",depth:2},{value:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.code,{children:"NetworkCapabilities"})," / 能力查询"]}),id:"networkcapabilities--能力查询",depth:2},{value:"Native details on desktop / 桌面原生详情",id:"native-details-on-desktop--桌面原生详情",depth:2},{value:"Reading native data / 读取原生数据",id:"reading-native-data--读取原生数据",depth:2}]}e.default=(0,t.c)(function(i){let{toc:e=d(i)}=i,s={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,l.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.h1,{children:"Platform Support / 平台支持"}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"zero_network_kit"})," is declared on ",(0,n.jsx)(s.strong,{children:"five"})," plugin platforms: Android, iOS,\r\nmacOS, Windows and Linux. ",(0,n.jsx)(s.strong,{children:"Web is not supported"})," — the Dart services rely on\r\n",(0,n.jsx)(s.code,{children:"dart:io"}),", which does not compile for the web, and browsers have no raw\r\nTCP/UDP sockets."]}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"zero_network_kit"})," 在 ",(0,n.jsx)(s.strong,{children:"五"})," 个插件平台上声明:Android、iOS、macOS、Windows 与\r\nLinux。",(0,n.jsx)(s.strong,{children:"不支持 Web"}),"——Dart 服务依赖 ",(0,n.jsx)(s.code,{children:"dart:io"}),"(无法在 Web 上编译),且浏览器没有\r\n原生 TCP/UDP 套接字。"]}),"\n",(0,n.jsx)(s.h2,{id:e[0].id,children:e[0].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(s.table,{children:[(0,n.jsx)(s.thead,{children:(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.th,{children:"Capability"}),(0,n.jsx)(s.th,{children:"Android / iOS"}),(0,n.jsx)(s.th,{children:"Desktop (macOS / Windows / Linux)"})]})}),(0,n.jsxs)(s.tbody,{children:[(0,n.jsxs)(s.tr,{children:[(0,n.jsxs)(s.td,{children:["Connectivity (",(0,n.jsx)(s.code,{children:"connectivity_plus"}),")"]}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsxs)(s.td,{children:["Local IP / IPv6 (",(0,n.jsx)(s.code,{children:"NetworkInterface"}),")"]}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Native details (SSID / gateway / MAC / VPN)"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"⚠️ see below"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"TCP ping"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsxs)(s.td,{children:["ICMP ping (",(0,n.jsx)(s.code,{children:"Process.run('ping')"}),")"]}),(0,n.jsx)(s.td,{children:"❌"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"HTTP ping"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"DNS system resolver"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"DNS raw UDP"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Port check / scan"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Speed test"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Quality score"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Benchmarks"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]})]})]}),"\n",(0,n.jsx)(s.h2,{id:e[1].id,children:e[1].value}),"\n",(0,n.jsx)(s.p,{children:"Query the host platform before calling, so your UI can hide unsupported cards:"}),"\n",(0,n.jsx)(s.p,{children:"在调用前查询当前平台能力,UI 即可据此隐藏不支持的卡片:"}),"\n",(0,n.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" caps "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".capabilities;"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(caps.platform); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 'android' | 'ios' | 'macos' | 'windows' | 'linux'"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(caps."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"supports"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkCapability"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".nativeDetails)); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// mobile: true, desktop: false"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(caps."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"supports"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkCapability"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".icmpPing)); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// desktop: true, mobile: false"})]})]})}),"\n",(0,n.jsxs)(s.p,{children:["Rules baked into ",(0,n.jsx)(s.code,{children:"NetworkCapabilities.current()"}),":"]}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"nativeDetails"})," is ",(0,n.jsx)(s.strong,{children:"mobile-only"})," (SSID / gateway / MAC / VPN need system APIs)."]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"icmpPing"})," is ",(0,n.jsx)(s.strong,{children:"desktop-only"})," (uses the system ",(0,n.jsx)(s.code,{children:"ping"})," binary)."]}),"\n"]}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"NetworkCapabilities.current()"})," 内置规则:"]}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"nativeDetails"})," ",(0,n.jsx)(s.strong,{children:"仅移动端"}),"(SSID / 网关 / MAC / VPN 需要系统 API)。"]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"icmpPing"})," ",(0,n.jsx)(s.strong,{children:"仅桌面"}),"(使用系统 ",(0,n.jsx)(s.code,{children:"ping"})," 命令)。"]}),"\n"]}),"\n",(0,n.jsx)(s.h2,{id:e[2].id,children:e[2].value}),"\n",(0,n.jsxs)(s.p,{children:["Desktop uses ",(0,n.jsx)(s.strong,{children:"tier A"})," by default: the native layer only reports the platform\r\nversion and an (often empty) details map. IP/IPv6 come from Dart\r\n",(0,n.jsx)(s.code,{children:"NetworkInterface"}),". As a result:"]}),"\n",(0,n.jsxs)(s.p,{children:["桌面默认采用 ",(0,n.jsx)(s.strong,{children:"A 档"}),":原生层只报告平台版本与(通常为空的)详情 map,IP/IPv6 由 Dart\r\n",(0,n.jsx)(s.code,{children:"NetworkInterface"})," 兜底。因此:"]}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsxs)(s.strong,{children:["SSID / signal strength are always ",(0,n.jsx)(s.code,{children:"null"})," on desktop."]}),"\r\n",(0,n.jsxs)(s.strong,{children:["桌面上的 SSID / 信号强度恒为 ",(0,n.jsx)(s.code,{children:"null"}),"。"]})]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"gateway"})," / ",(0,n.jsx)(s.code,{children:"macAddress"})," / ",(0,n.jsx)(s.code,{children:"isVpn"})," are ",(0,n.jsx)(s.code,{children:"null"})," on macOS and Linux.\r\nmacOS 与 Linux 上 ",(0,n.jsx)(s.code,{children:"gateway"})," / ",(0,n.jsx)(s.code,{children:"macAddress"})," / ",(0,n.jsx)(s.code,{children:"isVpn"})," 为 ",(0,n.jsx)(s.code,{children:"null"}),"。"]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.strong,{children:"Windows"})," additionally implements ",(0,n.jsx)(s.code,{children:"GetAdaptersAddresses"}),", so it reports\r\n",(0,n.jsx)(s.code,{children:"gateway"})," / ",(0,n.jsx)(s.code,{children:"macAddress"})," / DNS / ",(0,n.jsx)(s.code,{children:"isVpn"})," (SSID still ",(0,n.jsx)(s.code,{children:"null"}),"). This is a bonus\r\ntier-B fragment kept as-is.\r\n",(0,n.jsx)(s.strong,{children:"Windows"})," 额外实现了 ",(0,n.jsx)(s.code,{children:"GetAdaptersAddresses"}),",因此上报 ",(0,n.jsx)(s.code,{children:"gateway"})," / ",(0,n.jsx)(s.code,{children:"macAddress"})," /\r\nDNS / ",(0,n.jsx)(s.code,{children:"isVpn"}),"(SSID 仍为 ",(0,n.jsx)(s.code,{children:"null"}),")。这是保留的 B 档赠品。"]}),"\n"]}),"\n",(0,n.jsxs)(s.p,{children:["Whatever the platform, a missing permission or an unreachable native call never\r\nthrows — the field simply stays ",(0,n.jsx)(s.code,{children:"null"})," and the rest of the result still arrives."]}),"\n",(0,n.jsxs)(s.p,{children:["无论在哪个平台,缺权限或原生调用不可达都",(0,n.jsx)(s.strong,{children:"不会抛异常"}),"——对应字段保持 ",(0,n.jsx)(s.code,{children:"null"}),",其余\r\n结果照常返回。"]}),"\n",(0,n.jsx)(s.h2,{id:e[3].id,children:e[3].value}),"\n",(0,n.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" version "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ZeroNetworkKit"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"getPlatformVersion"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(version); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// e.g. 'Android 14' / 'iOS 18.0'"})]}),"\n",(0,n.jsx)(s.span,{children:" "}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" details "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ZeroNetworkKit"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"getNativeNetworkDetails"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"if"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (details "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"!="}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" null"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:") {"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(details); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// SSID, BSSID, gateway, MAC, VPN flag, RSSI …"})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})})]})},"/Platform-Support",{filePath:"pages/Platform-Support.md",pageMap:r.v,frontMatter:{},title:"Platform Support / 平台支持"},"undefined"==typeof RemoteContent?d:RemoteContent.useTOC)},7080:function(i,e,s){"use strict";s.d(e,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=9502)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Platform-Support-45a009c029992240.js b/docs/_next/static/chunks/pages/Platform-Support-45a009c029992240.js new file mode 100644 index 0000000..5b2944c --- /dev/null +++ b/docs/_next/static/chunks/pages/Platform-Support-45a009c029992240.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[397],{9502:function(i,e,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Platform-Support",function(){return s(622)}])},622:function(i,e,s){"use strict";s.r(e),s.d(e,{useTOC:function(){return d}});var n=s(5893),t=s(7812),r=s(7080),l=s(8925);function d(i){let e={code:"code",...(0,l.a)()};return[{value:"Capability matrix / 能力矩阵",id:"capability-matrix--能力矩阵",depth:2},{value:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.code,{children:"NetworkCapabilities"})," / 能力查询"]}),id:"networkcapabilities--能力查询",depth:2},{value:"Native details on desktop / 桌面原生详情",id:"native-details-on-desktop--桌面原生详情",depth:2},{value:"Reading native data / 读取原生数据",id:"reading-native-data--读取原生数据",depth:2}]}e.default=(0,t.c)(function(i){let{toc:e=d(i)}=i,s={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,l.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.h1,{children:"Platform Support / 平台支持"}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"zero_network_kit"})," is declared on ",(0,n.jsx)(s.strong,{children:"five"})," plugin platforms: Android, iOS,\nmacOS, Windows and Linux. ",(0,n.jsx)(s.strong,{children:"Web is not supported"})," — the Dart services rely on\n",(0,n.jsx)(s.code,{children:"dart:io"}),", which does not compile for the web, and browsers have no raw\nTCP/UDP sockets."]}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"zero_network_kit"})," 在 ",(0,n.jsx)(s.strong,{children:"五"})," 个插件平台上声明:Android、iOS、macOS、Windows 与\nLinux。",(0,n.jsx)(s.strong,{children:"不支持 Web"}),"——Dart 服务依赖 ",(0,n.jsx)(s.code,{children:"dart:io"}),"(无法在 Web 上编译),且浏览器没有\n原生 TCP/UDP 套接字。"]}),"\n",(0,n.jsx)(s.h2,{id:e[0].id,children:e[0].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(s.table,{children:[(0,n.jsx)(s.thead,{children:(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.th,{children:"Capability"}),(0,n.jsx)(s.th,{children:"Android / iOS"}),(0,n.jsx)(s.th,{children:"Desktop (macOS / Windows / Linux)"})]})}),(0,n.jsxs)(s.tbody,{children:[(0,n.jsxs)(s.tr,{children:[(0,n.jsxs)(s.td,{children:["Connectivity (",(0,n.jsx)(s.code,{children:"connectivity_plus"}),")"]}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsxs)(s.td,{children:["Local IP / IPv6 (",(0,n.jsx)(s.code,{children:"NetworkInterface"}),")"]}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Native details (SSID / gateway / MAC / VPN)"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"⚠️ see below"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"TCP ping"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsxs)(s.td,{children:["ICMP ping (",(0,n.jsx)(s.code,{children:"Process.run('ping')"}),")"]}),(0,n.jsx)(s.td,{children:"❌"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"HTTP ping"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"DNS system resolver"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"DNS raw UDP"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Port check / scan"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Speed test"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Quality score"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Benchmarks"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]})]})]}),"\n",(0,n.jsx)(s.h2,{id:e[1].id,children:e[1].value}),"\n",(0,n.jsx)(s.p,{children:"Query the host platform before calling, so your UI can hide unsupported cards:"}),"\n",(0,n.jsx)(s.p,{children:"在调用前查询当前平台能力,UI 即可据此隐藏不支持的卡片:"}),"\n",(0,n.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" caps "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".capabilities;"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(caps.platform); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 'android' | 'ios' | 'macos' | 'windows' | 'linux'"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(caps."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"supports"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkCapability"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".nativeDetails)); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// mobile: true, desktop: false"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(caps."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"supports"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkCapability"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".icmpPing)); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// desktop: true, mobile: false"})]})]})}),"\n",(0,n.jsxs)(s.p,{children:["Rules baked into ",(0,n.jsx)(s.code,{children:"NetworkCapabilities.current()"}),":"]}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"nativeDetails"})," is ",(0,n.jsx)(s.strong,{children:"mobile-only"})," (SSID / gateway / MAC / VPN need system APIs)."]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"icmpPing"})," is ",(0,n.jsx)(s.strong,{children:"desktop-only"})," (uses the system ",(0,n.jsx)(s.code,{children:"ping"})," binary)."]}),"\n"]}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"NetworkCapabilities.current()"})," 内置规则:"]}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"nativeDetails"})," ",(0,n.jsx)(s.strong,{children:"仅移动端"}),"(SSID / 网关 / MAC / VPN 需要系统 API)。"]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"icmpPing"})," ",(0,n.jsx)(s.strong,{children:"仅桌面"}),"(使用系统 ",(0,n.jsx)(s.code,{children:"ping"})," 命令)。"]}),"\n"]}),"\n",(0,n.jsx)(s.h2,{id:e[2].id,children:e[2].value}),"\n",(0,n.jsxs)(s.p,{children:["Desktop uses ",(0,n.jsx)(s.strong,{children:"tier A"})," by default: the native layer only reports the platform\nversion and an (often empty) details map. IP/IPv6 come from Dart\n",(0,n.jsx)(s.code,{children:"NetworkInterface"}),". As a result:"]}),"\n",(0,n.jsxs)(s.p,{children:["桌面默认采用 ",(0,n.jsx)(s.strong,{children:"A 档"}),":原生层只报告平台版本与(通常为空的)详情 map,IP/IPv6 由 Dart\n",(0,n.jsx)(s.code,{children:"NetworkInterface"})," 兜底。因此:"]}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsxs)(s.strong,{children:["SSID / signal strength are always ",(0,n.jsx)(s.code,{children:"null"})," on desktop."]}),"\n",(0,n.jsxs)(s.strong,{children:["桌面上的 SSID / 信号强度恒为 ",(0,n.jsx)(s.code,{children:"null"}),"。"]})]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"gateway"})," / ",(0,n.jsx)(s.code,{children:"macAddress"})," / ",(0,n.jsx)(s.code,{children:"isVpn"})," are ",(0,n.jsx)(s.code,{children:"null"})," on macOS and Linux.\nmacOS 与 Linux 上 ",(0,n.jsx)(s.code,{children:"gateway"})," / ",(0,n.jsx)(s.code,{children:"macAddress"})," / ",(0,n.jsx)(s.code,{children:"isVpn"})," 为 ",(0,n.jsx)(s.code,{children:"null"}),"。"]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.strong,{children:"Windows"})," additionally implements ",(0,n.jsx)(s.code,{children:"GetAdaptersAddresses"}),", so it reports\n",(0,n.jsx)(s.code,{children:"gateway"})," / ",(0,n.jsx)(s.code,{children:"macAddress"})," / DNS / ",(0,n.jsx)(s.code,{children:"isVpn"})," (SSID still ",(0,n.jsx)(s.code,{children:"null"}),"). This is a bonus\ntier-B fragment kept as-is.\n",(0,n.jsx)(s.strong,{children:"Windows"})," 额外实现了 ",(0,n.jsx)(s.code,{children:"GetAdaptersAddresses"}),",因此上报 ",(0,n.jsx)(s.code,{children:"gateway"})," / ",(0,n.jsx)(s.code,{children:"macAddress"})," /\nDNS / ",(0,n.jsx)(s.code,{children:"isVpn"}),"(SSID 仍为 ",(0,n.jsx)(s.code,{children:"null"}),")。这是保留的 B 档赠品。"]}),"\n"]}),"\n",(0,n.jsxs)(s.p,{children:["Whatever the platform, a missing permission or an unreachable native call never\nthrows — the field simply stays ",(0,n.jsx)(s.code,{children:"null"})," and the rest of the result still arrives."]}),"\n",(0,n.jsxs)(s.p,{children:["无论在哪个平台,缺权限或原生调用不可达都",(0,n.jsx)(s.strong,{children:"不会抛异常"}),"——对应字段保持 ",(0,n.jsx)(s.code,{children:"null"}),",其余\n结果照常返回。"]}),"\n",(0,n.jsx)(s.h2,{id:e[3].id,children:e[3].value}),"\n",(0,n.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" version "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ZeroNetworkKit"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"getPlatformVersion"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(version); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// e.g. 'Android 14' / 'iOS 18.0'"})]}),"\n",(0,n.jsx)(s.span,{children:" "}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" details "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ZeroNetworkKit"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"getNativeNetworkDetails"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"if"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (details "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"!="}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" null"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:") {"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(details); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// SSID, BSSID, gateway, MAC, VPN flag, RSSI …"})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})})]})},"/Platform-Support",{filePath:"pages/Platform-Support.md",timestamp:1789334081e3,pageMap:r.v,frontMatter:{},title:"Platform Support / 平台支持"},"undefined"==typeof RemoteContent?d:RemoteContent.useTOC)},7080:function(i,e,s){"use strict";s.d(e,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=9502)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Ports-325a60377e02f441.js b/docs/_next/static/chunks/pages/Ports-325a60377e02f441.js deleted file mode 100644 index b1dd86e..0000000 --- a/docs/_next/static/chunks/pages/Ports-325a60377e02f441.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[243],{5323:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Ports",function(){return e(7381)}])},7381:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return t}});var h=e(5893),n=e(7812),l=e(7080),r=e(8925);function t(i){return[{value:"Single port / 单端口",id:"single-port--单端口",depth:2},{value:"Bulk scan / 批量扫描",id:"bulk-scan--批量扫描",depth:2}]}s.default=(0,n.c)(function(i){let{toc:s=t(i)}=i,e={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,r.a)(),...i.components};return(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(e.h1,{children:"Ports / 端口检测"}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"checkPort()"})," returns a full ",(0,h.jsx)(e.code,{children:"PortCheckResult"})," for one port; ",(0,h.jsx)(e.code,{children:"isPortOpen()"})," is the\r\nplain boolean convenience; ",(0,h.jsx)(e.code,{children:"scanPorts()"})," runs many ports concurrently with\r\nbounded in-flight connections."]}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"checkPort()"})," 返回单个端口的完整 ",(0,h.jsx)(e.code,{children:"PortCheckResult"}),";",(0,h.jsx)(e.code,{children:"isPortOpen()"})," 是便捷的布尔版;\r\n",(0,h.jsx)(e.code,{children:"scanPorts()"})," 以有界并发批量扫描多个端口。"]}),"\n",(0,h.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Boolean convenience / 便捷布尔版"})}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" open "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"isPortOpen"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" host"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'example.com'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" port"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 443"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" timeout"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Duration"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(seconds"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 3"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(open "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"?"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'HTTPS reachable'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" :"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'HTTPS unreachable'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsx)(e.span,{children:" "}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Full result with RTT and error message / 含 RTT 与错误信息的完整结果"})}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" result "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"checkPort"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(host"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'example.com'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", port"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 443"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'open="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"result"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"isOpen"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" rtt="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"result"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"responseTimeMs"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'err="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"result"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"errorMessage"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})]})}),"\n",(0,h.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" scan "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"scanPorts"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" host"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'example.com'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ports"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" <"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"int"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:">"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"["}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"22"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"80"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"443"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"8080"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"8443"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" concurrency"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 8"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,h.jsx)(e.span,{children:" "}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"for"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" r "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"in"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" scan) {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"host"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"port"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"isOpen"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ? "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:'"open"'}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:'"closed"'}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"responseTimeMs"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"errorMessage"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ?? "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:'""'}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,h.jsxs)(e.table,{children:[(0,h.jsx)(e.thead,{children:(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.th,{children:"Parameter"}),(0,h.jsx)(e.th,{children:"Default"}),(0,h.jsx)(e.th,{children:"Meaning"})]})}),(0,h.jsxs)(e.tbody,{children:[(0,h.jsxs)(e.tr,{children:[(0,h.jsxs)(e.td,{children:[(0,h.jsx)(e.code,{children:"ports"})," (",(0,h.jsx)(e.code,{children:"scanPorts"}),")"]}),(0,h.jsxs)(e.td,{children:[(0,h.jsx)(e.code,{children:"config.probePorts"})," (",(0,h.jsx)(e.code,{children:"[80, 443]"}),")"]}),(0,h.jsx)(e.td,{children:"Ports to probe"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"concurrency"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"12"})}),(0,h.jsx)(e.td,{children:"Max in-flight connections"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"timeout"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.portCheckTimeout"})}),(0,h.jsx)(e.td,{children:"Timeout per port"})]})]})]}),"\n",(0,h.jsxs)(e.blockquote,{children:["\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"checkPort()"})," returns a ",(0,h.jsx)(e.strong,{children:(0,h.jsx)(e.code,{children:"PortCheckResult"})})," (with ",(0,h.jsx)(e.code,{children:"isOpen"}),", ",(0,h.jsx)(e.code,{children:"responseTimeMs"}),"\r\nand ",(0,h.jsx)(e.code,{children:"errorMessage"}),"); use ",(0,h.jsx)(e.code,{children:"isPortOpen()"})," for a plain boolean. When you need the\r\nround-trip time or the failure reason for a single port, call ",(0,h.jsx)(e.code,{children:"checkPort()"}),"\r\ndirectly or pass a one-element list to ",(0,h.jsx)(e.code,{children:"scanPorts()"}),":\r\n",(0,h.jsx)(e.code,{children:"scanPorts(host: 'example.com', ports: [443]).first"}),".\r\n",(0,h.jsx)(e.code,{children:"checkPort()"})," 返回 ",(0,h.jsx)(e.strong,{children:(0,h.jsx)(e.code,{children:"PortCheckResult"})}),"(含 ",(0,h.jsx)(e.code,{children:"isOpen"}),"、",(0,h.jsx)(e.code,{children:"responseTimeMs"}),"、\r\n",(0,h.jsx)(e.code,{children:"errorMessage"}),");单端口布尔诉求请用 ",(0,h.jsx)(e.code,{children:"isPortOpen()"}),"。需要 RTT 或失败原因时可直接\r\n调用 ",(0,h.jsx)(e.code,{children:"checkPort()"}),",或给 ",(0,h.jsx)(e.code,{children:"scanPorts(..., ports: [443])"})," 取单条结果。"]}),"\n"]})]})},"/Ports",{filePath:"pages/Ports.md",pageMap:l.v,frontMatter:{},title:"Ports / 端口检测"},"undefined"==typeof RemoteContent?t:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return h}});let h=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=5323)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Ports-743ec1523389b840.js b/docs/_next/static/chunks/pages/Ports-743ec1523389b840.js new file mode 100644 index 0000000..0c629b5 --- /dev/null +++ b/docs/_next/static/chunks/pages/Ports-743ec1523389b840.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[243],{5323:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Ports",function(){return e(7381)}])},7381:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return r}});var h=e(5893),n=e(7812),l=e(7080),t=e(8925);function r(i){return[{value:"Single port / 单端口",id:"single-port--单端口",depth:2},{value:"Bulk scan / 批量扫描",id:"bulk-scan--批量扫描",depth:2}]}s.default=(0,n.c)(function(i){let{toc:s=r(i)}=i,e={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,t.a)(),...i.components};return(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(e.h1,{children:"Ports / 端口检测"}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"checkPort()"})," returns a full ",(0,h.jsx)(e.code,{children:"PortCheckResult"})," for one port; ",(0,h.jsx)(e.code,{children:"isPortOpen()"})," is the\nplain boolean convenience; ",(0,h.jsx)(e.code,{children:"scanPorts()"})," runs many ports concurrently with\nbounded in-flight connections."]}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"checkPort()"})," 返回单个端口的完整 ",(0,h.jsx)(e.code,{children:"PortCheckResult"}),";",(0,h.jsx)(e.code,{children:"isPortOpen()"})," 是便捷的布尔版;\n",(0,h.jsx)(e.code,{children:"scanPorts()"})," 以有界并发批量扫描多个端口。"]}),"\n",(0,h.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Boolean convenience / 便捷布尔版"})}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" open "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"isPortOpen"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" host"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'example.com'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" port"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 443"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" timeout"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Duration"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(seconds"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 3"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(open "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"?"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'HTTPS reachable'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" :"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'HTTPS unreachable'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsx)(e.span,{children:" "}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Full result with RTT and error message / 含 RTT 与错误信息的完整结果"})}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" result "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"checkPort"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(host"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'example.com'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", port"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 443"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'open="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"result"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"isOpen"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" rtt="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"result"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"responseTimeMs"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'err="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"result"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"errorMessage"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})]})}),"\n",(0,h.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" scan "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"scanPorts"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" host"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'example.com'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ports"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" <"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"int"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:">"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"["}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"22"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"80"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"443"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"8080"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"8443"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" concurrency"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 8"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,h.jsx)(e.span,{children:" "}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"for"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" r "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"in"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" scan) {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"host"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"port"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"isOpen"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ? "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:'"open"'}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:'"closed"'}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"responseTimeMs"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"r"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"errorMessage"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ?? "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:'""'}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,h.jsxs)(e.table,{children:[(0,h.jsx)(e.thead,{children:(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.th,{children:"Parameter"}),(0,h.jsx)(e.th,{children:"Default"}),(0,h.jsx)(e.th,{children:"Meaning"})]})}),(0,h.jsxs)(e.tbody,{children:[(0,h.jsxs)(e.tr,{children:[(0,h.jsxs)(e.td,{children:[(0,h.jsx)(e.code,{children:"ports"})," (",(0,h.jsx)(e.code,{children:"scanPorts"}),")"]}),(0,h.jsxs)(e.td,{children:[(0,h.jsx)(e.code,{children:"config.probePorts"})," (",(0,h.jsx)(e.code,{children:"[80, 443]"}),")"]}),(0,h.jsx)(e.td,{children:"Ports to probe"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"concurrency"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"12"})}),(0,h.jsx)(e.td,{children:"Max in-flight connections"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"timeout"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.portCheckTimeout"})}),(0,h.jsx)(e.td,{children:"Timeout per port"})]})]})]}),"\n",(0,h.jsxs)(e.blockquote,{children:["\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"checkPort()"})," returns a ",(0,h.jsx)(e.strong,{children:(0,h.jsx)(e.code,{children:"PortCheckResult"})})," (with ",(0,h.jsx)(e.code,{children:"isOpen"}),", ",(0,h.jsx)(e.code,{children:"responseTimeMs"}),"\nand ",(0,h.jsx)(e.code,{children:"errorMessage"}),"); use ",(0,h.jsx)(e.code,{children:"isPortOpen()"})," for a plain boolean. When you need the\nround-trip time or the failure reason for a single port, call ",(0,h.jsx)(e.code,{children:"checkPort()"}),"\ndirectly or pass a one-element list to ",(0,h.jsx)(e.code,{children:"scanPorts()"}),":\n",(0,h.jsx)(e.code,{children:"scanPorts(host: 'example.com', ports: [443]).first"}),".\n",(0,h.jsx)(e.code,{children:"checkPort()"})," 返回 ",(0,h.jsx)(e.strong,{children:(0,h.jsx)(e.code,{children:"PortCheckResult"})}),"(含 ",(0,h.jsx)(e.code,{children:"isOpen"}),"、",(0,h.jsx)(e.code,{children:"responseTimeMs"}),"、\n",(0,h.jsx)(e.code,{children:"errorMessage"}),");单端口布尔诉求请用 ",(0,h.jsx)(e.code,{children:"isPortOpen()"}),"。需要 RTT 或失败原因时可直接\n调用 ",(0,h.jsx)(e.code,{children:"checkPort()"}),",或给 ",(0,h.jsx)(e.code,{children:"scanPorts(..., ports: [443])"})," 取单条结果。"]}),"\n"]})]})},"/Ports",{filePath:"pages/Ports.md",timestamp:1789334081e3,pageMap:l.v,frontMatter:{},title:"Ports / 端口检测"},"undefined"==typeof RemoteContent?r:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return h}});let h=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=5323)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Quality-84301e2f3a2871a5.js b/docs/_next/static/chunks/pages/Quality-84301e2f3a2871a5.js deleted file mode 100644 index 8ed1702..0000000 --- a/docs/_next/static/chunks/pages/Quality-84301e2f3a2871a5.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[293],{1569:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Quality",function(){return e(6695)}])},6695:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return r}});var n=e(5893),h=e(7812),l=e(7080),t=e(8925);function r(i){return[{value:"Basic / 基础",id:"basic--基础",depth:2},{value:"Lightweight variant / 轻量变体",id:"lightweight-variant--轻量变体",depth:3},{value:"Level thresholds / 等级阈值",id:"level-thresholds--等级阈值",depth:2},{value:"Weights / 权重",id:"weights--权重",depth:2},{value:"Pure function / 纯函数",id:"pure-function--纯函数",depth:2}]}s.default=(0,h.c)(function(i){let{toc:s=r(i)}=i,e={code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",span:"span",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,t.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{children:"Quality Score / 质量评分"}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"NetworkDiagnostic.evaluateQuality()"})," returns a weighted 0–100 score plus a\r\nlevel and human-readable suggestions, computed over whatever metrics are\r\navailable."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"NetworkDiagnostic.evaluateQuality()"})," 返回一个加权 0–100 分,附带等级与可读建议,\r\n它基于当前可用的各项指标计算得出。"]}),"\n",(0,n.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" quality "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"evaluateQuality"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includePing"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeDns"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeSpeedTest"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeUpload"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"quality"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"score"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"/100 — "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"quality"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"level"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"label"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"quality.metrics."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"forEach"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"((metric, value) {"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"' "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"$"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"metric"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" = "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"value"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"2"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"});"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"for"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" suggestion "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"in"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" quality.suggestions) {"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'• "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"$"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"suggestion"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"Parameter"}),(0,n.jsx)(e.th,{children:"Default"}),(0,n.jsx)(e.th,{children:"Meaning"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includePing"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"true"})}),(0,n.jsx)(e.td,{children:"Sample latency / jitter / loss"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includeDns"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"true"})}),(0,n.jsx)(e.td,{children:"Sample DNS latency"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includeSpeedTest"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"true"})}),(0,n.jsx)(e.td,{children:"Sample download / upload (heavy)"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includeUpload"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"true"})}),(0,n.jsx)(e.td,{children:"Include the upload metric"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"pingHost"})," / ",(0,n.jsx)(e.code,{children:"pingCount"})]}),(0,n.jsx)(e.td,{children:"from config"}),(0,n.jsx)(e.td,{children:"Latency target"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"dnsDomain"})," / ",(0,n.jsx)(e.code,{children:"dnsServers"})]}),(0,n.jsx)(e.td,{children:"from config"}),(0,n.jsx)(e.td,{children:"DNS target"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"downloadUrl"})," / ",(0,n.jsx)(e.code,{children:"uploadUrl"})]}),(0,n.jsx)(e.td,{children:"from config"}),(0,n.jsx)(e.td,{children:"Bandwidth endpoints"})]})]})]}),"\n",(0,n.jsx)(e.h3,{id:s[1].id,children:s[1].value}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsx)(e.code,{children:(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" quality "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"evaluateQuality"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(includeSpeedTest"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" false"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})})}),"\n",(0,n.jsx)(e.h2,{id:s[2].id,children:s[2].value}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"≥90"})," excellent \xb7 ",(0,n.jsx)(e.code,{children:"≥75"})," good \xb7 ",(0,n.jsx)(e.code,{children:"≥60"})," fair \xb7 ",(0,n.jsx)(e.code,{children:"≥40"})," poor \xb7 otherwise bad\r\n(",(0,n.jsx)(e.code,{children:"NetworkQualityLevel.fromScore"}),")."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"≥90"})," 极佳 \xb7 ",(0,n.jsx)(e.code,{children:"≥75"})," 良好 \xb7 ",(0,n.jsx)(e.code,{children:"≥60"})," 一般 \xb7 ",(0,n.jsx)(e.code,{children:"≥40"})," 较差 \xb7 其余为极差。"]}),"\n",(0,n.jsx)(e.h2,{id:s[3].id,children:s[3].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"Metric"}),(0,n.jsx)(e.th,{children:"Weight"}),(0,n.jsx)(e.th,{children:"Source"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"latency"})}),(0,n.jsx)(e.td,{children:"0.25"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"PingResult.averageTime"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"jitter"})}),(0,n.jsx)(e.td,{children:"0.10"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"PingResult.jitter"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"packetLoss"})}),(0,n.jsx)(e.td,{children:"0.15"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"PingResult.packetLoss"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"download"})}),(0,n.jsx)(e.td,{children:"0.25"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"SpeedTestResult.downloadSpeed"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"upload"})}),(0,n.jsx)(e.td,{children:"0.15"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"SpeedTestResult.uploadSpeed"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"dns"})}),(0,n.jsx)(e.td,{children:"0.10"}),(0,n.jsxs)(e.td,{children:["mean of successful ",(0,n.jsx)(e.code,{children:"DnsTestResult.responseTimeMs"})]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"signalStrength"})}),(0,n.jsx)(e.td,{children:"0.10"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkConnectionInfo.signalStrength"})})]})]})]}),"\n",(0,n.jsx)(e.h2,{id:s[4].id,children:s[4].value}),"\n",(0,n.jsx)(e.p,{children:"If you already have the metrics, skip the network entirely:"}),"\n",(0,n.jsx)(e.p,{children:"如果你已有指标,可完全跳过网络:"}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" score "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkQualityEvaluator"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"evaluate"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" latency"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 42"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", jitter"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 6"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", packetLoss"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 0"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" download"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 88.4"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", upload"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 12.1"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", dns"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 25"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", signalStrength"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" -"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"55"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" targets"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" QualityTargets"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"score"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"score"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" → "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"score"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"level"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"label"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})]})}),"\n",(0,n.jsxs)(e.p,{children:["Tune the ideal values globally through ",(0,n.jsx)(e.code,{children:"NetworkDiagnosticConfig(qualityTargets: ...)"}),".\r\n调整理想值请通过 ",(0,n.jsx)(e.code,{children:"NetworkDiagnosticConfig(qualityTargets: ...)"})," 全局设置。"]})]})},"/Quality",{filePath:"pages/Quality.md",pageMap:l.v,frontMatter:{},title:"Quality Score / 质量评分"},"undefined"==typeof RemoteContent?r:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=1569)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Quality-ac653fb19750eaeb.js b/docs/_next/static/chunks/pages/Quality-ac653fb19750eaeb.js new file mode 100644 index 0000000..f01dab4 --- /dev/null +++ b/docs/_next/static/chunks/pages/Quality-ac653fb19750eaeb.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[293],{1569:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Quality",function(){return e(6695)}])},6695:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return r}});var n=e(5893),h=e(7812),l=e(7080),t=e(8925);function r(i){return[{value:"Basic / 基础",id:"basic--基础",depth:2},{value:"Lightweight variant / 轻量变体",id:"lightweight-variant--轻量变体",depth:3},{value:"Level thresholds / 等级阈值",id:"level-thresholds--等级阈值",depth:2},{value:"Weights / 权重",id:"weights--权重",depth:2},{value:"Pure function / 纯函数",id:"pure-function--纯函数",depth:2}]}s.default=(0,h.c)(function(i){let{toc:s=r(i)}=i,e={code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",span:"span",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,t.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{children:"Quality Score / 质量评分"}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"NetworkDiagnostic.evaluateQuality()"})," returns a weighted 0–100 score plus a\nlevel and human-readable suggestions, computed over whatever metrics are\navailable."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"NetworkDiagnostic.evaluateQuality()"})," 返回一个加权 0–100 分,附带等级与可读建议,\n它基于当前可用的各项指标计算得出。"]}),"\n",(0,n.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" quality "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"evaluateQuality"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includePing"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeDns"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeSpeedTest"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeUpload"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"quality"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"score"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"/100 — "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"quality"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"level"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"label"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"quality.metrics."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"forEach"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"((metric, value) {"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"' "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"$"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"metric"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" = "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"value"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"2"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"});"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"for"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" suggestion "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"in"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" quality.suggestions) {"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'• "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"$"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"suggestion"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"Parameter"}),(0,n.jsx)(e.th,{children:"Default"}),(0,n.jsx)(e.th,{children:"Meaning"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includePing"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"true"})}),(0,n.jsx)(e.td,{children:"Sample latency / jitter / loss"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includeDns"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"true"})}),(0,n.jsx)(e.td,{children:"Sample DNS latency"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includeSpeedTest"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"true"})}),(0,n.jsx)(e.td,{children:"Sample download / upload (heavy)"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"includeUpload"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"true"})}),(0,n.jsx)(e.td,{children:"Include the upload metric"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"pingHost"})," / ",(0,n.jsx)(e.code,{children:"pingCount"})]}),(0,n.jsx)(e.td,{children:"from config"}),(0,n.jsx)(e.td,{children:"Latency target"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"dnsDomain"})," / ",(0,n.jsx)(e.code,{children:"dnsServers"})]}),(0,n.jsx)(e.td,{children:"from config"}),(0,n.jsx)(e.td,{children:"DNS target"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"downloadUrl"})," / ",(0,n.jsx)(e.code,{children:"uploadUrl"})]}),(0,n.jsx)(e.td,{children:"from config"}),(0,n.jsx)(e.td,{children:"Bandwidth endpoints"})]})]})]}),"\n",(0,n.jsx)(e.h3,{id:s[1].id,children:s[1].value}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsx)(e.code,{children:(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" quality "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"evaluateQuality"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(includeSpeedTest"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" false"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})})}),"\n",(0,n.jsx)(e.h2,{id:s[2].id,children:s[2].value}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"≥90"})," excellent \xb7 ",(0,n.jsx)(e.code,{children:"≥75"})," good \xb7 ",(0,n.jsx)(e.code,{children:"≥60"})," fair \xb7 ",(0,n.jsx)(e.code,{children:"≥40"})," poor \xb7 otherwise bad\n(",(0,n.jsx)(e.code,{children:"NetworkQualityLevel.fromScore"}),")."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"≥90"})," 极佳 \xb7 ",(0,n.jsx)(e.code,{children:"≥75"})," 良好 \xb7 ",(0,n.jsx)(e.code,{children:"≥60"})," 一般 \xb7 ",(0,n.jsx)(e.code,{children:"≥40"})," 较差 \xb7 其余为极差。"]}),"\n",(0,n.jsx)(e.h2,{id:s[3].id,children:s[3].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"Metric"}),(0,n.jsx)(e.th,{children:"Weight"}),(0,n.jsx)(e.th,{children:"Source"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"latency"})}),(0,n.jsx)(e.td,{children:"0.25"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"PingResult.averageTime"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"jitter"})}),(0,n.jsx)(e.td,{children:"0.10"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"PingResult.jitter"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"packetLoss"})}),(0,n.jsx)(e.td,{children:"0.15"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"PingResult.packetLoss"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"download"})}),(0,n.jsx)(e.td,{children:"0.25"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"SpeedTestResult.downloadSpeed"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"upload"})}),(0,n.jsx)(e.td,{children:"0.15"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"SpeedTestResult.uploadSpeed"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"dns"})}),(0,n.jsx)(e.td,{children:"0.10"}),(0,n.jsxs)(e.td,{children:["mean of successful ",(0,n.jsx)(e.code,{children:"DnsTestResult.responseTimeMs"})]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"signalStrength"})}),(0,n.jsx)(e.td,{children:"0.10"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkConnectionInfo.signalStrength"})})]})]})]}),"\n",(0,n.jsx)(e.h2,{id:s[4].id,children:s[4].value}),"\n",(0,n.jsx)(e.p,{children:"If you already have the metrics, skip the network entirely:"}),"\n",(0,n.jsx)(e.p,{children:"如果你已有指标,可完全跳过网络:"}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" score "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkQualityEvaluator"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"evaluate"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" latency"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 42"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", jitter"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 6"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", packetLoss"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 0"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" download"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 88.4"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", upload"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 12.1"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", dns"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 25"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", signalStrength"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" -"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"55"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" targets"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" QualityTargets"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"score"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"score"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" → "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"score"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"level"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"label"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})]})}),"\n",(0,n.jsxs)(e.p,{children:["Tune the ideal values globally through ",(0,n.jsx)(e.code,{children:"NetworkDiagnosticConfig(qualityTargets: ...)"}),".\n调整理想值请通过 ",(0,n.jsx)(e.code,{children:"NetworkDiagnosticConfig(qualityTargets: ...)"})," 全局设置。"]})]})},"/Quality",{filePath:"pages/Quality.md",timestamp:1789334081e3,pageMap:l.v,frontMatter:{},title:"Quality Score / 质量评分"},"undefined"==typeof RemoteContent?r:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=1569)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Speed-Test-03d333b534600839.js b/docs/_next/static/chunks/pages/Speed-Test-03d333b534600839.js new file mode 100644 index 0000000..263558b --- /dev/null +++ b/docs/_next/static/chunks/pages/Speed-Test-03d333b534600839.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[375],{7003:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Speed-Test",function(){return e(9797)}])},9797:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return r}});var h=e(5893),n=e(7812),l=e(7080),t=e(8925);function r(i){return[{value:"Basic / 基础",id:"basic--基础",depth:2},{value:"Fast, low-traffic variant / 轻量低流量变体",id:"fast-low-traffic-variant--轻量低流量变体",depth:2}]}s.default=(0,n.c)(function(i){let{toc:s=r(i)}=i,e={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",span:"span",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,t.a)(),...i.components};return(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(e.h1,{children:"Speed Test / 测速"}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"NetworkDiagnostic.runSpeedTest()"})," measures download and upload throughput and\nsamples latency during the run, reporting progress through ",(0,h.jsx)(e.code,{children:"onProgress"}),"."]}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"NetworkDiagnostic.runSpeedTest()"})," 测量下载与上传吞吐量,并在过程中采样延迟,通过\n",(0,h.jsx)(e.code,{children:"onProgress"})," 汇报进度。"]}),"\n",(0,h.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" speed "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"runSpeedTest"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeUpload"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includePing"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" onProgress"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (progress) {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"progress"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"phase"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"name"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:": '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"progress"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"speedMbps"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" Mbps '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"progress"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"bytes"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" bytes, "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"progress"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"elapsed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"inMilliseconds"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms)'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" },"})}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,h.jsx)(e.span,{children:" "}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'download : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"speed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"downloadSpeed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"2"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" Mbps'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'upload : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"speed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"uploadSpeed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"2"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" Mbps'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'ping : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"speed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'jitter : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"speed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"jitter"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"2"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'loss : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"speed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"packetLoss"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" %'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'server : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"speed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"server"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'duration : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"speed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"duration"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"inMilliseconds"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,h.jsxs)(e.table,{children:[(0,h.jsx)(e.thead,{children:(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.th,{children:"Parameter"}),(0,h.jsx)(e.th,{children:"Default"}),(0,h.jsx)(e.th,{children:"Meaning"})]})}),(0,h.jsxs)(e.tbody,{children:[(0,h.jsxs)(e.tr,{children:[(0,h.jsxs)(e.td,{children:[(0,h.jsx)(e.code,{children:"downloadUrl"})," / ",(0,h.jsx)(e.code,{children:"uploadUrl"})]}),(0,h.jsx)(e.td,{children:"from config"}),(0,h.jsx)(e.td,{children:"Endpoints used"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"timeout"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.speedTestTimeout"})}),(0,h.jsx)(e.td,{children:"Per-request timeout"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"maxDuration"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.speedTestMaxDuration"})}),(0,h.jsx)(e.td,{children:"Sampling window per phase"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"uploadPayloadBytes"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.uploadPayloadBytes"})}),(0,h.jsx)(e.td,{children:"Upload size"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsxs)(e.td,{children:[(0,h.jsx)(e.code,{children:"pingHost"})," / ",(0,h.jsx)(e.code,{children:"pingCount"})]}),(0,h.jsx)(e.td,{children:"from config"}),(0,h.jsx)(e.td,{children:"Latency sampled during the test"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"includeUpload"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"true"})}),(0,h.jsx)(e.td,{children:"Skip the upload phase"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"includePing"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"true"})}),(0,h.jsx)(e.td,{children:"Skip the latency sample"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"onProgress"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"null"})}),(0,h.jsx)(e.td,{children:"Called repeatedly during both phases"})]})]})]}),"\n",(0,h.jsxs)(e.p,{children:["Progress phases: ",(0,h.jsx)(e.code,{children:"SpeedTestPhase.download"})," → ",(0,h.jsx)(e.code,{children:"SpeedTestPhase.upload"})," →\n",(0,h.jsx)(e.code,{children:"SpeedTestPhase.completed"}),"."]}),"\n",(0,h.jsxs)(e.p,{children:["进度阶段依次为 ",(0,h.jsx)(e.code,{children:"download"})," → ",(0,h.jsx)(e.code,{children:"upload"})," → ",(0,h.jsx)(e.code,{children:"completed"}),"。"]}),"\n",(0,h.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" quick "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"runSpeedTest"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeUpload"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" false"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includePing"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" false"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" maxDuration"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Duration"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(seconds"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})})]})}),"\n",(0,h.jsxs)(e.blockquote,{children:["\n",(0,h.jsxs)(e.p,{children:["The default endpoints point at Cloudflare’s public speed service and move real\ntraffic (≈25 MB download by default). Ask for consent before running it on a\nmetered connection, and override ",(0,h.jsx)(e.code,{children:"downloadUrl"})," / ",(0,h.jsx)(e.code,{children:"uploadUrl"})," for production.\n默认端点指向 Cloudflare 公共服务并会产生真实流量(默认下载约 25 MB)。在按量计费\n网络上运行前请征得同意,并为生产环境替换 ",(0,h.jsx)(e.code,{children:"downloadUrl"})," / ",(0,h.jsx)(e.code,{children:"uploadUrl"}),"。"]}),"\n"]})]})},"/Speed-Test",{filePath:"pages/Speed-Test.md",timestamp:1789334081e3,pageMap:l.v,frontMatter:{},title:"Speed Test / 测速"},"undefined"==typeof RemoteContent?r:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return h}});let h=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=7003)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Speed-Test-f92135729d9500cb.js b/docs/_next/static/chunks/pages/Speed-Test-f92135729d9500cb.js deleted file mode 100644 index 982e50e..0000000 --- a/docs/_next/static/chunks/pages/Speed-Test-f92135729d9500cb.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[375],{7003:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Speed-Test",function(){return e(9797)}])},9797:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return r}});var h=e(5893),n=e(7812),l=e(7080),t=e(8925);function r(i){return[{value:"Basic / 基础",id:"basic--基础",depth:2},{value:"Fast, low-traffic variant / 轻量低流量变体",id:"fast-low-traffic-variant--轻量低流量变体",depth:2}]}s.default=(0,n.c)(function(i){let{toc:s=r(i)}=i,e={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",span:"span",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,t.a)(),...i.components};return(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(e.h1,{children:"Speed Test / 测速"}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"NetworkDiagnostic.runSpeedTest()"})," measures download and upload throughput and\r\nsamples latency during the run, reporting progress through ",(0,h.jsx)(e.code,{children:"onProgress"}),"."]}),"\n",(0,h.jsxs)(e.p,{children:[(0,h.jsx)(e.code,{children:"NetworkDiagnostic.runSpeedTest()"})," 测量下载与上传吞吐量,并在过程中采样延迟,通过\r\n",(0,h.jsx)(e.code,{children:"onProgress"})," 汇报进度。"]}),"\n",(0,h.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" speed "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"runSpeedTest"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeUpload"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includePing"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" true"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" onProgress"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (progress) {"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"progress"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"phase"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"name"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:": '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"progress"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"speedMbps"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" Mbps '"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"progress"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"bytes"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" bytes, "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"progress"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"elapsed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"inMilliseconds"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms)'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" },"})}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,h.jsx)(e.span,{children:" "}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'download : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"speed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"downloadSpeed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"2"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" Mbps'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'upload : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"speed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"uploadSpeed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"2"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" Mbps'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'ping : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"speed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ping"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'jitter : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"speed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"jitter"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"2"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'loss : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"speed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"packetLoss"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toStringAsFixed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"1"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:")}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" %'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'server : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"speed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"server"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'duration : "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"${"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"speed"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"duration"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"inMilliseconds"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"}"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" ms'"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,h.jsxs)(e.table,{children:[(0,h.jsx)(e.thead,{children:(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.th,{children:"Parameter"}),(0,h.jsx)(e.th,{children:"Default"}),(0,h.jsx)(e.th,{children:"Meaning"})]})}),(0,h.jsxs)(e.tbody,{children:[(0,h.jsxs)(e.tr,{children:[(0,h.jsxs)(e.td,{children:[(0,h.jsx)(e.code,{children:"downloadUrl"})," / ",(0,h.jsx)(e.code,{children:"uploadUrl"})]}),(0,h.jsx)(e.td,{children:"from config"}),(0,h.jsx)(e.td,{children:"Endpoints used"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"timeout"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.speedTestTimeout"})}),(0,h.jsx)(e.td,{children:"Per-request timeout"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"maxDuration"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.speedTestMaxDuration"})}),(0,h.jsx)(e.td,{children:"Sampling window per phase"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"uploadPayloadBytes"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"config.uploadPayloadBytes"})}),(0,h.jsx)(e.td,{children:"Upload size"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsxs)(e.td,{children:[(0,h.jsx)(e.code,{children:"pingHost"})," / ",(0,h.jsx)(e.code,{children:"pingCount"})]}),(0,h.jsx)(e.td,{children:"from config"}),(0,h.jsx)(e.td,{children:"Latency sampled during the test"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"includeUpload"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"true"})}),(0,h.jsx)(e.td,{children:"Skip the upload phase"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"includePing"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"true"})}),(0,h.jsx)(e.td,{children:"Skip the latency sample"})]}),(0,h.jsxs)(e.tr,{children:[(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"onProgress"})}),(0,h.jsx)(e.td,{children:(0,h.jsx)(e.code,{children:"null"})}),(0,h.jsx)(e.td,{children:"Called repeatedly during both phases"})]})]})]}),"\n",(0,h.jsxs)(e.p,{children:["Progress phases: ",(0,h.jsx)(e.code,{children:"SpeedTestPhase.download"})," → ",(0,h.jsx)(e.code,{children:"SpeedTestPhase.upload"})," →\r\n",(0,h.jsx)(e.code,{children:"SpeedTestPhase.completed"}),"."]}),"\n",(0,h.jsxs)(e.p,{children:["进度阶段依次为 ",(0,h.jsx)(e.code,{children:"download"})," → ",(0,h.jsx)(e.code,{children:"upload"})," → ",(0,h.jsx)(e.code,{children:"completed"}),"。"]}),"\n",(0,h.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,h.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,h.jsxs)(e.code,{children:[(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" quick "}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"runSpeedTest"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includeUpload"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" false"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" includePing"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" false"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,h.jsxs)(e.span,{children:[(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" maxDuration"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Duration"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(seconds"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,h.jsx)(e.span,{children:(0,h.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})})]})}),"\n",(0,h.jsxs)(e.blockquote,{children:["\n",(0,h.jsxs)(e.p,{children:["The default endpoints point at Cloudflare’s public speed service and move real\r\ntraffic (≈25 MB download by default). Ask for consent before running it on a\r\nmetered connection, and override ",(0,h.jsx)(e.code,{children:"downloadUrl"})," / ",(0,h.jsx)(e.code,{children:"uploadUrl"})," for production.\r\n默认端点指向 Cloudflare 公共服务并会产生真实流量(默认下载约 25 MB)。在按量计费\r\n网络上运行前请征得同意,并为生产环境替换 ",(0,h.jsx)(e.code,{children:"downloadUrl"})," / ",(0,h.jsx)(e.code,{children:"uploadUrl"}),"。"]}),"\n"]})]})},"/Speed-Test",{filePath:"pages/Speed-Test.md",pageMap:l.v,frontMatter:{},title:"Speed Test / 测速"},"undefined"==typeof RemoteContent?r:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return h}});let h=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=7003)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Usage-362f5b8f3e61e54f.js b/docs/_next/static/chunks/pages/Usage-362f5b8f3e61e54f.js deleted file mode 100644 index f1cbd2b..0000000 --- a/docs/_next/static/chunks/pages/Usage-362f5b8f3e61e54f.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[848],{4276:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Usage",function(){return e(1258)}])},1258:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return r}});var n=e(5893),h=e(7812),l=e(7080),t=e(8925);function r(i){return[{value:"Which API do I need? / 该用哪个 API?",id:"which-api-do-i-need--该用哪个-api",depth:2},{value:"Global configuration / 全局配置",id:"global-configuration--全局配置",depth:2},{value:"Quality targets / 质量评分理想值",id:"quality-targets--质量评分理想值",depth:3},{value:"JSON serialisation / 序列化",id:"json-serialisation--序列化",depth:2},{value:"Dependency injection & tests / 注入与测试",id:"dependency-injection--tests--注入与测试",depth:2}]}s.default=(0,h.c)(function(i){let{toc:s=r(i)}=i,e={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",span:"span",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,t.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{children:"Usage / 用法"}),"\n",(0,n.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"I want to know…"}),(0,n.jsx)(e.th,{children:"Call"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Am I online, and over what transport?"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.checkConnection()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"React to Wi-Fi ⇄ cellular switches"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.onConnectivityChanged"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Latency, jitter, packet loss"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.ping()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Is DNS slow or broken?"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.resolve()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:["Is ",(0,n.jsx)(e.code,{children:"host:port"})," reachable?"]}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.checkPort()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Which of these ports are open?"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.scanPorts()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"How fast is down/up?"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.runSpeedTest()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"One number for “good or bad”"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.evaluateQuality()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Everything at once, as a report"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.diagnose()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Is the diagnostics API itself expensive?"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkBenchmark.runAll()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Native version / SSID / gateway / MAC"}),(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"ZeroNetworkKit.getPlatformVersion()"}),", ",(0,n.jsx)(e.code,{children:"getNativeNetworkDetails()"})]})]})]})]}),"\n",(0,n.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"NetworkDiagnosticConfig"})," centralises every default. Override only what you\r\nneed; the rest keep the defaults below."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"NetworkDiagnosticConfig"})," 集中了全部默认参数,只需覆盖你关心的字段。"]}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ZeroNetworkKit"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"init"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" config"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnosticConfig"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" pingHost"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '1.1.1.1'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" pingPort"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 443"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" pingCount"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" dnsDomain"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'example.com'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" dnsServers"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" <"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:">"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'1.1.1.1'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'8.8.8.8'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" downloadUrl"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'https://my-cdn.example.com/speedtest.bin'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" uploadUrl"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'https://my-cdn.example.com/upload'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ),"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"Field"}),(0,n.jsx)(e.th,{children:"Default"}),(0,n.jsx)(e.th,{children:"Meaning"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"pingHost"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"'1.1.1.1'"})}),(0,n.jsx)(e.td,{children:"Default ping / port-scan target"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"pingPort"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"443"})}),(0,n.jsx)(e.td,{children:"Port used by the TCP ping"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"pingCount"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"4"})}),(0,n.jsx)(e.td,{children:"Probes per ping run"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"pingTimeout"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"3s"})}),(0,n.jsx)(e.td,{children:"Timeout of one probe"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"pingInterval"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"200ms"})}),(0,n.jsx)(e.td,{children:"Delay between probes"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"dnsDomain"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"'www.google.com'"})}),(0,n.jsx)(e.td,{children:"Default domain for DNS tests"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"dnsServers"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"['1.1.1.1', '8.8.8.8', '114.114.114.114']"})}),(0,n.jsx)(e.td,{children:"Servers queried by default"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"dnsTimeout"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"5s"})}),(0,n.jsx)(e.td,{children:"Timeout per DNS server"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"downloadUrl"})}),(0,n.jsxs)(e.td,{children:["Cloudflare ",(0,n.jsx)(e.code,{children:"__down?bytes=25000000"})]}),(0,n.jsx)(e.td,{children:"Download endpoint"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"uploadUrl"})}),(0,n.jsxs)(e.td,{children:["Cloudflare ",(0,n.jsx)(e.code,{children:"__up"})]}),(0,n.jsx)(e.td,{children:"Upload endpoint"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"uploadPayloadBytes"})}),(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"1048576"})," (1 MiB)"]}),(0,n.jsx)(e.td,{children:"Upload payload size"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"speedTestTimeout"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"30s"})}),(0,n.jsx)(e.td,{children:"Per-request timeout"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"speedTestMaxDuration"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"10s"})}),(0,n.jsx)(e.td,{children:"Sampling window per phase"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"portCheckTimeout"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"3s"})}),(0,n.jsx)(e.td,{children:"Timeout of one port check"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"probePorts"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"[80, 443]"})}),(0,n.jsxs)(e.td,{children:["Ports used by ",(0,n.jsx)(e.code,{children:"scanPorts()"})," by default"]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"qualityTargets"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"const QualityTargets()"})}),(0,n.jsx)(e.td,{children:"Ideal values for scoring"})]})]})]}),"\n",(0,n.jsxs)(e.blockquote,{children:["\n",(0,n.jsx)(e.p,{children:"The default speed-test endpoints are Cloudflare’s public service. Swap them for\r\nyour own before shipping production traffic.\r\n默认测速端点是 Cloudflare 的公共服务,正式项目请替换为自建端点。"}),"\n"]}),"\n",(0,n.jsx)(e.h3,{id:s[2].id,children:s[2].value}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnosticConfig"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" qualityTargets"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" QualityTargets"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" excellentLatency"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 30"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// ms"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" acceptableLatency"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 150"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// ms"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" excellentJitter"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// ms"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" acceptableJitter"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 40"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// ms"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" acceptablePacketLoss"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// %"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" excellentDownload"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 50"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Mbps"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" acceptableDownload"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Mbps"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" excellentUpload"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 20"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Mbps"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" acceptableUpload"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 2"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Mbps"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" excellentDns"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 30"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// ms"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" acceptableDns"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 200"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// ms"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ),"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})})]})}),"\n",(0,n.jsx)(e.h2,{id:s[3].id,children:s[3].value}),"\n",(0,n.jsxs)(e.p,{children:["Every result object implements ",(0,n.jsx)(e.code,{children:"toMap()"})," and is JSON encodable:"]}),"\n",(0,n.jsxs)(e.p,{children:["每个结果对象都实现了 ",(0,n.jsx)(e.code,{children:"toMap()"}),",可直接 JSON 序列化:"]}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'dart:convert'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" report "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"diagnose"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(includeSpeedTest"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" false"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" json "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" jsonEncode"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(report."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toMap"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"());"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(json);"})]}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Round-trip a connection snapshot."})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" decoded "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkConnectionInfo"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"fromMap"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"jsonDecode"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"jsonEncode"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" report.connection."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toMap"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:")) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"as"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Map"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"Object"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"?, "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"Object"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"?>);"})]})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"Type"}),(0,n.jsx)(e.th,{children:"Serialisation"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkConnectionInfo"})}),(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"toMap()"})," + ",(0,n.jsx)(e.code,{children:"fromMap()"})]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"PingResult"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"toMap()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"DnsTestResult"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"toMap()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"PortCheckResult"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"toMap()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"SpeedTestResult"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"toMap()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkQualityScore"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"toMap()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnosticReport"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"toMap()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"BenchmarkResult"})," / ",(0,n.jsx)(e.code,{children:"BenchmarkSuiteResult"})]}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"toMap()"})})]})]})]}),"\n",(0,n.jsx)(e.h2,{id:s[4].id,children:s[4].value}),"\n",(0,n.jsx)(e.p,{children:"Every service accepts its collaborators, so your integration points are\r\nunit-testable without touching the network."}),"\n",(0,n.jsx)(e.p,{children:"每个服务都支持注入协作对象,可以完全脱离网络做单测。"}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"class"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" FakeConnectivityAdapter"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" implements"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ConnectivityAdapter"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"List"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:">> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"checkConnectivity"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"() "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"async"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" =>"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" <"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:">"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'wifi'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"];"})]}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Stream"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"List"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:">> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"get"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" onConnectivityChanged "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Stream"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"empty"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkDiagnostic"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"configure"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" config"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnosticConfig"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(pingHost"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '127.0.0.1'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" connectivity"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ConnectivityService"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(adapter"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" FakeConnectivityAdapter"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"()),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ping"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" PingService"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" dns"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" DnsService"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ports"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" PortService"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" speedTest"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" SpeedTestService"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(client"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" fakeClient),"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Restore defaults afterwards."})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkDiagnostic"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"reset"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]})]})}),"\n",(0,n.jsx)(e.p,{children:"Swap individual services directly when you prefer:"}),"\n",(0,n.jsx)(e.p,{children:"也可以直接替换单个服务:"}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkDiagnostic"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".pingService "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" MyFakePingService"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkDiagnostic"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".dnsService "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" MyFakeDnsService"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]})]})}),"\n",(0,n.jsxs)(e.blockquote,{children:["\n",(0,n.jsxs)(e.p,{children:["For advanced service classes, the DNS wire codec and low-level APIs, import\r\n",(0,n.jsx)(e.code,{children:"package:zero_network_kit/advanced.dart"}),".\r\n进阶的服务类、DNS 报文编解码器等底层 API 请通过\r\n",(0,n.jsx)(e.code,{children:"package:zero_network_kit/advanced.dart"})," 引入。"]}),"\n"]})]})},"/Usage",{filePath:"pages/Usage.md",pageMap:l.v,frontMatter:{},title:"Usage / 用法"},"undefined"==typeof RemoteContent?r:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=4276)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Usage-668e8555c3b8432b.js b/docs/_next/static/chunks/pages/Usage-668e8555c3b8432b.js new file mode 100644 index 0000000..90f2ec5 --- /dev/null +++ b/docs/_next/static/chunks/pages/Usage-668e8555c3b8432b.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[848],{4276:function(i,s,e){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Usage",function(){return e(1258)}])},1258:function(i,s,e){"use strict";e.r(s),e.d(s,{useTOC:function(){return r}});var n=e(5893),h=e(7812),l=e(7080),t=e(8925);function r(i){return[{value:"Which API do I need? / 该用哪个 API?",id:"which-api-do-i-need--该用哪个-api",depth:2},{value:"Global configuration / 全局配置",id:"global-configuration--全局配置",depth:2},{value:"Quality targets / 质量评分理想值",id:"quality-targets--质量评分理想值",depth:3},{value:"JSON serialisation / 序列化",id:"json-serialisation--序列化",depth:2},{value:"Dependency injection & tests / 注入与测试",id:"dependency-injection--tests--注入与测试",depth:2}]}s.default=(0,h.c)(function(i){let{toc:s=r(i)}=i,e={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",span:"span",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,t.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{children:"Usage / 用法"}),"\n",(0,n.jsx)(e.h2,{id:s[0].id,children:s[0].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"I want to know…"}),(0,n.jsx)(e.th,{children:"Call"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Am I online, and over what transport?"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.checkConnection()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"React to Wi-Fi ⇄ cellular switches"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.onConnectivityChanged"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Latency, jitter, packet loss"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.ping()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Is DNS slow or broken?"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.resolve()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:["Is ",(0,n.jsx)(e.code,{children:"host:port"})," reachable?"]}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.checkPort()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Which of these ports are open?"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.scanPorts()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"How fast is down/up?"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.runSpeedTest()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"One number for “good or bad”"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.evaluateQuality()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Everything at once, as a report"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnostic.diagnose()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Is the diagnostics API itself expensive?"}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkBenchmark.runAll()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:"Native version / SSID / gateway / MAC"}),(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"ZeroNetworkKit.getPlatformVersion()"}),", ",(0,n.jsx)(e.code,{children:"getNativeNetworkDetails()"})]})]})]})]}),"\n",(0,n.jsx)(e.h2,{id:s[1].id,children:s[1].value}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"NetworkDiagnosticConfig"})," centralises every default. Override only what you\nneed; the rest keep the defaults below."]}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.code,{children:"NetworkDiagnosticConfig"})," 集中了全部默认参数,只需覆盖你关心的字段。"]}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ZeroNetworkKit"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"init"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" config"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnosticConfig"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" pingHost"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '1.1.1.1'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" pingPort"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 443"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" pingCount"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" dnsDomain"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'example.com'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" dnsServers"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" <"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:">"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'1.1.1.1'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'8.8.8.8'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"],"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" downloadUrl"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'https://my-cdn.example.com/speedtest.bin'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" uploadUrl"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'https://my-cdn.example.com/upload'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ),"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"Field"}),(0,n.jsx)(e.th,{children:"Default"}),(0,n.jsx)(e.th,{children:"Meaning"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"pingHost"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"'1.1.1.1'"})}),(0,n.jsx)(e.td,{children:"Default ping / port-scan target"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"pingPort"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"443"})}),(0,n.jsx)(e.td,{children:"Port used by the TCP ping"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"pingCount"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"4"})}),(0,n.jsx)(e.td,{children:"Probes per ping run"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"pingTimeout"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"3s"})}),(0,n.jsx)(e.td,{children:"Timeout of one probe"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"pingInterval"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"200ms"})}),(0,n.jsx)(e.td,{children:"Delay between probes"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"dnsDomain"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"'www.google.com'"})}),(0,n.jsx)(e.td,{children:"Default domain for DNS tests"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"dnsServers"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"['1.1.1.1', '8.8.8.8', '114.114.114.114']"})}),(0,n.jsx)(e.td,{children:"Servers queried by default"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"dnsTimeout"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"5s"})}),(0,n.jsx)(e.td,{children:"Timeout per DNS server"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"downloadUrl"})}),(0,n.jsxs)(e.td,{children:["Cloudflare ",(0,n.jsx)(e.code,{children:"__down?bytes=25000000"})]}),(0,n.jsx)(e.td,{children:"Download endpoint"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"uploadUrl"})}),(0,n.jsxs)(e.td,{children:["Cloudflare ",(0,n.jsx)(e.code,{children:"__up"})]}),(0,n.jsx)(e.td,{children:"Upload endpoint"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"uploadPayloadBytes"})}),(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"1048576"})," (1 MiB)"]}),(0,n.jsx)(e.td,{children:"Upload payload size"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"speedTestTimeout"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"30s"})}),(0,n.jsx)(e.td,{children:"Per-request timeout"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"speedTestMaxDuration"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"10s"})}),(0,n.jsx)(e.td,{children:"Sampling window per phase"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"portCheckTimeout"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"3s"})}),(0,n.jsx)(e.td,{children:"Timeout of one port check"})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"probePorts"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"[80, 443]"})}),(0,n.jsxs)(e.td,{children:["Ports used by ",(0,n.jsx)(e.code,{children:"scanPorts()"})," by default"]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"qualityTargets"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"const QualityTargets()"})}),(0,n.jsx)(e.td,{children:"Ideal values for scoring"})]})]})]}),"\n",(0,n.jsxs)(e.blockquote,{children:["\n",(0,n.jsx)(e.p,{children:"The default speed-test endpoints are Cloudflare’s public service. Swap them for\nyour own before shipping production traffic.\n默认测速端点是 Cloudflare 的公共服务,正式项目请替换为自建端点。"}),"\n"]}),"\n",(0,n.jsx)(e.h3,{id:s[2].id,children:s[2].value}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnosticConfig"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" qualityTargets"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" QualityTargets"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" excellentLatency"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 30"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// ms"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" acceptableLatency"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 150"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// ms"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" excellentJitter"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// ms"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" acceptableJitter"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 40"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// ms"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" acceptablePacketLoss"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// %"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" excellentDownload"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 50"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Mbps"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" acceptableDownload"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 5"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Mbps"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" excellentUpload"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 20"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Mbps"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" acceptableUpload"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 2"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Mbps"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" excellentDns"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 30"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// ms"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" acceptableDns"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" 200"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// ms"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ),"})}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})})]})}),"\n",(0,n.jsx)(e.h2,{id:s[3].id,children:s[3].value}),"\n",(0,n.jsxs)(e.p,{children:["Every result object implements ",(0,n.jsx)(e.code,{children:"toMap()"})," and is JSON encodable:"]}),"\n",(0,n.jsxs)(e.p,{children:["每个结果对象都实现了 ",(0,n.jsx)(e.code,{children:"toMap()"}),",可直接 JSON 序列化:"]}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" 'dart:convert'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" report "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"diagnose"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(includeSpeedTest"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" false"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" json "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" jsonEncode"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(report."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toMap"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"());"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(json);"})]}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Round-trip a connection snapshot."})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" decoded "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkConnectionInfo"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"fromMap"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"jsonDecode"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"jsonEncode"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" report.connection."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"toMap"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:")) "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"as"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Map"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"Object"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"?, "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"Object"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"?>);"})]})]})}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{children:"Type"}),(0,n.jsx)(e.th,{children:"Serialisation"})]})}),(0,n.jsxs)(e.tbody,{children:[(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkConnectionInfo"})}),(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"toMap()"})," + ",(0,n.jsx)(e.code,{children:"fromMap()"})]})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"PingResult"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"toMap()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"DnsTestResult"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"toMap()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"PortCheckResult"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"toMap()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"SpeedTestResult"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"toMap()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkQualityScore"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"toMap()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"NetworkDiagnosticReport"})}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"toMap()"})})]}),(0,n.jsxs)(e.tr,{children:[(0,n.jsxs)(e.td,{children:[(0,n.jsx)(e.code,{children:"BenchmarkResult"})," / ",(0,n.jsx)(e.code,{children:"BenchmarkSuiteResult"})]}),(0,n.jsx)(e.td,{children:(0,n.jsx)(e.code,{children:"toMap()"})})]})]})]}),"\n",(0,n.jsx)(e.h2,{id:s[4].id,children:s[4].value}),"\n",(0,n.jsx)(e.p,{children:"Every service accepts its collaborators, so your integration points are\nunit-testable without touching the network."}),"\n",(0,n.jsx)(e.p,{children:"每个服务都支持注入协作对象,可以完全脱离网络做单测。"}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"class"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" FakeConnectivityAdapter"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" implements"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ConnectivityAdapter"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Future"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"List"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:">> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"checkConnectivity"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"() "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"async"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" =>"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" <"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:">"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"["}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:"'wifi'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"];"})]}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" @override"})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Stream"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"List"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:">> "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"get"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" onConnectivityChanged "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Stream"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"empty"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkDiagnostic"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"configure"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" config"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnosticConfig"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(pingHost"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:" '127.0.0.1'"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" connectivity"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ConnectivityService"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(adapter"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" FakeConnectivityAdapter"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"()),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ping"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" PingService"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" dns"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" DnsService"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ports"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" PortService"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" speedTest"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" SpeedTestService"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(client"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" fakeClient),"})]}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:");"})}),"\n",(0,n.jsx)(e.span,{children:" "}),"\n",(0,n.jsx)(e.span,{children:(0,n.jsx)(e.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// Restore defaults afterwards."})}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkDiagnostic"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"reset"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]})]})}),"\n",(0,n.jsx)(e.p,{children:"Swap individual services directly when you prefer:"}),"\n",(0,n.jsx)(e.p,{children:"也可以直接替换单个服务:"}),"\n",(0,n.jsx)(e.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(e.code,{children:[(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkDiagnostic"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".pingService "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" MyFakePingService"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsxs)(e.span,{children:[(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkDiagnostic"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".dnsService "}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" MyFakeDnsService"}),(0,n.jsx)(e.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]})]})}),"\n",(0,n.jsxs)(e.blockquote,{children:["\n",(0,n.jsxs)(e.p,{children:["For advanced service classes, the DNS wire codec and low-level APIs, import\n",(0,n.jsx)(e.code,{children:"package:zero_network_kit/advanced.dart"}),".\n进阶的服务类、DNS 报文编解码器等底层 API 请通过\n",(0,n.jsx)(e.code,{children:"package:zero_network_kit/advanced.dart"})," 引入。"]}),"\n"]})]})},"/Usage",{filePath:"pages/Usage.md",timestamp:1789334081e3,pageMap:l.v,frontMatter:{},title:"Usage / 用法"},"undefined"==typeof RemoteContent?r:RemoteContent.useTOC)},7080:function(i,s,e){"use strict";e.d(s,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=4276)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/index-2a81fce2c8fa4aa7.js b/docs/_next/static/chunks/pages/index-2a81fce2c8fa4aa7.js new file mode 100644 index 0000000..3f653e5 --- /dev/null +++ b/docs/_next/static/chunks/pages/index-2a81fce2c8fa4aa7.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[405],{2725:function(e,n,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/",function(){return t(4991)}])},4991:function(e,n,t){"use strict";t.r(n),t.d(n,{useTOC:function(){return l}});var r=t(5893),i=t(7812),s=t(7080),d=t(8925);function l(e){return[{value:"✨ Features / 功能特性",id:"-features--功能特性",depth:2},{value:"\uD83D\uDCDA Table of Contents / 目录",id:"-table-of-contents--目录",depth:2},{value:"\uD83D\uDD17 Links / 链接",id:"-links--链接",depth:2},{value:"\uD83D\uDCC4 License / 许可证",id:"-license--许可证",depth:2}]}n.default=(0,i.c)(function(e){let{toc:n=l(e)}=e,t={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,d.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{children:"Zero Network Kit"}),"\n",(0,r.jsxs)(t.p,{children:["A Flutter plugin for ",(0,r.jsx)(t.strong,{children:"network diagnostics"}),": connectivity inspection, latency\nprobing, DNS resolution, port checks, bandwidth measurement, quality scoring and\nmicro-benchmarks — on Android, iOS, macOS, Windows and Linux."]}),"\n",(0,r.jsxs)(t.p,{children:["一个 Flutter 插件,提供",(0,r.jsx)(t.strong,{children:"网络诊断"}),"能力:连通性检测、延迟探测、DNS 解析、端口\n检测、带宽测速、质量评分与微基准测试——覆盖 Android、iOS、macOS、Windows 与 Linux。"]}),"\n",(0,r.jsx)(t.h2,{id:n[0].id,children:n[0].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Feature"}),(0,r.jsx)(t.th,{children:"Description"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Zero setup"})}),(0,r.jsxs)(t.td,{children:["Works out of the box; ",(0,r.jsx)(t.code,{children:"init()"})," only to override defaults / 开箱即用,仅需在想覆盖默认值时才 ",(0,r.jsx)(t.code,{children:"init()"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Connectivity"})}),(0,r.jsx)(t.td,{children:"Transport type, IPv4/IPv6, gateway, SSID, RSSI, MAC, VPN / 传输类型、IPv4/IPv6、网关、SSID、信号强度、MAC、VPN"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Latency"})}),(0,r.jsx)(t.td,{children:"TCP handshake RTT everywhere; system ICMP on desktop / TCP 握手 RTT 全平台可用,桌面额外支持系统 ICMP"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"DNS"})}),(0,r.jsx)(t.td,{children:"System resolver + raw UDP against explicit servers / 系统解析器 + 针对指定服务器的原始 UDP 查询"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Ports"})}),(0,r.jsx)(t.td,{children:"Bounded-concurrency TCP reachability / 有界并发的 TCP 可达性检测"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Speed test"})}),(0,r.jsx)(t.td,{children:"Download/upload throughput with progress callbacks / 上下行测速,带进度回调"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Quality"})}),(0,r.jsx)(t.td,{children:"Weighted 0–100 score + level + suggestions / 加权 0–100 分 + 等级 + 建议"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Full report"})}),(0,r.jsx)(t.td,{children:"One-shot aggregate of every probe / 一次性汇总所有探测"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Benchmarks"})}),(0,r.jsx)(t.td,{children:"Measures how fast the diagnostics API itself runs / 衡量诊断 API 自身开销"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Capabilities"})}),(0,r.jsx)(t.td,{children:"Query-then-call; hide unsupported cards (e.g. SSID on desktop) / 先查询后调用,隐藏不支持的卡片"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Graceful degradation"})}),(0,r.jsxs)(t.td,{children:["Missing permission or unreachable sub-service never throws / 缺权限或子服务不可达时只返回 ",(0,r.jsx)(t.code,{children:"null"}),",绝不抛异常"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Hermetic tests"})}),(0,r.jsx)(t.td,{children:"Every service accepts injected collaborators / 每个服务都支持注入协作对象,便于单测"})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:n[1].id,children:n[1].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Page"}),(0,r.jsx)(t.th,{children:"Description"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Getting-Started",children:"Getting Started"})}),(0,r.jsx)(t.td,{children:"Quick start guide / 快速开始"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Installation",children:"Installation"})}),(0,r.jsx)(t.td,{children:"How to install / 安装方式"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Usage",children:"Usage"})}),(0,r.jsx)(t.td,{children:"Global config, serialisation, dependency injection / 全局配置、序列化、依赖注入"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Connectivity",children:"Connectivity"})}),(0,r.jsx)(t.td,{children:"Connection snapshot & change stream / 连通性快照与变化监听"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Ping",children:"Latency / Ping"})}),(0,r.jsx)(t.td,{children:"TCP & ICMP latency probing / 延迟探测"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"DNS",children:"DNS"})}),(0,r.jsx)(t.td,{children:"Resolver comparison across servers / DNS 解析"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Ports",children:"Ports"})}),(0,r.jsx)(t.td,{children:"Single port & bulk scan / 端口检测"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Speed-Test",children:"Speed Test"})}),(0,r.jsx)(t.td,{children:"Download/upload throughput / 测速"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Quality",children:"Quality Score"})}),(0,r.jsx)(t.td,{children:"Weighted scoring / 质量评分"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Full-Report",children:"Full Report"})}),(0,r.jsx)(t.td,{children:"One-shot aggregate / 汇总报告"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Benchmark",children:"Benchmarks"})}),(0,r.jsx)(t.td,{children:"Micro-benchmarks / 微基准"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Platform-Support",children:"Platform Support"})}),(0,r.jsx)(t.td,{children:"Capability matrix & native details / 能力矩阵与原生详情"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"API-Reference",children:"API Reference"})}),(0,r.jsx)(t.td,{children:"Model field reference & gotchas / 模型字段速查与陷阱"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"FAQ",children:"FAQ"})}),(0,r.jsx)(t.td,{children:"Frequently asked questions / 常见问题"})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:n[2].id,children:n[2].value}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://github.com/zero-labsco/zero_network_kit",children:"GitHub"})}),"\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://www.zerolabsco.com/",children:"Official Website"})}),"\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://pub.dev/packages/zero_network_kit",children:"pub.dev"})}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:n[3].id,children:n[3].value}),"\n",(0,r.jsxs)(t.p,{children:["This project is licensed under the ",(0,r.jsx)(t.strong,{children:"MPL-2.0"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["本项目采用 ",(0,r.jsx)(t.strong,{children:"MPL-2.0"})," 许可证。"]}),"\n",(0,r.jsx)(t.p,{children:"This plugin is provided “as is”, without warranty of any kind. The author assumes\nno responsibility or liability for the functionality, security, or any\nconsequences arising from the use of modified versions or derivative projects."}),"\n",(0,r.jsx)(t.p,{children:"本插件按”原样”提供,不提供任何担保。作者不对修改版或衍生项目的功能、安全性及\n任何使用后果承担责任。"})]})},"/",{filePath:"pages/index.md",timestamp:1789334081e3,pageMap:s.v,frontMatter:{},title:"Zero Network Kit"},"undefined"==typeof RemoteContent?l:RemoteContent.useTOC)},7080:function(e,n,t){"use strict";t.d(n,{v:function(){return r}});let r=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=2725)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/index-b4ab3b9e4fb7d062.js b/docs/_next/static/chunks/pages/index-b4ab3b9e4fb7d062.js deleted file mode 100644 index ece3af0..0000000 --- a/docs/_next/static/chunks/pages/index-b4ab3b9e4fb7d062.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[405],{2725:function(e,n,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/",function(){return t(4991)}])},4991:function(e,n,t){"use strict";t.r(n),t.d(n,{useTOC:function(){return l}});var r=t(5893),i=t(7812),s=t(7080),d=t(8925);function l(e){return[{value:"✨ Features / 功能特性",id:"-features--功能特性",depth:2},{value:"\uD83D\uDCDA Table of Contents / 目录",id:"-table-of-contents--目录",depth:2},{value:"\uD83D\uDD17 Links / 链接",id:"-links--链接",depth:2},{value:"\uD83D\uDCC4 License / 许可证",id:"-license--许可证",depth:2}]}n.default=(0,i.c)(function(e){let{toc:n=l(e)}=e,t={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,d.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{children:"Zero Network Kit"}),"\n",(0,r.jsxs)(t.p,{children:["A Flutter plugin for ",(0,r.jsx)(t.strong,{children:"network diagnostics"}),": connectivity inspection, latency\r\nprobing, DNS resolution, port checks, bandwidth measurement, quality scoring and\r\nmicro-benchmarks — on Android, iOS, macOS, Windows and Linux."]}),"\n",(0,r.jsxs)(t.p,{children:["一个 Flutter 插件,提供",(0,r.jsx)(t.strong,{children:"网络诊断"}),"能力:连通性检测、延迟探测、DNS 解析、端口\r\n检测、带宽测速、质量评分与微基准测试——覆盖 Android、iOS、macOS、Windows 与 Linux。"]}),"\n",(0,r.jsx)(t.h2,{id:n[0].id,children:n[0].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Feature"}),(0,r.jsx)(t.th,{children:"Description"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Zero setup"})}),(0,r.jsxs)(t.td,{children:["Works out of the box; ",(0,r.jsx)(t.code,{children:"init()"})," only to override defaults / 开箱即用,仅需在想覆盖默认值时才 ",(0,r.jsx)(t.code,{children:"init()"})]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Connectivity"})}),(0,r.jsx)(t.td,{children:"Transport type, IPv4/IPv6, gateway, SSID, RSSI, MAC, VPN / 传输类型、IPv4/IPv6、网关、SSID、信号强度、MAC、VPN"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Latency"})}),(0,r.jsx)(t.td,{children:"TCP handshake RTT everywhere; system ICMP on desktop / TCP 握手 RTT 全平台可用,桌面额外支持系统 ICMP"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"DNS"})}),(0,r.jsx)(t.td,{children:"System resolver + raw UDP against explicit servers / 系统解析器 + 针对指定服务器的原始 UDP 查询"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Ports"})}),(0,r.jsx)(t.td,{children:"Bounded-concurrency TCP reachability / 有界并发的 TCP 可达性检测"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Speed test"})}),(0,r.jsx)(t.td,{children:"Download/upload throughput with progress callbacks / 上下行测速,带进度回调"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Quality"})}),(0,r.jsx)(t.td,{children:"Weighted 0–100 score + level + suggestions / 加权 0–100 分 + 等级 + 建议"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Full report"})}),(0,r.jsx)(t.td,{children:"One-shot aggregate of every probe / 一次性汇总所有探测"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Benchmarks"})}),(0,r.jsx)(t.td,{children:"Measures how fast the diagnostics API itself runs / 衡量诊断 API 自身开销"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Capabilities"})}),(0,r.jsx)(t.td,{children:"Query-then-call; hide unsupported cards (e.g. SSID on desktop) / 先查询后调用,隐藏不支持的卡片"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Graceful degradation"})}),(0,r.jsxs)(t.td,{children:["Missing permission or unreachable sub-service never throws / 缺权限或子服务不可达时只返回 ",(0,r.jsx)(t.code,{children:"null"}),",绝不抛异常"]})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.strong,{children:"Hermetic tests"})}),(0,r.jsx)(t.td,{children:"Every service accepts injected collaborators / 每个服务都支持注入协作对象,便于单测"})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:n[1].id,children:n[1].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"Page"}),(0,r.jsx)(t.th,{children:"Description"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Getting-Started",children:"Getting Started"})}),(0,r.jsx)(t.td,{children:"Quick start guide / 快速开始"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Installation",children:"Installation"})}),(0,r.jsx)(t.td,{children:"How to install / 安装方式"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Usage",children:"Usage"})}),(0,r.jsx)(t.td,{children:"Global config, serialisation, dependency injection / 全局配置、序列化、依赖注入"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Connectivity",children:"Connectivity"})}),(0,r.jsx)(t.td,{children:"Connection snapshot & change stream / 连通性快照与变化监听"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Ping",children:"Latency / Ping"})}),(0,r.jsx)(t.td,{children:"TCP & ICMP latency probing / 延迟探测"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"DNS",children:"DNS"})}),(0,r.jsx)(t.td,{children:"Resolver comparison across servers / DNS 解析"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Ports",children:"Ports"})}),(0,r.jsx)(t.td,{children:"Single port & bulk scan / 端口检测"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Speed-Test",children:"Speed Test"})}),(0,r.jsx)(t.td,{children:"Download/upload throughput / 测速"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Quality",children:"Quality Score"})}),(0,r.jsx)(t.td,{children:"Weighted scoring / 质量评分"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Full-Report",children:"Full Report"})}),(0,r.jsx)(t.td,{children:"One-shot aggregate / 汇总报告"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Benchmark",children:"Benchmarks"})}),(0,r.jsx)(t.td,{children:"Micro-benchmarks / 微基准"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"Platform-Support",children:"Platform Support"})}),(0,r.jsx)(t.td,{children:"Capability matrix & native details / 能力矩阵与原生详情"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"API-Reference",children:"API Reference"})}),(0,r.jsx)(t.td,{children:"Model field reference & gotchas / 模型字段速查与陷阱"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"FAQ",children:"FAQ"})}),(0,r.jsx)(t.td,{children:"Frequently asked questions / 常见问题"})]})]})]}),"\n",(0,r.jsx)(t.h2,{id:n[2].id,children:n[2].value}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://github.com/zero-labsco/zero_network_kit",children:"GitHub"})}),"\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://www.zerolabsco.com/",children:"Official Website"})}),"\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://pub.dev/packages/zero_network_kit",children:"pub.dev"})}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:n[3].id,children:n[3].value}),"\n",(0,r.jsxs)(t.p,{children:["This project is licensed under the ",(0,r.jsx)(t.strong,{children:"MPL-2.0"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["本项目采用 ",(0,r.jsx)(t.strong,{children:"MPL-2.0"})," 许可证。"]}),"\n",(0,r.jsx)(t.p,{children:"This plugin is provided “as is”, without warranty of any kind. The author assumes\r\nno responsibility or liability for the functionality, security, or any\r\nconsequences arising from the use of modified versions or derivative projects."}),"\n",(0,r.jsx)(t.p,{children:"本插件按”原样”提供,不提供任何担保。作者不对修改版或衍生项目的功能、安全性及\r\n任何使用后果承担责任。"})]})},"/",{filePath:"pages/index.md",pageMap:s.v,frontMatter:{},title:"Zero Network Kit"},"undefined"==typeof RemoteContent?l:RemoteContent.useTOC)},7080:function(e,n,t){"use strict";t.d(n,{v:function(){return r}});let r=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=2725)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/docs/_next/static/dF_UuZS4SBtufIwTYLshU/_buildManifest.js b/docs/_next/static/dF_UuZS4SBtufIwTYLshU/_buildManifest.js new file mode 100644 index 0000000..11b3f26 --- /dev/null +++ b/docs/_next/static/dF_UuZS4SBtufIwTYLshU/_buildManifest.js @@ -0,0 +1 @@ +self.__BUILD_MANIFEST=function(e){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":[e,"static/chunks/pages/index-2a81fce2c8fa4aa7.js"],"/API-Reference":[e,"static/chunks/pages/API-Reference-e13a2917d7546319.js"],"/Benchmark":[e,"static/chunks/pages/Benchmark-a292e8cb0a504f00.js"],"/Connectivity":[e,"static/chunks/pages/Connectivity-f9b385023ad97f07.js"],"/DNS":[e,"static/chunks/pages/DNS-93340032eaa9ffdd.js"],"/FAQ":[e,"static/chunks/pages/FAQ-c14e0ebd2147b3f8.js"],"/Full-Report":[e,"static/chunks/pages/Full-Report-8fdda01136483e9e.js"],"/Getting-Started":[e,"static/chunks/pages/Getting-Started-0b9a79d0ebc87cdf.js"],"/Installation":[e,"static/chunks/pages/Installation-43ade467e1e7ca4a.js"],"/Ping":[e,"static/chunks/pages/Ping-e7614d3667bef7af.js"],"/Platform-Support":[e,"static/chunks/pages/Platform-Support-45a009c029992240.js"],"/Ports":[e,"static/chunks/pages/Ports-743ec1523389b840.js"],"/Quality":[e,"static/chunks/pages/Quality-ac653fb19750eaeb.js"],"/Speed-Test":[e,"static/chunks/pages/Speed-Test-03d333b534600839.js"],"/Usage":[e,"static/chunks/pages/Usage-668e8555c3b8432b.js"],"/_error":["static/chunks/pages/_error-7a92967bea80186d.js"],"/_meta":["static/chunks/pages/_meta-b47e7a01bb6b7929.js"],sortedPages:["/","/API-Reference","/Benchmark","/Connectivity","/DNS","/FAQ","/Full-Report","/Getting-Started","/Installation","/Ping","/Platform-Support","/Ports","/Quality","/Speed-Test","/Usage","/_app","/_error","/_meta"]}}("static/chunks/812-02e96d01ac591260.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB(); \ No newline at end of file diff --git a/docs/_next/static/kzRY1NuiYAeDBzYFfxfw_/_ssgManifest.js b/docs/_next/static/dF_UuZS4SBtufIwTYLshU/_ssgManifest.js similarity index 100% rename from docs/_next/static/kzRY1NuiYAeDBzYFfxfw_/_ssgManifest.js rename to docs/_next/static/dF_UuZS4SBtufIwTYLshU/_ssgManifest.js diff --git a/docs/_next/static/kzRY1NuiYAeDBzYFfxfw_/_buildManifest.js b/docs/_next/static/kzRY1NuiYAeDBzYFfxfw_/_buildManifest.js deleted file mode 100644 index f93ffe2..0000000 --- a/docs/_next/static/kzRY1NuiYAeDBzYFfxfw_/_buildManifest.js +++ /dev/null @@ -1 +0,0 @@ -self.__BUILD_MANIFEST=function(s){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":[s,"static/chunks/pages/index-b4ab3b9e4fb7d062.js"],"/API-Reference":[s,"static/chunks/pages/API-Reference-8e9a91f2d08796c0.js"],"/Benchmark":[s,"static/chunks/pages/Benchmark-5a9a84620f44f1ef.js"],"/Connectivity":[s,"static/chunks/pages/Connectivity-f42171fa3a2a6178.js"],"/DNS":[s,"static/chunks/pages/DNS-9c89ec32dcd86fa0.js"],"/FAQ":[s,"static/chunks/pages/FAQ-fc88c8a22ac8a489.js"],"/Full-Report":[s,"static/chunks/pages/Full-Report-5051e1f889df2f3a.js"],"/Getting-Started":[s,"static/chunks/pages/Getting-Started-51c49bf7439b90f4.js"],"/Installation":[s,"static/chunks/pages/Installation-b38e40fcafc59c1e.js"],"/Ping":[s,"static/chunks/pages/Ping-ffd9c666caab5ae7.js"],"/Platform-Support":[s,"static/chunks/pages/Platform-Support-2f4f155ba23a4f83.js"],"/Ports":[s,"static/chunks/pages/Ports-325a60377e02f441.js"],"/Quality":[s,"static/chunks/pages/Quality-84301e2f3a2871a5.js"],"/Speed-Test":[s,"static/chunks/pages/Speed-Test-f92135729d9500cb.js"],"/Usage":[s,"static/chunks/pages/Usage-362f5b8f3e61e54f.js"],"/_error":["static/chunks/pages/_error-7a92967bea80186d.js"],"/_meta":["static/chunks/pages/_meta-b47e7a01bb6b7929.js"],sortedPages:["/","/API-Reference","/Benchmark","/Connectivity","/DNS","/FAQ","/Full-Report","/Getting-Started","/Installation","/Ping","/Platform-Support","/Ports","/Quality","/Speed-Test","/Usage","/_app","/_error","/_meta"]}}("static/chunks/812-02e96d01ac591260.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB(); \ No newline at end of file diff --git a/docs/favicon.svg b/docs/favicon.svg index 7474f23..819cb29 100644 --- a/docs/favicon.svg +++ b/docs/favicon.svg @@ -1,4 +1,4 @@ - + diff --git a/docs/index.html b/docs/index.html index a4f12d5..f8d17ae 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,4 +1,4 @@ -
    🏠 Home

    Zero Network Kit

    +
    🏠 Home

    Zero Network Kit

    A Flutter plugin for network diagnostics: connectivity inspection, latency probing, DNS resolution, port checks, bandwidth measurement, quality scoring and micro-benchmarks — on Android, iOS, macOS, Windows and Linux.

    @@ -143,4 +143,4 @@

    本插件按”原样”提供,不提供任何担保。作者不对修改版或衍生项目的功能、安全性及 -任何使用后果承担责任。


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +任何使用后果承担责任。


    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/example/web/favicon.png b/example/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM literal 0 HcmV?d00001 diff --git a/example/web/icons/Icon-192.png b/example/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 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 literal 0 HcmV?d00001 diff --git a/example/web/icons/Icon-512.png b/example/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/example/web/icons/Icon-maskable-192.png b/example/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 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 literal 0 HcmV?d00001 diff --git a/example/web/icons/Icon-maskable-512.png b/example/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/example/web/index.html b/example/web/index.html new file mode 100644 index 0000000..dda3d45 --- /dev/null +++ b/example/web/index.html @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + zero_network_kit_example + + + + + + + diff --git a/example/web/manifest.json b/example/web/manifest.json new file mode 100644 index 0000000..7e53c6d --- /dev/null +++ b/example/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "zero_network_kit_example", + "short_name": "zero_network_kit_example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "Demonstrates how to use the zero_network_kit plugin.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/lib/src/models/network_capabilities.dart b/lib/src/models/network_capabilities.dart index d8fac91..bb10f11 100644 --- a/lib/src/models/network_capabilities.dart +++ b/lib/src/models/network_capabilities.dart @@ -1,92 +1,9 @@ -import 'dart:io'; - -/// 单项网络诊断能力 / A single network diagnostic capability. -enum NetworkCapability { - /// 连通性检测 / Connectivity check. - connectivity, - - /// 原生网络详情(SSID / 网关 / MAC / VPN)/ Native details. - nativeDetails, - - /// 本地 IP / IPv6 快照 / Local address snapshot. - localAddresses, - - /// TCP 握手延迟 / TCP handshake latency. - tcpPing, - - /// 系统 ICMP `ping` 命令(仅桌面)/ System ICMP ping (desktop only). - icmpPing, - - /// 系统 DNS 解析器 / System DNS resolver. - dnsSystem, - - /// 指定服务器的原始 UDP DNS 查询 / Raw UDP DNS against an explicit server. - dnsUdp, - - /// TCP 端口检测 / TCP port check. - portCheck, - - /// 带宽测速 / Bandwidth speed test. - speedTest, - - /// 质量评分 / Quality scoring. - quality, - - /// 微基准 / Micro-benchmarks. - benchmark, -} - -/// 当前平台支持的网络能力集合 / The set of capabilities on the current platform. -class NetworkCapabilities { - /// 构造 [NetworkCapabilities] / Creates a [NetworkCapabilities]. - const NetworkCapabilities({required this.supported, required this.platform}); - - /// 当前平台支持的能力 / Capabilities available on the current platform. - final Set supported; - - /// 平台标识 / Platform identifier. - final String platform; - - /// 该能力是否可用 / Whether [capability] is available. - bool supports(NetworkCapability capability) => supported.contains(capability); - - /// 基于当前运行平台构建能力集 / Builds the capability set for the host platform. - /// - /// 桌面(A 档)不保证原生详情,故 [NetworkCapability.nativeDetails] 仅移动端纳入; - /// [NetworkCapability.icmpPing] 反之仅桌面可用 / - /// Desktops (tier A) cannot reliably provide native details, so [nativeDetails] - /// is mobile-only; [icmpPing] is desktop-only. - static NetworkCapabilities current() { - final isMobile = Platform.isAndroid || Platform.isIOS; - final isDesktop = - Platform.isMacOS || Platform.isWindows || Platform.isLinux; - - final platform = Platform.isAndroid - ? 'android' - : Platform.isIOS - ? 'ios' - : Platform.isMacOS - ? 'macos' - : Platform.isWindows - ? 'windows' - : Platform.isLinux - ? 'linux' - : 'unknown'; - - final supported = { - NetworkCapability.connectivity, - NetworkCapability.localAddresses, - NetworkCapability.tcpPing, - NetworkCapability.dnsSystem, - NetworkCapability.dnsUdp, - NetworkCapability.portCheck, - NetworkCapability.speedTest, - NetworkCapability.quality, - NetworkCapability.benchmark, - }; - if (isMobile) supported.add(NetworkCapability.nativeDetails); - if (isDesktop) supported.add(NetworkCapability.icmpPing); - - return NetworkCapabilities(supported: supported, platform: platform); - } -} +// 网络诊断能力枚举与当前平台能力集 / Network diagnostic capabilities and the +// capability set of the current platform. +// +// 依据平台条件导出实现:原生平台报告完整能力,Web 仅报告浏览器沙箱内可实现的 +// 能力 / Conditionally exports the implementation: the native build reports the +// full capability set, while the web build reports only what the browser sandbox +// supports. +export 'network_capabilities_io.dart' + if (dart.library.html) 'network_capabilities_web.dart'; diff --git a/lib/src/models/network_capabilities_io.dart b/lib/src/models/network_capabilities_io.dart new file mode 100644 index 0000000..d8fac91 --- /dev/null +++ b/lib/src/models/network_capabilities_io.dart @@ -0,0 +1,92 @@ +import 'dart:io'; + +/// 单项网络诊断能力 / A single network diagnostic capability. +enum NetworkCapability { + /// 连通性检测 / Connectivity check. + connectivity, + + /// 原生网络详情(SSID / 网关 / MAC / VPN)/ Native details. + nativeDetails, + + /// 本地 IP / IPv6 快照 / Local address snapshot. + localAddresses, + + /// TCP 握手延迟 / TCP handshake latency. + tcpPing, + + /// 系统 ICMP `ping` 命令(仅桌面)/ System ICMP ping (desktop only). + icmpPing, + + /// 系统 DNS 解析器 / System DNS resolver. + dnsSystem, + + /// 指定服务器的原始 UDP DNS 查询 / Raw UDP DNS against an explicit server. + dnsUdp, + + /// TCP 端口检测 / TCP port check. + portCheck, + + /// 带宽测速 / Bandwidth speed test. + speedTest, + + /// 质量评分 / Quality scoring. + quality, + + /// 微基准 / Micro-benchmarks. + benchmark, +} + +/// 当前平台支持的网络能力集合 / The set of capabilities on the current platform. +class NetworkCapabilities { + /// 构造 [NetworkCapabilities] / Creates a [NetworkCapabilities]. + const NetworkCapabilities({required this.supported, required this.platform}); + + /// 当前平台支持的能力 / Capabilities available on the current platform. + final Set supported; + + /// 平台标识 / Platform identifier. + final String platform; + + /// 该能力是否可用 / Whether [capability] is available. + bool supports(NetworkCapability capability) => supported.contains(capability); + + /// 基于当前运行平台构建能力集 / Builds the capability set for the host platform. + /// + /// 桌面(A 档)不保证原生详情,故 [NetworkCapability.nativeDetails] 仅移动端纳入; + /// [NetworkCapability.icmpPing] 反之仅桌面可用 / + /// Desktops (tier A) cannot reliably provide native details, so [nativeDetails] + /// is mobile-only; [icmpPing] is desktop-only. + static NetworkCapabilities current() { + final isMobile = Platform.isAndroid || Platform.isIOS; + final isDesktop = + Platform.isMacOS || Platform.isWindows || Platform.isLinux; + + final platform = Platform.isAndroid + ? 'android' + : Platform.isIOS + ? 'ios' + : Platform.isMacOS + ? 'macos' + : Platform.isWindows + ? 'windows' + : Platform.isLinux + ? 'linux' + : 'unknown'; + + final supported = { + NetworkCapability.connectivity, + NetworkCapability.localAddresses, + NetworkCapability.tcpPing, + NetworkCapability.dnsSystem, + NetworkCapability.dnsUdp, + NetworkCapability.portCheck, + NetworkCapability.speedTest, + NetworkCapability.quality, + NetworkCapability.benchmark, + }; + if (isMobile) supported.add(NetworkCapability.nativeDetails); + if (isDesktop) supported.add(NetworkCapability.icmpPing); + + return NetworkCapabilities(supported: supported, platform: platform); + } +} diff --git a/lib/src/models/network_capabilities_web.dart b/lib/src/models/network_capabilities_web.dart new file mode 100644 index 0000000..a651efe --- /dev/null +++ b/lib/src/models/network_capabilities_web.dart @@ -0,0 +1,64 @@ +/// 单项网络诊断能力 / A single network diagnostic capability. +enum NetworkCapability { + /// 连通性检测 / Connectivity check. + connectivity, + + /// 原生网络详情(SSID / 网关 / MAC / VPN)/ Native details. + nativeDetails, + + /// 本地 IP / IPv6 快照 / Local address snapshot. + localAddresses, + + /// TCP 握手延迟 / TCP handshake latency. + tcpPing, + + /// 系统 ICMP `ping` 命令(仅桌面)/ System ICMP ping (desktop only). + icmpPing, + + /// 系统 DNS 解析器 / System DNS resolver. + dnsSystem, + + /// 指定服务器的原始 UDP DNS 查询 / Raw UDP DNS against an explicit server. + dnsUdp, + + /// TCP 端口检测 / TCP port check. + portCheck, + + /// 带宽测速 / Bandwidth speed test. + speedTest, + + /// 质量评分 / Quality scoring. + quality, + + /// 微基准 / Micro-benchmarks. + benchmark, +} + +/// Web 平台支持的网络能力集合 / The set of capabilities on the web platform. +class NetworkCapabilities { + /// 构造 [NetworkCapabilities] / Creates a [NetworkCapabilities]. + const NetworkCapabilities({required this.supported, required this.platform}); + + /// 当前平台支持的能力 / Capabilities available on the current platform. + final Set supported; + + /// 平台标识 / Platform identifier. + final String platform; + + /// 该能力是否可用 / Whether [capability] is available. + bool supports(NetworkCapability capability) => supported.contains(capability); + + /// 基于当前运行平台构建能力集 / Builds the capability set for the host platform. + static NetworkCapabilities current() { + const supported = { + NetworkCapability.connectivity, + NetworkCapability.tcpPing, + NetworkCapability.dnsSystem, + NetworkCapability.speedTest, + NetworkCapability.quality, + NetworkCapability.benchmark, + }; + + return NetworkCapabilities(supported: supported, platform: 'web'); + } +} diff --git a/lib/src/services/connectivity_service.dart b/lib/src/services/connectivity_service.dart index 89ed136..242e906 100644 --- a/lib/src/services/connectivity_service.dart +++ b/lib/src/services/connectivity_service.dart @@ -1,227 +1,9 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:connectivity_plus/connectivity_plus.dart'; - -import '../../zero_network_kit_platform_interface.dart'; -import '../models/network_connection_info.dart'; -import '../models/network_type.dart'; - -/// 连接类型数据源抽象 / Abstraction over the platform connectivity source. -/// -/// 默认由 `connectivity_plus` 实现,单元测试可注入假实现 / -/// Implemented by `connectivity_plus` by default; unit tests can inject fakes. -abstract class ConnectivityAdapter { - /// 读取当前连接类型(如 `['wifi']`)/ Reads the current transports, e.g. - /// `['wifi']`. - Future> checkConnectivity(); - - /// 监听连接类型变化 / Emits whenever the transports change. - Stream> get onConnectivityChanged; -} - -/// 基于 `connectivity_plus` 的默认适配器 / -/// Default adapter backed by `connectivity_plus`. -class ConnectivityPlusAdapter implements ConnectivityAdapter { - /// 构造 [ConnectivityPlusAdapter] / Creates a [ConnectivityPlusAdapter]. - ConnectivityPlusAdapter([Connectivity? connectivity]) - : _connectivity = connectivity ?? Connectivity(); - - final Connectivity _connectivity; - - @override - Future> checkConnectivity() async { - final results = await _connectivity.checkConnectivity(); - return _names(results); - } - - @override - Stream> get onConnectivityChanged => - _connectivity.onConnectivityChanged.map(_names); - - List _names(List results) => - results.map((result) => result.name).toList(growable: false); -} - -/// 连通性检测与网络信息采集服务 / -/// Connectivity detection and network information service. -class ConnectivityService { - /// 构造 [ConnectivityService] / Creates a [ConnectivityService]. - ConnectivityService({ConnectivityAdapter? adapter}) - : _adapter = adapter ?? ConnectivityPlusAdapter(); - - final ConnectivityAdapter _adapter; - - /// 主动可达性探测实现 / Reachability probe used when explicitly requested. - /// - /// 默认通过系统解析器查询 `one.one.one.one` / Defaults to resolving - /// `one.one.one.one` through the platform resolver. - Future Function() reachabilityProbe = _defaultReachabilityProbe; - - /// 采集一次网络连接快照 / Captures one network connection snapshot. - /// - /// [includeNativeDetails] 为 `true` 时会调用原生通道获取 SSID、网关、MAC 等 - /// 信息(失败时静默降级)/ When [includeNativeDetails] is `true` an extra - /// platform-channel call enriches the snapshot with SSID, gateway and MAC - /// (silently degrades on failure). - /// [probeReachability] 为 `true` 时会额外执行主动连通性探测 / - /// [probeReachability] additionally performs an active reachability probe. - Future checkConnection({ - bool includeNativeDetails = true, - bool probeReachability = false, - Duration probeTimeout = const Duration(seconds: 3), - }) async { - final transports = await _safeTransports(); - final types = transports - .map(NetworkType.fromRaw) - .where((type) => type != NetworkType.none) - .toList(growable: false); - - Map? native; - if (includeNativeDetails) { - native = await _safeNativeDetails(); - } - - final fallback = await _dartInterfaceSnapshot(); - - final ipAddress = - _asString(native?['ipAddress']) ?? - fallback.ipAddress ?? - _asString(native?['ipv6Address']) ?? - fallback.ipv6Address; - - final info = NetworkConnectionInfo( - isConnected: types.isNotEmpty || ipAddress != null, - type: _resolveType(types), - ssid: _asString(native?['ssid']), - signalStrength: (native?['signalStrength'] as num?)?.toInt(), - ipAddress: _asString(native?['ipAddress']) ?? fallback.ipAddress, - ipv6Address: _asString(native?['ipv6Address']) ?? fallback.ipv6Address, - gateway: _asString(native?['gateway']), - macAddress: _asString(native?['macAddress']), - isVpn: native?['isVpn'] == true || types.contains(NetworkType.vpn), - timestamp: DateTime.now(), - ); - - if (!probeReachability) return info; - return info.copyWith(isReachable: await _safeProbe(probeTimeout)); - } - - /// 监听网络连接变化 / Emits a fresh snapshot whenever connectivity changes. - /// - /// 立即发出一次当前状态,随后在每次底层变化时重新采集 / - /// Emits the current state immediately, then re-samples on every change. - Stream get onConnectivityChanged async* { - yield await checkConnection(); - await for (final _ in _adapter.onConnectivityChanged) { - yield await checkConnection(); - } - } - - Future> _safeTransports() async { - try { - return await _adapter.checkConnectivity(); - } catch (_) { - return const []; - } - } - - Future?> _safeNativeDetails() async { - try { - return await ZeroNetworkKitPlatform.instance.getNetworkDetails(); - } catch (_) { - return null; - } - } - - Future _safeProbe(Duration timeout) async { - try { - return await reachabilityProbe().timeout(timeout); - } catch (_) { - return false; - } - } - - /// 从连通性结果中挑出最具代表性的传输类型 / - /// Picks the most representative transport from the raw results. - static NetworkType _resolveType(List types) { - const priority = [ - NetworkType.wifi, - NetworkType.ethernet, - NetworkType.mobile, - NetworkType.bluetooth, - NetworkType.other, - NetworkType.vpn, - ]; - for (final candidate in priority) { - if (types.contains(candidate)) return candidate; - } - return NetworkType.none; - } - - /// 通过 `dart:io` 读取 IP / IPv6 / MAC 作为跨平台兜底 / - /// Reads IP, IPv6 and MAC through `dart:io` as a cross-platform fallback. - static Future<_InterfaceSnapshot> _dartInterfaceSnapshot() async { - try { - final interfaces = await NetworkInterface.list( - includeLoopback: false, - includeLinkLocal: false, - type: InternetAddressType.any, - ); - - _InterfaceSnapshot snapshot = const _InterfaceSnapshot(); - for (final interface in interfaces) { - final ipv4 = _firstOf(interface.addresses, InternetAddressType.IPv4); - final ipv6 = _firstOf(interface.addresses, InternetAddressType.IPv6); - final candidate = _InterfaceSnapshot( - ipAddress: ipv4, - ipv6Address: ipv6, - ); - if (snapshot.ipAddress == null) { - snapshot = candidate; - } - // 优先保留带 IPv4 的接口 / Prefer an interface that owns an IPv4. - if (ipv4 != null && interface.name != 'lo') break; - } - return snapshot; - } catch (_) { - return const _InterfaceSnapshot(); - } - } - - static String? _firstOf( - List addresses, - InternetAddressType type, - ) { - for (final address in addresses) { - if (address.type == type) { - final raw = address.address; - return type == InternetAddressType.IPv6 ? raw.split('%').first : raw; - } - } - return null; - } - - static String? _asString(Object? value) { - if (value == null) return null; - final text = value.toString().trim(); - return text.isEmpty ? null : text; - } - - static Future _defaultReachabilityProbe() async { - final addresses = await InternetAddress.lookup('one.one.one.one'); - return addresses.isNotEmpty; - } -} - -/// `dart:io` 网卡快照 / Snapshot derived from `dart:io` network interfaces. -/// -/// `dart:io` 不暴露 MAC 地址,该字段只能由原生通道提供 / -/// `dart:io` does not expose the MAC address, so it can only come from the -/// native channel. -class _InterfaceSnapshot { - const _InterfaceSnapshot({this.ipAddress, this.ipv6Address}); - - final String? ipAddress; - final String? ipv6Address; -} +// 连通性检测与网络信息采集服务 / Connectivity detection and network information +// service. +// +// 依据平台条件导出实现:原生平台使用 `dart:io` 版本,Web 使用基于 +// `connectivity_plus` 与 HTTP 探测的版本 / +// Conditionally exports the implementation: the native build uses the `dart:io` +// variant, while the web build uses the `connectivity_plus` + HTTP variant. +export 'connectivity_service_io.dart' + if (dart.library.html) 'connectivity_service_web.dart'; diff --git a/lib/src/services/connectivity_service_io.dart b/lib/src/services/connectivity_service_io.dart new file mode 100644 index 0000000..89ed136 --- /dev/null +++ b/lib/src/services/connectivity_service_io.dart @@ -0,0 +1,227 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:connectivity_plus/connectivity_plus.dart'; + +import '../../zero_network_kit_platform_interface.dart'; +import '../models/network_connection_info.dart'; +import '../models/network_type.dart'; + +/// 连接类型数据源抽象 / Abstraction over the platform connectivity source. +/// +/// 默认由 `connectivity_plus` 实现,单元测试可注入假实现 / +/// Implemented by `connectivity_plus` by default; unit tests can inject fakes. +abstract class ConnectivityAdapter { + /// 读取当前连接类型(如 `['wifi']`)/ Reads the current transports, e.g. + /// `['wifi']`. + Future> checkConnectivity(); + + /// 监听连接类型变化 / Emits whenever the transports change. + Stream> get onConnectivityChanged; +} + +/// 基于 `connectivity_plus` 的默认适配器 / +/// Default adapter backed by `connectivity_plus`. +class ConnectivityPlusAdapter implements ConnectivityAdapter { + /// 构造 [ConnectivityPlusAdapter] / Creates a [ConnectivityPlusAdapter]. + ConnectivityPlusAdapter([Connectivity? connectivity]) + : _connectivity = connectivity ?? Connectivity(); + + final Connectivity _connectivity; + + @override + Future> checkConnectivity() async { + final results = await _connectivity.checkConnectivity(); + return _names(results); + } + + @override + Stream> get onConnectivityChanged => + _connectivity.onConnectivityChanged.map(_names); + + List _names(List results) => + results.map((result) => result.name).toList(growable: false); +} + +/// 连通性检测与网络信息采集服务 / +/// Connectivity detection and network information service. +class ConnectivityService { + /// 构造 [ConnectivityService] / Creates a [ConnectivityService]. + ConnectivityService({ConnectivityAdapter? adapter}) + : _adapter = adapter ?? ConnectivityPlusAdapter(); + + final ConnectivityAdapter _adapter; + + /// 主动可达性探测实现 / Reachability probe used when explicitly requested. + /// + /// 默认通过系统解析器查询 `one.one.one.one` / Defaults to resolving + /// `one.one.one.one` through the platform resolver. + Future Function() reachabilityProbe = _defaultReachabilityProbe; + + /// 采集一次网络连接快照 / Captures one network connection snapshot. + /// + /// [includeNativeDetails] 为 `true` 时会调用原生通道获取 SSID、网关、MAC 等 + /// 信息(失败时静默降级)/ When [includeNativeDetails] is `true` an extra + /// platform-channel call enriches the snapshot with SSID, gateway and MAC + /// (silently degrades on failure). + /// [probeReachability] 为 `true` 时会额外执行主动连通性探测 / + /// [probeReachability] additionally performs an active reachability probe. + Future checkConnection({ + bool includeNativeDetails = true, + bool probeReachability = false, + Duration probeTimeout = const Duration(seconds: 3), + }) async { + final transports = await _safeTransports(); + final types = transports + .map(NetworkType.fromRaw) + .where((type) => type != NetworkType.none) + .toList(growable: false); + + Map? native; + if (includeNativeDetails) { + native = await _safeNativeDetails(); + } + + final fallback = await _dartInterfaceSnapshot(); + + final ipAddress = + _asString(native?['ipAddress']) ?? + fallback.ipAddress ?? + _asString(native?['ipv6Address']) ?? + fallback.ipv6Address; + + final info = NetworkConnectionInfo( + isConnected: types.isNotEmpty || ipAddress != null, + type: _resolveType(types), + ssid: _asString(native?['ssid']), + signalStrength: (native?['signalStrength'] as num?)?.toInt(), + ipAddress: _asString(native?['ipAddress']) ?? fallback.ipAddress, + ipv6Address: _asString(native?['ipv6Address']) ?? fallback.ipv6Address, + gateway: _asString(native?['gateway']), + macAddress: _asString(native?['macAddress']), + isVpn: native?['isVpn'] == true || types.contains(NetworkType.vpn), + timestamp: DateTime.now(), + ); + + if (!probeReachability) return info; + return info.copyWith(isReachable: await _safeProbe(probeTimeout)); + } + + /// 监听网络连接变化 / Emits a fresh snapshot whenever connectivity changes. + /// + /// 立即发出一次当前状态,随后在每次底层变化时重新采集 / + /// Emits the current state immediately, then re-samples on every change. + Stream get onConnectivityChanged async* { + yield await checkConnection(); + await for (final _ in _adapter.onConnectivityChanged) { + yield await checkConnection(); + } + } + + Future> _safeTransports() async { + try { + return await _adapter.checkConnectivity(); + } catch (_) { + return const []; + } + } + + Future?> _safeNativeDetails() async { + try { + return await ZeroNetworkKitPlatform.instance.getNetworkDetails(); + } catch (_) { + return null; + } + } + + Future _safeProbe(Duration timeout) async { + try { + return await reachabilityProbe().timeout(timeout); + } catch (_) { + return false; + } + } + + /// 从连通性结果中挑出最具代表性的传输类型 / + /// Picks the most representative transport from the raw results. + static NetworkType _resolveType(List types) { + const priority = [ + NetworkType.wifi, + NetworkType.ethernet, + NetworkType.mobile, + NetworkType.bluetooth, + NetworkType.other, + NetworkType.vpn, + ]; + for (final candidate in priority) { + if (types.contains(candidate)) return candidate; + } + return NetworkType.none; + } + + /// 通过 `dart:io` 读取 IP / IPv6 / MAC 作为跨平台兜底 / + /// Reads IP, IPv6 and MAC through `dart:io` as a cross-platform fallback. + static Future<_InterfaceSnapshot> _dartInterfaceSnapshot() async { + try { + final interfaces = await NetworkInterface.list( + includeLoopback: false, + includeLinkLocal: false, + type: InternetAddressType.any, + ); + + _InterfaceSnapshot snapshot = const _InterfaceSnapshot(); + for (final interface in interfaces) { + final ipv4 = _firstOf(interface.addresses, InternetAddressType.IPv4); + final ipv6 = _firstOf(interface.addresses, InternetAddressType.IPv6); + final candidate = _InterfaceSnapshot( + ipAddress: ipv4, + ipv6Address: ipv6, + ); + if (snapshot.ipAddress == null) { + snapshot = candidate; + } + // 优先保留带 IPv4 的接口 / Prefer an interface that owns an IPv4. + if (ipv4 != null && interface.name != 'lo') break; + } + return snapshot; + } catch (_) { + return const _InterfaceSnapshot(); + } + } + + static String? _firstOf( + List addresses, + InternetAddressType type, + ) { + for (final address in addresses) { + if (address.type == type) { + final raw = address.address; + return type == InternetAddressType.IPv6 ? raw.split('%').first : raw; + } + } + return null; + } + + static String? _asString(Object? value) { + if (value == null) return null; + final text = value.toString().trim(); + return text.isEmpty ? null : text; + } + + static Future _defaultReachabilityProbe() async { + final addresses = await InternetAddress.lookup('one.one.one.one'); + return addresses.isNotEmpty; + } +} + +/// `dart:io` 网卡快照 / Snapshot derived from `dart:io` network interfaces. +/// +/// `dart:io` 不暴露 MAC 地址,该字段只能由原生通道提供 / +/// `dart:io` does not expose the MAC address, so it can only come from the +/// native channel. +class _InterfaceSnapshot { + const _InterfaceSnapshot({this.ipAddress, this.ipv6Address}); + + final String? ipAddress; + final String? ipv6Address; +} diff --git a/lib/src/services/connectivity_service_web.dart b/lib/src/services/connectivity_service_web.dart new file mode 100644 index 0000000..f74bb62 --- /dev/null +++ b/lib/src/services/connectivity_service_web.dart @@ -0,0 +1,170 @@ +import 'dart:async'; + +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:http/http.dart' as http; + +import '../../zero_network_kit_platform_interface.dart'; +import '../models/network_connection_info.dart'; +import '../models/network_type.dart'; + +/// 连接类型数据源抽象 / Abstraction over the platform connectivity source. +/// +/// 默认由 `connectivity_plus` 实现,单元测试可注入假实现 / +/// Implemented by `connectivity_plus` by default; unit tests can inject fakes. +abstract class ConnectivityAdapter { + /// 读取当前连接类型(如 `['wifi']`)/ Reads the current transports, e.g. + /// `['wifi']`. + Future> checkConnectivity(); + + /// 监听连接类型变化 / Emits whenever the transports change. + Stream> get onConnectivityChanged; +} + +/// 基于 `connectivity_plus` 的默认适配器 / +/// Default adapter backed by `connectivity_plus`. +class ConnectivityPlusAdapter implements ConnectivityAdapter { + /// 构造 [ConnectivityPlusAdapter] / Creates a [ConnectivityPlusAdapter]. + ConnectivityPlusAdapter([Connectivity? connectivity]) + : _connectivity = connectivity ?? Connectivity(); + + final Connectivity _connectivity; + + @override + Future> checkConnectivity() async { + final results = await _connectivity.checkConnectivity(); + return _names(results); + } + + @override + Stream> get onConnectivityChanged => + _connectivity.onConnectivityChanged.map(_names); + + List _names(List results) => + results.map((result) => result.name).toList(growable: false); +} + +/// Web 端连通性检测与网络信息采集服务 / +/// Connectivity detection and network information service for the web platform. +/// +/// 浏览器无法枚举网卡(无 `dart:io`),因此 IP / 网关 / MAC 等字段恒为 `null`; +/// 主动可达性探测改为对公共端点发起 HTTP 请求 / +/// Browsers cannot enumerate network interfaces (no `dart:io`), so IP / gateway / +/// MAC fields are always `null`; the reachability probe performs an HTTP request +/// against a public endpoint instead. +class ConnectivityService { + /// 构造 [ConnectivityService] / Creates a [ConnectivityService]. + ConnectivityService({ConnectivityAdapter? adapter}) + : _adapter = adapter ?? ConnectivityPlusAdapter(); + + final ConnectivityAdapter _adapter; + + /// 主动可达性探测实现 / Reachability probe used when explicitly requested. + /// + /// Web 端通过 HTTP 请求公共端点来判定连通性 / + /// On the web a public endpoint is probed over HTTP to decide reachability. + Future Function() reachabilityProbe = _defaultReachabilityProbe; + + /// 采集一次网络连接快照 / Captures one network connection snapshot. + Future checkConnection({ + bool includeNativeDetails = true, + bool probeReachability = false, + Duration probeTimeout = const Duration(seconds: 3), + }) async { + final transports = await _safeTransports(); + final types = transports + .map(NetworkType.fromRaw) + .where((type) => type != NetworkType.none) + .toList(growable: false); + + Map? native; + if (includeNativeDetails) { + native = await _safeNativeDetails(); + } + + final info = NetworkConnectionInfo( + isConnected: types.isNotEmpty, + type: _resolveType(types), + ssid: _asString(native?['ssid']), + signalStrength: (native?['signalStrength'] as num?)?.toInt(), + ipAddress: _asString(native?['ipAddress']), + ipv6Address: _asString(native?['ipv6Address']), + gateway: _asString(native?['gateway']), + macAddress: _asString(native?['macAddress']), + isVpn: native?['isVpn'] == true || types.contains(NetworkType.vpn), + timestamp: DateTime.now(), + ); + + if (!probeReachability) return info; + return info.copyWith(isReachable: await _safeProbe(probeTimeout)); + } + + /// 监听网络连接变化 / Emits a fresh snapshot whenever connectivity changes. + Stream get onConnectivityChanged async* { + yield await checkConnection(); + await for (final _ in _adapter.onConnectivityChanged) { + yield await checkConnection(); + } + } + + Future> _safeTransports() async { + try { + return await _adapter.checkConnectivity(); + } catch (_) { + return const []; + } + } + + Future?> _safeNativeDetails() async { + try { + return await ZeroNetworkKitPlatform.instance.getNetworkDetails(); + } catch (_) { + return null; + } + } + + Future _safeProbe(Duration timeout) async { + try { + return await reachabilityProbe().timeout(timeout); + } catch (_) { + return false; + } + } + + /// 从连通性结果中挑出最具代表性的传输类型 / + /// Picks the most representative transport from the raw results. + static NetworkType _resolveType(List types) { + const priority = [ + NetworkType.wifi, + NetworkType.ethernet, + NetworkType.mobile, + NetworkType.bluetooth, + NetworkType.other, + NetworkType.vpn, + ]; + for (final candidate in priority) { + if (types.contains(candidate)) return candidate; + } + return NetworkType.none; + } + + static String? _asString(Object? value) { + if (value == null) return null; + final text = value.toString().trim(); + return text.isEmpty ? null : text; + } + + /// 通过 HTTP 请求公共端点判定连通性 / Decides reachability via an HTTP probe. + static Future _defaultReachabilityProbe() async { + final client = http.Client(); + try { + final response = await client + .get(Uri.parse('https://one.one.one.one/cdn-cgi/trace')) + .timeout(const Duration(seconds: 5)); + return response.statusCode >= 200 && response.statusCode < 400; + } catch (_) { + return false; + } finally { + client.close(); + } + } +} diff --git a/lib/src/services/dns_service.dart b/lib/src/services/dns_service.dart index e87d418..99d87da 100644 --- a/lib/src/services/dns_service.dart +++ b/lib/src/services/dns_service.dart @@ -1,220 +1,7 @@ -import 'dart:async'; -import 'dart:io'; - -import '../dns/dns_packet.dart'; -import '../models/dns_test_result.dart'; - -/// DNS 解析测试服务 / DNS resolution test service. -/// -/// 支持两种解析路径 / Two resolution paths are supported: -/// - 系统解析器(`InternetAddress.lookup`)/ the platform resolver; -/// - 指定 DNS 服务器的原始 UDP 查询(自实现报文编解码)/ -/// raw UDP queries against explicit DNS servers, using the built-in codec. -class DnsService { - /// 构造 [DnsService] / Creates a [DnsService]. - const DnsService({this.defaultTimeout = const Duration(seconds: 5)}); - - /// 单次查询默认超时 / Default timeout of a single query. - final Duration defaultTimeout; - - /// 依次/并发测试多台 DNS 服务器 / Tests multiple DNS servers. - /// - /// [concurrent] 为 `true`(默认)时并发查询;为 `false` 时按顺序查询,可用于 - /// 规避部分网络对并发 UDP 的限制 / [concurrent] queries in parallel by - /// default; set it to `false` to serialise them. - /// [includeSystemResolver] 为 `true` 时额外加入一条系统解析器结果 / - /// [includeSystemResolver] also appends a platform-resolver result. - Future> testDns({ - String domain = 'www.google.com', - List dnsServers = const [ - '1.1.1.1', - '8.8.8.8', - '114.114.114.114', - ], - Duration? timeout, - bool concurrent = true, - bool includeSystemResolver = false, - }) async { - final servers = [ - if (includeSystemResolver) 'system', - ...dnsServers, - ]; - if (servers.isEmpty) return const []; - - if (concurrent) { - return Future.wait( - servers.map( - (server) => query(domain: domain, server: server, timeout: timeout), - ), - ); - } - - final results = []; - for (final server in servers) { - results.add( - await query(domain: domain, server: server, timeout: timeout), - ); - } - return results; - } - - /// 查询单个 DNS 服务器 / Queries a single DNS server. - /// - /// [server] 传 `system` 时走系统解析器 / Pass `system` as [server] to use the - /// platform resolver. - Future query({ - required String domain, - required String server, - Duration? timeout, - }) { - if (server.toLowerCase() == 'system') { - return resolveWithSystemResolver(domain: domain, timeout: timeout); - } - return _queryUdp( - domain: domain, - server: server, - timeout: timeout ?? defaultTimeout, - ); - } - - /// 使用系统解析器解析域名 / Resolves a domain through the platform resolver. - Future resolveWithSystemResolver({ - required String domain, - Duration? timeout, - }) async { - final stopwatch = Stopwatch()..start(); - try { - final addresses = await InternetAddress.lookup( - domain, - ).timeout(timeout ?? defaultTimeout); - stopwatch.stop(); - return DnsTestResult( - server: 'system', - domain: domain, - isSuccess: addresses.isNotEmpty, - responseTime: stopwatch.elapsed, - resolvedIps: addresses - .map((address) => address.address) - .toList(growable: false), - timestamp: DateTime.now(), - errorMessage: addresses.isEmpty ? 'No address returned' : null, - ); - } catch (error) { - stopwatch.stop(); - return DnsTestResult( - server: 'system', - domain: domain, - isSuccess: false, - responseTime: stopwatch.elapsed, - errorMessage: error.toString(), - timestamp: DateTime.now(), - ); - } - } - - Future _queryUdp({ - required String domain, - required String server, - required Duration timeout, - }) async { - final stopwatch = Stopwatch()..start(); - RawDatagramSocket? socket; - StreamSubscription? subscription; - Timer? timer; - - try { - final target = await _resolveServer(server).timeout(timeout); - socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0); - final udp = socket; - final id = DnsPacket.randomId(); - final payload = DnsPacket.encodeQuery(domain, id: id); - final completer = Completer(); - - subscription = udp.listen( - (event) { - if (event != RawSocketEvent.read) return; - final datagram = udp.receive(); - if (datagram == null) return; - try { - final response = DnsPacket.parse(datagram.data); - if (response.id != id) return; - if (!completer.isCompleted) completer.complete(response); - } catch (error) { - if (!completer.isCompleted) completer.completeError(error); - } - }, - onError: (Object error, StackTrace stackTrace) { - if (!completer.isCompleted) { - completer.completeError(error, stackTrace); - } - }, - ); - - timer = Timer(timeout, () { - if (!completer.isCompleted) { - completer.completeError( - TimeoutException('DNS query to $server timed out', timeout), - ); - } - }); - - udp.send(payload, target, 53); - - final response = await completer.future.timeout( - timeout, - onTimeout: () => - throw TimeoutException('DNS query to $server timed out', timeout), - ); - stopwatch.stop(); - - if (response.responseCode != 0) { - return DnsTestResult( - server: server, - domain: domain, - isSuccess: false, - responseTime: stopwatch.elapsed, - errorMessage: 'DNS server returned RCODE ${response.responseCode}', - timestamp: DateTime.now(), - ); - } - - return DnsTestResult( - server: server, - domain: domain, - isSuccess: response.isSuccess, - responseTime: stopwatch.elapsed, - resolvedIps: response.addresses, - timestamp: DateTime.now(), - errorMessage: response.isSuccess - ? null - : (response.truncated - ? 'Response truncated; retry over TCP' - : 'No A/AAAA record in the answer section'), - ); - } catch (error) { - stopwatch.stop(); - return DnsTestResult( - server: server, - domain: domain, - isSuccess: false, - responseTime: stopwatch.elapsed, - errorMessage: error.toString(), - timestamp: DateTime.now(), - ); - } finally { - timer?.cancel(); - await subscription?.cancel(); - socket?.close(); - } - } - - static Future _resolveServer(String server) async { - final parsed = InternetAddress.tryParse(server); - if (parsed != null) return parsed; - final addresses = await InternetAddress.lookup(server); - if (addresses.isEmpty) { - throw SocketException('Cannot resolve DNS server: $server'); - } - return addresses.first; - } -} +// DNS 解析测试服务 / DNS resolution test service. +// +// 依据平台条件导出实现:原生平台使用 `dart:io`(系统解析器 + 原始 UDP)版本, +// Web 使用基于 DNS-over-HTTPS 的版本 / Conditionally exports the implementation: +// the native build uses the `dart:io` (system resolver + raw UDP) variant, while +// the web build uses the DNS-over-HTTPS variant. +export 'dns_service_io.dart' if (dart.library.html) 'dns_service_web.dart'; diff --git a/lib/src/services/dns_service_io.dart b/lib/src/services/dns_service_io.dart new file mode 100644 index 0000000..e87d418 --- /dev/null +++ b/lib/src/services/dns_service_io.dart @@ -0,0 +1,220 @@ +import 'dart:async'; +import 'dart:io'; + +import '../dns/dns_packet.dart'; +import '../models/dns_test_result.dart'; + +/// DNS 解析测试服务 / DNS resolution test service. +/// +/// 支持两种解析路径 / Two resolution paths are supported: +/// - 系统解析器(`InternetAddress.lookup`)/ the platform resolver; +/// - 指定 DNS 服务器的原始 UDP 查询(自实现报文编解码)/ +/// raw UDP queries against explicit DNS servers, using the built-in codec. +class DnsService { + /// 构造 [DnsService] / Creates a [DnsService]. + const DnsService({this.defaultTimeout = const Duration(seconds: 5)}); + + /// 单次查询默认超时 / Default timeout of a single query. + final Duration defaultTimeout; + + /// 依次/并发测试多台 DNS 服务器 / Tests multiple DNS servers. + /// + /// [concurrent] 为 `true`(默认)时并发查询;为 `false` 时按顺序查询,可用于 + /// 规避部分网络对并发 UDP 的限制 / [concurrent] queries in parallel by + /// default; set it to `false` to serialise them. + /// [includeSystemResolver] 为 `true` 时额外加入一条系统解析器结果 / + /// [includeSystemResolver] also appends a platform-resolver result. + Future> testDns({ + String domain = 'www.google.com', + List dnsServers = const [ + '1.1.1.1', + '8.8.8.8', + '114.114.114.114', + ], + Duration? timeout, + bool concurrent = true, + bool includeSystemResolver = false, + }) async { + final servers = [ + if (includeSystemResolver) 'system', + ...dnsServers, + ]; + if (servers.isEmpty) return const []; + + if (concurrent) { + return Future.wait( + servers.map( + (server) => query(domain: domain, server: server, timeout: timeout), + ), + ); + } + + final results = []; + for (final server in servers) { + results.add( + await query(domain: domain, server: server, timeout: timeout), + ); + } + return results; + } + + /// 查询单个 DNS 服务器 / Queries a single DNS server. + /// + /// [server] 传 `system` 时走系统解析器 / Pass `system` as [server] to use the + /// platform resolver. + Future query({ + required String domain, + required String server, + Duration? timeout, + }) { + if (server.toLowerCase() == 'system') { + return resolveWithSystemResolver(domain: domain, timeout: timeout); + } + return _queryUdp( + domain: domain, + server: server, + timeout: timeout ?? defaultTimeout, + ); + } + + /// 使用系统解析器解析域名 / Resolves a domain through the platform resolver. + Future resolveWithSystemResolver({ + required String domain, + Duration? timeout, + }) async { + final stopwatch = Stopwatch()..start(); + try { + final addresses = await InternetAddress.lookup( + domain, + ).timeout(timeout ?? defaultTimeout); + stopwatch.stop(); + return DnsTestResult( + server: 'system', + domain: domain, + isSuccess: addresses.isNotEmpty, + responseTime: stopwatch.elapsed, + resolvedIps: addresses + .map((address) => address.address) + .toList(growable: false), + timestamp: DateTime.now(), + errorMessage: addresses.isEmpty ? 'No address returned' : null, + ); + } catch (error) { + stopwatch.stop(); + return DnsTestResult( + server: 'system', + domain: domain, + isSuccess: false, + responseTime: stopwatch.elapsed, + errorMessage: error.toString(), + timestamp: DateTime.now(), + ); + } + } + + Future _queryUdp({ + required String domain, + required String server, + required Duration timeout, + }) async { + final stopwatch = Stopwatch()..start(); + RawDatagramSocket? socket; + StreamSubscription? subscription; + Timer? timer; + + try { + final target = await _resolveServer(server).timeout(timeout); + socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0); + final udp = socket; + final id = DnsPacket.randomId(); + final payload = DnsPacket.encodeQuery(domain, id: id); + final completer = Completer(); + + subscription = udp.listen( + (event) { + if (event != RawSocketEvent.read) return; + final datagram = udp.receive(); + if (datagram == null) return; + try { + final response = DnsPacket.parse(datagram.data); + if (response.id != id) return; + if (!completer.isCompleted) completer.complete(response); + } catch (error) { + if (!completer.isCompleted) completer.completeError(error); + } + }, + onError: (Object error, StackTrace stackTrace) { + if (!completer.isCompleted) { + completer.completeError(error, stackTrace); + } + }, + ); + + timer = Timer(timeout, () { + if (!completer.isCompleted) { + completer.completeError( + TimeoutException('DNS query to $server timed out', timeout), + ); + } + }); + + udp.send(payload, target, 53); + + final response = await completer.future.timeout( + timeout, + onTimeout: () => + throw TimeoutException('DNS query to $server timed out', timeout), + ); + stopwatch.stop(); + + if (response.responseCode != 0) { + return DnsTestResult( + server: server, + domain: domain, + isSuccess: false, + responseTime: stopwatch.elapsed, + errorMessage: 'DNS server returned RCODE ${response.responseCode}', + timestamp: DateTime.now(), + ); + } + + return DnsTestResult( + server: server, + domain: domain, + isSuccess: response.isSuccess, + responseTime: stopwatch.elapsed, + resolvedIps: response.addresses, + timestamp: DateTime.now(), + errorMessage: response.isSuccess + ? null + : (response.truncated + ? 'Response truncated; retry over TCP' + : 'No A/AAAA record in the answer section'), + ); + } catch (error) { + stopwatch.stop(); + return DnsTestResult( + server: server, + domain: domain, + isSuccess: false, + responseTime: stopwatch.elapsed, + errorMessage: error.toString(), + timestamp: DateTime.now(), + ); + } finally { + timer?.cancel(); + await subscription?.cancel(); + socket?.close(); + } + } + + static Future _resolveServer(String server) async { + final parsed = InternetAddress.tryParse(server); + if (parsed != null) return parsed; + final addresses = await InternetAddress.lookup(server); + if (addresses.isEmpty) { + throw SocketException('Cannot resolve DNS server: $server'); + } + return addresses.first; + } +} diff --git a/lib/src/services/dns_service_web.dart b/lib/src/services/dns_service_web.dart new file mode 100644 index 0000000..08ab8f5 --- /dev/null +++ b/lib/src/services/dns_service_web.dart @@ -0,0 +1,178 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:http/http.dart' as http; + +import '../models/dns_test_result.dart'; + +/// Web 端 DNS 解析测试服务 / DNS resolution service for the web platform. +/// +/// 浏览器禁止原始 UDP 套接字,因此: +/// - 系统解析器退化为通过 DNS-over-HTTPS (DoH) 解析; +/// - 显式 DNS 服务器若提供已知 DoH 端点(如 1.1.1.1 / 8.8.8.8)则走 DoH, +/// 否则(如 114.114.114.114)返回“不支持”结果 / +/// Browsers forbid raw UDP sockets, so on the web: +/// - the platform resolver degrades to DNS-over-HTTPS (DoH); +/// - explicit servers with a known DoH endpoint (e.g. 1.1.1.1 / 8.8.8.8) use DoH, +/// while others (e.g. 114.114.114.114) report "unsupported". +class DnsService { + /// 构造 [DnsService] / Creates a [DnsService]. + const DnsService({this.defaultTimeout = const Duration(seconds: 5)}); + + /// 单次查询默认超时 / Default timeout of a single query. + final Duration defaultTimeout; + + /// 依次/并发测试多台 DNS 服务器 / Tests multiple DNS servers. + Future> testDns({ + String domain = 'www.google.com', + List dnsServers = const [ + '1.1.1.1', + '8.8.8.8', + '114.114.114.114', + ], + Duration? timeout, + bool concurrent = true, + bool includeSystemResolver = false, + }) async { + final servers = [ + if (includeSystemResolver) 'system', + ...dnsServers, + ]; + if (servers.isEmpty) return const []; + + if (concurrent) { + return Future.wait( + servers.map( + (server) => query(domain: domain, server: server, timeout: timeout), + ), + ); + } + + final results = []; + for (final server in servers) { + results.add( + await query(domain: domain, server: server, timeout: timeout), + ); + } + return results; + } + + /// 查询单个 DNS 服务器 / Queries a single DNS server. + Future query({ + required String domain, + required String server, + Duration? timeout, + }) { + if (server.toLowerCase() == 'system') { + return resolveWithSystemResolver(domain: domain, timeout: timeout); + } + final doh = _dohForServer(server); + if (doh == null) { + return Future.value( + DnsTestResult( + server: server, + domain: domain, + isSuccess: false, + responseTime: Duration.zero, + errorMessage: + 'Raw UDP DNS is unavailable on the web; this server has no DoH ' + 'endpoint.', + timestamp: DateTime.now(), + ), + ); + } + return _queryDoH( + domain: domain, + dohUrl: doh, + timeout: timeout ?? defaultTimeout, + serverLabel: server, + ); + } + + /// 使用系统解析器解析域名(Web 端通过 DoH 实现)/ + /// Resolves a domain through the platform resolver (DoH on the web). + Future resolveWithSystemResolver({ + required String domain, + Duration? timeout, + }) { + return _queryDoH( + domain: domain, + dohUrl: 'https://cloudflare-dns.com/dns-query', + timeout: timeout ?? defaultTimeout, + serverLabel: 'system', + ); + } + + /// 将知名 DNS 服务器映射到其 DoH 端点 / Maps well-known DNS servers to DoH. + static String? _dohForServer(String server) { + switch (server) { + case '1.1.1.1': + case '1.0.0.1': + return 'https://cloudflare-dns.com/dns-query'; + case '8.8.8.8': + case '8.8.4.4': + return 'https://dns.google/dns-query'; + default: + return 'https://$server/dns-query'; + } + } + + /// 通过 DNS-over-HTTPS (JSON) 查询域名 / Resolves a domain over DoH (JSON). + Future _queryDoH({ + required String domain, + required String dohUrl, + required Duration timeout, + required String serverLabel, + }) async { + final stopwatch = Stopwatch()..start(); + final client = http.Client(); + try { + final response = await client + .get( + Uri.parse('$dohUrl?name=$domain&type=A'), + headers: {'Accept': 'application/dns-json'}, + ) + .timeout(timeout); + stopwatch.stop(); + if (response.statusCode != 200) { + return DnsTestResult( + server: serverLabel, + domain: domain, + isSuccess: false, + responseTime: stopwatch.elapsed, + errorMessage: 'DoH returned HTTP ${response.statusCode}', + timestamp: DateTime.now(), + ); + } + final json = jsonDecode(response.body) as Map; + final answers = + (json['Answer'] as List?)?.cast>() ?? + const >[]; + final ips = answers + .where((answer) => answer['type'] == 1 || answer['type'] == 28) + .map((answer) => answer['data'].toString()) + .toList(growable: false); + return DnsTestResult( + server: serverLabel, + domain: domain, + isSuccess: ips.isNotEmpty, + responseTime: stopwatch.elapsed, + resolvedIps: ips, + timestamp: DateTime.now(), + errorMessage: ips.isEmpty ? 'No A/AAAA record returned' : null, + ); + } catch (error) { + stopwatch.stop(); + return DnsTestResult( + server: serverLabel, + domain: domain, + isSuccess: false, + responseTime: stopwatch.elapsed, + errorMessage: error.toString(), + timestamp: DateTime.now(), + ); + } finally { + client.close(); + } + } +} diff --git a/lib/src/services/ping_service.dart b/lib/src/services/ping_service.dart index f2da05d..a3dfb7b 100644 --- a/lib/src/services/ping_service.dart +++ b/lib/src/services/ping_service.dart @@ -1,159 +1,7 @@ -import 'dart:async'; -import 'dart:io'; -import 'dart:math' as math; - -import '../models/ping_result.dart'; - -/// 网络延迟(Ping)测试服务 / Network latency (ping) test service. -/// -/// 默认使用 TCP 握手往返测量,跨平台且无需特殊权限;桌面端可选择使用系统 -/// ICMP `ping` 命令 / TCP handshake timing is used by default: it works on every -/// platform without extra privileges. Desktop platforms may opt into the system -/// ICMP `ping` command instead. -class PingService { - /// 构造 [PingService] / Creates a [PingService]. - const PingService({this.defaultPort = 443}); - - /// TCP 模式下默认探测端口 / Default probe port in TCP mode. - final int defaultPort; - - /// 执行 Ping 测试 / Runs a ping test. - /// - /// [count] 为探测次数,[interval] 为两次探测之间的间隔 / - /// [count] is the number of probes, [interval] the delay between them. - /// [mode] 为 [PingMode.icmp] 时仅桌面端可用,其它平台抛出 - /// [UnsupportedError] / [PingMode.icmp] is desktop-only and throws - /// [UnsupportedError] elsewhere. - Future ping({ - required String host, - int count = 4, - Duration timeout = const Duration(seconds: 3), - Duration interval = const Duration(milliseconds: 200), - int? port, - PingMode mode = PingMode.tcp, - }) async { - if (count <= 0) { - return PingResult( - host: host, - sent: 0, - received: 0, - times: const [], - timestamp: DateTime.now(), - port: port ?? defaultPort, - mode: mode, - ); - } - - if (mode == PingMode.icmp) { - return _icmpPing(host: host, count: count, timeout: timeout); - } - return _tcpPing( - host: host, - count: count, - timeout: timeout, - interval: interval, - port: port ?? defaultPort, - ); - } - - Future _tcpPing({ - required String host, - required int count, - required Duration timeout, - required Duration interval, - required int port, - }) async { - final times = []; - for (var i = 0; i < count; i++) { - if (i > 0 && interval > Duration.zero) { - await Future.delayed(interval); - } - final elapsed = await _probeTcp(host, port, timeout); - if (elapsed != null) times.add(elapsed); - } - - return PingResult( - host: host, - sent: count, - received: times.length, - times: times, - timestamp: DateTime.now(), - port: port, - mode: PingMode.tcp, - ); - } - - static Future _probeTcp( - String host, - int port, - Duration timeout, - ) async { - final stopwatch = Stopwatch()..start(); - Socket? socket; - try { - socket = await Socket.connect(host, port, timeout: timeout); - stopwatch.stop(); - return stopwatch.elapsedMicroseconds / 1000; - } catch (_) { - return null; - } finally { - socket?.destroy(); - } - } - - Future _icmpPing({ - required String host, - required int count, - required Duration timeout, - }) async { - if (!_systemPingSupported) { - throw UnsupportedError( - 'PingMode.icmp requires a desktop platform with a system ping ' - 'executable; use PingMode.tcp on mobile.', - ); - } - - final args = Platform.isWindows - ? ['-n', '$count', '-w', '${timeout.inMilliseconds}', host] - : [ - '-c', - '$count', - '-W', - '${math.max(1, timeout.inSeconds)}', - host, - ]; - - final process = await Process.run( - 'ping', - args, - ).timeout(timeout * count + const Duration(seconds: 5)); - final output = '${process.stdout}\n${process.stderr}'; - final times = _parseIcmpTimes(output); - - return PingResult( - host: host, - sent: count, - received: times.length, - times: times, - timestamp: DateTime.now(), - mode: PingMode.icmp, - ); - } - - /// 解析系统 ping 输出中的往返耗时(兼容中英文输出)/ - /// Extracts round trip times from system ping output (English and Chinese). - static List _parseIcmpTimes(String output) { - final pattern = RegExp( - r'(?:time|时间)[=<]\s*([0-9]+(?:\.[0-9]+)?)\s*ms', - caseSensitive: false, - ); - return pattern - .allMatches(output) - .map((match) => double.tryParse(match.group(1) ?? '') ?? double.nan) - .where((value) => !value.isNaN) - .toList(growable: false); - } - - static bool get _systemPingSupported => - !Platform.isAndroid && !Platform.isIOS && !Platform.isFuchsia; -} +// 网络延迟(Ping)测试服务 / Network latency (ping) test service. +// +// 依据平台条件导出实现:原生平台使用 `dart:io`(TCP/ICMP)版本,Web 使用基于 +// HTTPS 往返的退化版本 / Conditionally exports the implementation: the native +// build uses the `dart:io` (TCP/ICMP) variant, while the web build uses the +// HTTPS round-trip fallback. +export 'ping_service_io.dart' if (dart.library.html) 'ping_service_web.dart'; diff --git a/lib/src/services/ping_service_io.dart b/lib/src/services/ping_service_io.dart new file mode 100644 index 0000000..f2da05d --- /dev/null +++ b/lib/src/services/ping_service_io.dart @@ -0,0 +1,159 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:math' as math; + +import '../models/ping_result.dart'; + +/// 网络延迟(Ping)测试服务 / Network latency (ping) test service. +/// +/// 默认使用 TCP 握手往返测量,跨平台且无需特殊权限;桌面端可选择使用系统 +/// ICMP `ping` 命令 / TCP handshake timing is used by default: it works on every +/// platform without extra privileges. Desktop platforms may opt into the system +/// ICMP `ping` command instead. +class PingService { + /// 构造 [PingService] / Creates a [PingService]. + const PingService({this.defaultPort = 443}); + + /// TCP 模式下默认探测端口 / Default probe port in TCP mode. + final int defaultPort; + + /// 执行 Ping 测试 / Runs a ping test. + /// + /// [count] 为探测次数,[interval] 为两次探测之间的间隔 / + /// [count] is the number of probes, [interval] the delay between them. + /// [mode] 为 [PingMode.icmp] 时仅桌面端可用,其它平台抛出 + /// [UnsupportedError] / [PingMode.icmp] is desktop-only and throws + /// [UnsupportedError] elsewhere. + Future ping({ + required String host, + int count = 4, + Duration timeout = const Duration(seconds: 3), + Duration interval = const Duration(milliseconds: 200), + int? port, + PingMode mode = PingMode.tcp, + }) async { + if (count <= 0) { + return PingResult( + host: host, + sent: 0, + received: 0, + times: const [], + timestamp: DateTime.now(), + port: port ?? defaultPort, + mode: mode, + ); + } + + if (mode == PingMode.icmp) { + return _icmpPing(host: host, count: count, timeout: timeout); + } + return _tcpPing( + host: host, + count: count, + timeout: timeout, + interval: interval, + port: port ?? defaultPort, + ); + } + + Future _tcpPing({ + required String host, + required int count, + required Duration timeout, + required Duration interval, + required int port, + }) async { + final times = []; + for (var i = 0; i < count; i++) { + if (i > 0 && interval > Duration.zero) { + await Future.delayed(interval); + } + final elapsed = await _probeTcp(host, port, timeout); + if (elapsed != null) times.add(elapsed); + } + + return PingResult( + host: host, + sent: count, + received: times.length, + times: times, + timestamp: DateTime.now(), + port: port, + mode: PingMode.tcp, + ); + } + + static Future _probeTcp( + String host, + int port, + Duration timeout, + ) async { + final stopwatch = Stopwatch()..start(); + Socket? socket; + try { + socket = await Socket.connect(host, port, timeout: timeout); + stopwatch.stop(); + return stopwatch.elapsedMicroseconds / 1000; + } catch (_) { + return null; + } finally { + socket?.destroy(); + } + } + + Future _icmpPing({ + required String host, + required int count, + required Duration timeout, + }) async { + if (!_systemPingSupported) { + throw UnsupportedError( + 'PingMode.icmp requires a desktop platform with a system ping ' + 'executable; use PingMode.tcp on mobile.', + ); + } + + final args = Platform.isWindows + ? ['-n', '$count', '-w', '${timeout.inMilliseconds}', host] + : [ + '-c', + '$count', + '-W', + '${math.max(1, timeout.inSeconds)}', + host, + ]; + + final process = await Process.run( + 'ping', + args, + ).timeout(timeout * count + const Duration(seconds: 5)); + final output = '${process.stdout}\n${process.stderr}'; + final times = _parseIcmpTimes(output); + + return PingResult( + host: host, + sent: count, + received: times.length, + times: times, + timestamp: DateTime.now(), + mode: PingMode.icmp, + ); + } + + /// 解析系统 ping 输出中的往返耗时(兼容中英文输出)/ + /// Extracts round trip times from system ping output (English and Chinese). + static List _parseIcmpTimes(String output) { + final pattern = RegExp( + r'(?:time|时间)[=<]\s*([0-9]+(?:\.[0-9]+)?)\s*ms', + caseSensitive: false, + ); + return pattern + .allMatches(output) + .map((match) => double.tryParse(match.group(1) ?? '') ?? double.nan) + .where((value) => !value.isNaN) + .toList(growable: false); + } + + static bool get _systemPingSupported => + !Platform.isAndroid && !Platform.isIOS && !Platform.isFuchsia; +} diff --git a/lib/src/services/ping_service_web.dart b/lib/src/services/ping_service_web.dart new file mode 100644 index 0000000..9afa6c1 --- /dev/null +++ b/lib/src/services/ping_service_web.dart @@ -0,0 +1,119 @@ +import 'dart:async'; + +import 'package:http/http.dart' as http; + +import '../models/ping_result.dart'; + +/// Web 端网络延迟(Ping)测试服务 / Latency (ping) test service for the web. +/// +/// 浏览器无法建立任意 TCP / ICMP 连接,因此: +/// - [PingMode.tcp] 退化为对目标主机发起 HTTPS 请求并测量往返耗时; +/// - [PingMode.icmp] 在 Web 上不可用时抛出 [UnsupportedError] / +/// Browsers cannot open arbitrary TCP or ICMP connections, so on the web: +/// - [PingMode.tcp] degrades to measuring the round trip of an HTTPS request; +/// - [PingMode.icmp] is unavailable and throws [UnsupportedError]. +class PingService { + /// 构造 [PingService] / Creates a [PingService]. + const PingService({this.defaultPort = 443}); + + /// TCP 模式下默认探测端口 / Default probe port in TCP mode. + final int defaultPort; + + /// 执行 Ping 测试 / Runs a ping test. + Future ping({ + required String host, + int count = 4, + Duration timeout = const Duration(seconds: 3), + Duration interval = const Duration(milliseconds: 200), + int? port, + PingMode mode = PingMode.tcp, + }) async { + if (count <= 0) { + return PingResult( + host: host, + sent: 0, + received: 0, + times: const [], + timestamp: DateTime.now(), + port: port ?? defaultPort, + mode: mode, + ); + } + + if (mode == PingMode.icmp) { + return _icmpPing(); + } + return _tcpPing( + host: host, + count: count, + timeout: timeout, + interval: interval, + port: port ?? defaultPort, + ); + } + + Future _tcpPing({ + required String host, + required int count, + required Duration timeout, + required Duration interval, + required int port, + }) async { + final times = []; + for (var i = 0; i < count; i++) { + if (i > 0 && interval > Duration.zero) { + await Future.delayed(interval); + } + final elapsed = await _probeHttp(host, port, timeout); + if (elapsed != null) times.add(elapsed); + } + + return PingResult( + host: host, + sent: count, + received: times.length, + times: times, + timestamp: DateTime.now(), + port: port, + mode: PingMode.tcp, + ); + } + + /// 通过一次 HTTPS 请求测量往返耗时 / Measures the round trip via an HTTPS request. + /// + /// 失败(CORS、证书、网络错误)时返回 `null`,视为丢包 / Returns `null` on any + /// failure (CORS, certificate, network), which is treated as packet loss. + static Future _probeHttp( + String host, + int port, + Duration timeout, + ) async { + final uri = Uri( + scheme: port == 80 ? 'http' : 'https', + host: host, + port: port, + path: '/', + ); + final client = http.Client(); + final stopwatch = Stopwatch()..start(); + try { + final response = await client + .get(uri, headers: {'Cache-Control': 'no-cache'}) + .timeout(timeout); + stopwatch.stop(); + if (response.statusCode >= 400) return null; + return stopwatch.elapsedMicroseconds / 1000; + } catch (_) { + stopwatch.stop(); + return null; + } finally { + client.close(); + } + } + + Future _icmpPing() async { + throw UnsupportedError( + 'PingMode.icmp is unavailable on the web platform; use PingMode.tcp.', + ); + } +} diff --git a/lib/src/services/port_service.dart b/lib/src/services/port_service.dart index e5e6cf8..a9b7705 100644 --- a/lib/src/services/port_service.dart +++ b/lib/src/services/port_service.dart @@ -1,101 +1,8 @@ -import 'dart:async'; -import 'dart:io'; -import 'dart:math' as math; - -import '../models/port_check_result.dart'; - -/// TCP 端口连通性检测服务 / TCP port reachability service. -class PortService { - /// 构造 [PortService] / Creates a [PortService]. - const PortService({this.defaultTimeout = const Duration(seconds: 3)}); - - /// 单次连接默认超时 / Default timeout of a single connection attempt. - final Duration defaultTimeout; - - /// 检测单个端口是否可连接 / Checks whether a single port accepts connections. - Future checkPort({ - required String host, - required int port, - Duration? timeout, - }) async { - final effectiveTimeout = timeout ?? defaultTimeout; - final stopwatch = Stopwatch()..start(); - Socket? socket; - - try { - socket = await Socket.connect(host, port, timeout: effectiveTimeout); - stopwatch.stop(); - return PortCheckResult( - host: host, - port: port, - isOpen: true, - responseTime: stopwatch.elapsed, - timestamp: DateTime.now(), - ); - } catch (error) { - stopwatch.stop(); - return PortCheckResult( - host: host, - port: port, - isOpen: false, - responseTime: stopwatch.elapsed, - errorMessage: _describe(error), - timestamp: DateTime.now(), - ); - } finally { - socket?.destroy(); - } - } - - /// [checkPort] 的布尔快捷方式 / Boolean shorthand for [checkPort]. - Future isPortOpen({ - required String host, - required int port, - Duration? timeout, - }) async { - final result = await checkPort(host: host, port: port, timeout: timeout); - return result.isOpen; - } - - /// 并发扫描多个端口 / Scans multiple ports with bounded concurrency. - /// - /// 结果顺序与 [ports] 一致 / Results preserve the order of [ports]. - Future> scanPorts({ - required String host, - List ports = const [80, 443], - Duration? timeout, - int concurrency = 12, - }) async { - if (ports.isEmpty) return const []; - - final results = List.filled(ports.length, null); - var cursor = 0; - - Future worker() async { - while (true) { - final index = cursor; - cursor += 1; - if (index >= ports.length) return; - results[index] = await checkPort( - host: host, - port: ports[index], - timeout: timeout, - ); - } - } - - final workerCount = math.min(math.max(1, concurrency), ports.length); - await Future.wait( - List>.generate(workerCount, (_) => worker()), - ); - return results.whereType().toList(growable: false); - } - - static String _describe(Object error) { - if (error is TimeoutException) return 'Connection timed out'; - if (error is SocketException) { - return error.osError?.message ?? error.message; - } - return error.toString(); - } -} +// TCP 端口连通性检测服务 / TCP port reachability service. +// +// 依据平台条件导出实现:原生平台使用 `dart:io`(原始 TCP 套接字)版本,Web 上 +// 端口检测不可用,导出返回“不可用”结果的退化版本 / +// Conditionally exports the implementation: the native build uses the `dart:io` +// (raw TCP socket) variant, while the web build exports the variant that reports +// port checks as unavailable. +export 'port_service_io.dart' if (dart.library.html) 'port_service_web.dart'; diff --git a/lib/src/services/port_service_io.dart b/lib/src/services/port_service_io.dart new file mode 100644 index 0000000..e5e6cf8 --- /dev/null +++ b/lib/src/services/port_service_io.dart @@ -0,0 +1,101 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:math' as math; + +import '../models/port_check_result.dart'; + +/// TCP 端口连通性检测服务 / TCP port reachability service. +class PortService { + /// 构造 [PortService] / Creates a [PortService]. + const PortService({this.defaultTimeout = const Duration(seconds: 3)}); + + /// 单次连接默认超时 / Default timeout of a single connection attempt. + final Duration defaultTimeout; + + /// 检测单个端口是否可连接 / Checks whether a single port accepts connections. + Future checkPort({ + required String host, + required int port, + Duration? timeout, + }) async { + final effectiveTimeout = timeout ?? defaultTimeout; + final stopwatch = Stopwatch()..start(); + Socket? socket; + + try { + socket = await Socket.connect(host, port, timeout: effectiveTimeout); + stopwatch.stop(); + return PortCheckResult( + host: host, + port: port, + isOpen: true, + responseTime: stopwatch.elapsed, + timestamp: DateTime.now(), + ); + } catch (error) { + stopwatch.stop(); + return PortCheckResult( + host: host, + port: port, + isOpen: false, + responseTime: stopwatch.elapsed, + errorMessage: _describe(error), + timestamp: DateTime.now(), + ); + } finally { + socket?.destroy(); + } + } + + /// [checkPort] 的布尔快捷方式 / Boolean shorthand for [checkPort]. + Future isPortOpen({ + required String host, + required int port, + Duration? timeout, + }) async { + final result = await checkPort(host: host, port: port, timeout: timeout); + return result.isOpen; + } + + /// 并发扫描多个端口 / Scans multiple ports with bounded concurrency. + /// + /// 结果顺序与 [ports] 一致 / Results preserve the order of [ports]. + Future> scanPorts({ + required String host, + List ports = const [80, 443], + Duration? timeout, + int concurrency = 12, + }) async { + if (ports.isEmpty) return const []; + + final results = List.filled(ports.length, null); + var cursor = 0; + + Future worker() async { + while (true) { + final index = cursor; + cursor += 1; + if (index >= ports.length) return; + results[index] = await checkPort( + host: host, + port: ports[index], + timeout: timeout, + ); + } + } + + final workerCount = math.min(math.max(1, concurrency), ports.length); + await Future.wait( + List>.generate(workerCount, (_) => worker()), + ); + return results.whereType().toList(growable: false); + } + + static String _describe(Object error) { + if (error is TimeoutException) return 'Connection timed out'; + if (error is SocketException) { + return error.osError?.message ?? error.message; + } + return error.toString(); + } +} diff --git a/lib/src/services/port_service_web.dart b/lib/src/services/port_service_web.dart new file mode 100644 index 0000000..5903d88 --- /dev/null +++ b/lib/src/services/port_service_web.dart @@ -0,0 +1,60 @@ +import '../models/port_check_result.dart'; + +/// Web 端 TCP 端口连通性检测服务 / TCP port reachability service for the web. +/// +/// 浏览器禁止任意出站 TCP 连接,因此端口检测在 Web 上不可用;所有方法均返回 +/// 表示“不可用”的结果,不抛异常 / Browsers forbid arbitrary outbound TCP +/// connections, so port checks are unavailable on the web; every method returns a +/// result that marks the capability as unavailable instead of throwing. +class PortService { + /// 构造 [PortService] / Creates a [PortService]. + const PortService({this.defaultTimeout = const Duration(seconds: 3)}); + + /// 单次连接默认超时 / Default timeout of a single connection attempt. + final Duration defaultTimeout; + + /// 检测单个端口是否可连接 / Checks whether a single port accepts connections. + Future checkPort({ + required String host, + required int port, + Duration? timeout, + }) async { + return PortCheckResult( + host: host, + port: port, + isOpen: false, + responseTime: Duration.zero, + errorMessage: 'TCP port scanning is not available on the web platform.', + timestamp: DateTime.now(), + ); + } + + /// [checkPort] 的布尔快捷方式 / Boolean shorthand for [checkPort]. + Future isPortOpen({ + required String host, + required int port, + Duration? timeout, + }) async => false; + + /// 并发扫描多个端口 / Scans multiple ports with bounded concurrency. + Future> scanPorts({ + required String host, + List ports = const [80, 443], + Duration? timeout, + int concurrency = 12, + }) async { + return ports + .map( + (port) => PortCheckResult( + host: host, + port: port, + isOpen: false, + responseTime: Duration.zero, + errorMessage: + 'TCP port scanning is not available on the web platform.', + timestamp: DateTime.now(), + ), + ) + .toList(growable: false); + } +} diff --git a/lib/src/zero_network_kit_web.dart b/lib/src/zero_network_kit_web.dart new file mode 100644 index 0000000..62c37e5 --- /dev/null +++ b/lib/src/zero_network_kit_web.dart @@ -0,0 +1,22 @@ +import 'package:flutter_web_plugins/flutter_web_plugins.dart'; + +import 'package:zero_network_kit/zero_network_kit_platform_interface.dart'; + +/// Web 平台实现 / Web platform implementation. +/// +/// 浏览器无法提供 SSID / 网关 / MAC 等原生网络详情,因此 [getNetworkDetails] +/// 返回 `null`;[getPlatformVersion] 返回固定字符串 `Web` / +/// Browsers cannot provide native network details such as SSID / gateway / MAC, +/// so [getNetworkDetails] returns `null`, and [getPlatformVersion] returns `Web`. +class ZeroNetworkKitWeb extends ZeroNetworkKitPlatform { + /// 注册 Web 平台实现 / Registers the web implementation. + static void registerWith(Registrar registrar) { + ZeroNetworkKitPlatform.instance = ZeroNetworkKitWeb(); + } + + @override + Future getPlatformVersion() async => 'Web'; + + @override + Future?> getNetworkDetails() async => null; +} diff --git a/pubspec.yaml b/pubspec.yaml index 0f1ef47..f82b807 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: zero_network_kit description: "Network diagnostics toolkit for Flutter: connectivity, ping, DNS, speed test, port scan and quality scoring across Android, iOS, macOS, Windows and Linux." -version: 1.0.0 +version: 1.0.1 topics: - network - diagnostics @@ -25,6 +25,8 @@ dependencies: plugin_platform_interface: ^2.1.8 connectivity_plus: ^7.0.0 http: ^1.2.1 + flutter_web_plugins: + sdk: flutter dev_dependencies: flutter_test: @@ -45,3 +47,6 @@ flutter: pluginClass: ZeroNetworkKitPlugin windows: pluginClass: ZeroNetworkKitPlugin + web: + pluginClass: ZeroNetworkKitWeb + fileName: src/zero_network_kit_web.dart From 5938700b801abec63fba2faf14c1ff2172abe816 Mon Sep 17 00:00:00 2001 From: AmisKwok Date: Mon, 14 Sep 2026 07:00:55 +0800 Subject: [PATCH 2/6] fix: drop Cache-Control header that breaks the speed test on web MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cache-Control is not a CORS-safelisted header, so sending it forces an OPTIONS preflight that speed-test endpoints reject, surfacing as Failed to fetch on the web. The endpoints already send Cache-Control: no-store themselves. Cache-Control 不属于 CORS 安全头,发送它会触发被测速端点拒绝的 OPTIONS 预检,在 Web 上表现为 Failed to fetch;端点自身已下发 no-store。 --- lib/src/services/speed_test_service.dart | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/src/services/speed_test_service.dart b/lib/src/services/speed_test_service.dart index 16f2a3d..1d6f060 100644 --- a/lib/src/services/speed_test_service.dart +++ b/lib/src/services/speed_test_service.dart @@ -178,8 +178,16 @@ class SpeedTestService { required Duration maxDuration, void Function(SpeedTestProgress progress)? onProgress, }) async { + // 刻意不发送 `Cache-Control`:它不属于 CORS 安全头(白名单只有 Accept / + // Accept-Language / Content-Language / Content-Type / Range),设置后浏览器会 + // 先发 OPTIONS 预检,而多数测速端点只放行 `authorization, content-type`, + // 预检被拒即表现为 Web 上的 `Failed to fetch`。测速端点自身已下发 + // `Cache-Control: no-store` / + // `Cache-Control` is intentionally omitted: it is not CORS-safelisted, so + // setting it forces an OPTIONS preflight that most speed-test endpoints + // reject, surfacing as `Failed to fetch` on the web. Endpoints already + // send `Cache-Control: no-store` themselves. final request = http.Request('GET', uri) - ..headers['Cache-Control'] = 'no-cache' ..headers['User-Agent'] = 'zero_network_kit/1.0'; final stopwatch = Stopwatch()..start(); @@ -241,9 +249,10 @@ class SpeedTestService { required Duration timeout, void Function(SpeedTestProgress progress)? onProgress, }) async { + // 同样省略 `Cache-Control`,理由见 [_measureDownload] / + // `Cache-Control` is omitted here too; see [_measureDownload] for why. final request = http.Request('POST', uri) ..headers['Content-Type'] = 'application/octet-stream' - ..headers['Cache-Control'] = 'no-cache' ..headers['User-Agent'] = 'zero_network_kit/1.0' ..bodyBytes = payload; From d33fa9bb365d8deb6be88453a11a6d9ec7958745 Mon Sep 17 00:00:00 2001 From: AmisKwok Date: Mon, 14 Sep 2026 07:01:08 +0800 Subject: [PATCH 3/6] fix: recognise VPN adapters by driver name on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only IF_TYPE_TUNNEL was treated as a VPN, which missed TAP-Windows, Wintun, WireGuard and OpenVPN adapters. IF_TYPE_PPP is deliberately excluded because PPPoE broadband reports the same interface type and would be misreported. 此前仅将 IF_TYPE_TUNNEL 视为 VPN,漏掉 TAP-Windows、Wintun、WireGuard、OpenVPN 等网卡;有意排除 IF_TYPE_PPP,因为 PPPoE 宽带上报同一接口类型,会被误报。 --- windows/zero_network_kit_plugin.cpp | 36 ++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/windows/zero_network_kit_plugin.cpp b/windows/zero_network_kit_plugin.cpp index 98cfe93..83825e2 100644 --- a/windows/zero_network_kit_plugin.cpp +++ b/windows/zero_network_kit_plugin.cpp @@ -209,6 +209,40 @@ std::string WindowsVersionString() { return version.str(); } +/// 已知 VPN 驱动在网卡描述里出现的关键字 / +/// Substrings identifying well-known VPN drivers in an adapter description. +const char* const kVpnDescriptionKeywords[] = { + "tap-windows", "wintun", "wireguard", "openvpn", + "anyconnect", "softether", "tailscale", "zerotier", + "nordlynx", "mullvad", "fortissl", "globalprotect"}; + +/// 判断一块网卡是否属于 VPN / Decides whether an adapter belongs to a VPN. +/// +/// `IF_TYPE_TUNNEL` 覆盖 IKEv2 / SSTP / L2TP 等系统内置 VPN。不能把 +/// `IF_TYPE_PPP` 一律视为 VPN:PPPoE 宽带拨号同样是 PPP,会大规模误判。 +/// 而 TAP-Windows / Wintun / OpenVPN 这类适配器不按隧道类型上报,只能依据网卡 +/// 描述里的驱动名识别 / +/// `IF_TYPE_TUNNEL` covers the built-in IKEv2 / SSTP / L2TP VPNs. +/// `IF_TYPE_PPP` cannot be treated as a VPN unconditionally: PPPoE broadband is +/// PPP as well and would be misreported on a large scale. TAP-Windows / Wintun / +/// OpenVPN adapters do not report as tunnels, so they are recognised from the +/// driver name in the adapter description instead. +bool IsVpnAdapter(const IP_ADAPTER_ADDRESSES* adapter) { + if (adapter->IfType == IF_TYPE_TUNNEL) return true; + + std::string description = WideToUtf8(adapter->Description); + for (char& character : description) { + if (character >= 'A' && character <= 'Z') { + character = static_cast(character - 'A' + 'a'); + } + } + + for (const char* keyword : kVpnDescriptionKeywords) { + if (description.find(keyword) != std::string::npos) return true; + } + return false; +} + /// 汇总当前激活网络的属性 / Collects the properties of the active network. /// /// 活跃网卡由「是否拥有默认网关」优先决定,其次才看遍历顺序 / @@ -243,7 +277,7 @@ flutter::EncodableMap CollectNetworkDetails() { adapter != nullptr; adapter = adapter->Next) { if (adapter->OperStatus != IfOperStatusUp) continue; if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) continue; - if (adapter->IfType == IF_TYPE_TUNNEL) { + if (IsVpnAdapter(adapter)) { vpn_detected = true; continue; } From 7e6dd4cf435c365dd09e132fc9d0c2986e18cd01 Mon Sep 17 00:00:00 2001 From: AmisKwok Date: Mon, 14 Sep 2026 07:01:09 +0800 Subject: [PATCH 4/6] fix: restore app icons corrupted by UTF-8 BOM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The earlier line-ending normalisation rewrote binary assets as UTF-8, replacing non-ASCII bytes with U+FFFD and breaking the Android, iOS, macOS and Windows app icons. Restore them from c2638f9. 此前换行归一化把二进制资源按 UTF-8 重写,非 ASCII 字节被替换为 U+FFFD,导致 Android、iOS、macOS、Windows 应用图标损坏。从 c2638f9 恢复。 --- .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 872 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 743 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 1191 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1735 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 2371 -> 1443 bytes .../Icon-App-1024x1024@1x.png | Bin 18703 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 593 -> 295 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 795 -> 406 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 857 -> 450 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 530 -> 282 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 927 -> 462 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1379 -> 704 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 795 -> 406 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1120 -> 586 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 1682 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 1682 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3171 -> 1674 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1492 -> 762 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 2326 -> 1226 bytes .../Icon-App-83.5x83.5@2x.png | Bin 2676 -> 1418 bytes .../LaunchImage.imageset/LaunchImage.png | Bin 86 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 86 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 86 -> 68 bytes .../AppIcon.appiconset/app_icon_1024.png | Bin 182501 -> 102994 bytes .../AppIcon.appiconset/app_icon_128.png | Bin 10178 -> 5680 bytes .../AppIcon.appiconset/app_icon_16.png | Bin 858 -> 520 bytes .../AppIcon.appiconset/app_icon_256.png | Bin 25230 -> 14142 bytes .../AppIcon.appiconset/app_icon_32.png | Bin 1878 -> 1066 bytes .../AppIcon.appiconset/app_icon_512.png | Bin 65196 -> 36406 bytes .../AppIcon.appiconset/app_icon_64.png | Bin 3873 -> 2218 bytes example/windows/runner/resources/app_icon.ico | Bin 53585 -> 33772 bytes 31 files changed, 0 insertions(+), 0 deletions(-) diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index 57c579a36dbae9d3d3dda1afe465533be60b69b2..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 100644 GIT binary patch delta 494 zcmaFCwt$7TGr-TCcOs`<{mE1t1_p+80X`wFK$_97i!pq*=C*GkM}I&_#;{os5w`>1 zfr3E97&a3qB2l&!qQG|DV+Ny028$F%ZEr?{U`D$PjD9_g zffE^nCNTz0W(=Of7&@IXbOvJ>5Y+=s2U);mozCP?z~o%Uw+p3gfld}K3GxeO5CDRJfCLa|I1d8%B?X@R z0!qL1ba4!cIQ;g^b-pGC0f)elH+vJ_clF3>|N3vA*1}QG?X7ff9sjYN>&-2@oIHKj z-uwCK$pmLUOEB?%PDrDEYr!YQ&8zAzbG91z&1fmE;C#)Zy65rq81?Tv4|}bfyftsW z^}Hh%V(P91ag)w-dQFsZ=d!5NT=aR0Mf+4GYoB?KJr|wx7AlwVZ2LUL!0*zd)rvBz zfe+`rwp)8*f?k5PtdY=?&t+*1EHAf6zUCH~-uL?8l{S{8hc_9|Ig{hzVKn=#U;P?p z4zFcl`Cpf@H7rQU>U}43qadi#v?)PDGmK?|@=LRNA&qLSBtx)-3R`S|Mgd5YRlO%th}LE; z)g>G6RI|E@IIl0^aC{%uhsN7DK;uO;=lpt%pLglV1 zt(E&T$@?aM-V`XBsHS<9XpJZa>No&(=0J`skn;xA4OEqjJ)`v?d&c$PIK3EIdqGnZ zk{wShmZpcZ{;|W(0iL!JTu5%#X0*WZ+x>B>oi5!!^o;T8{2sKmDcb-2)cW}XduA52 zsL*g~CD1}~W~wm(Ww9hp}`-Av^ug7t@$KA$(B3;u0IDjT&RDASvNAZv6 zDRz${5jR`vEwtH6{iJAzkOo%SL)Nstymmbel^z*QQJn!GItXI%(yu=_V3Fyz5NtrhW diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 77e7bf0bd5da013b3f837677e393b0a3a8bd8d64..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be 100644 GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@UFfh@*wAUgzzfk+cVL3v;qR3WVDpn}M{ z*pUnc8^hvU1T`rT#SR9WY(}S2Mqi*HqaTO>nF1j~L98%10WuM66tk{3vtb~sQywcw z7h5opkON{Ml7~==5K0M!g4%8f5kz%Fpg&NQ6&MzxB|(0{3<3fQ3I+xS5S0YUe25BR zNT7PUIEHv2>k$HS3_7sD3}u0Y2oUSsY;r8LIZ1X306 lBMj%4F@%ZK19|MXCxT)Wh+ma}kmm$S!2r5Ww>efC{L)rIastu6yEx;$l6-b91 z{h_(-8>2@9WB6XM)pIvKymkj-=R{$Q-HE!InyADCqA;SZ)WsrVf1Nd z^yy&q1)@$yzb;1qKE{B4#-NFeL6aGSfoKY2$W+GA>5O4B7{g{VhRtFO2cp?b#t}?b zsZ92HOwMIY?$ykmb9$?6T?c?R zyX*%!r*OmC1q=-J3}Pige!&a^3I;$BkdRPN&@g}g{PXWYU^h#uAOi!Vzo(01NXEUl zH?R90b`WTN=%BIidsbCGqfb)POCcKu#wN;Vs(#q+AK^|M~yK?$#gnUe2oZ1~2@ zRBW%B@i(xo&gsH0<+c26`_xo^>3W^G($BflPBG<;d(*;v5u@+7n>OYP6n$}Se6hSG z=C6aoZ%)PZ`1$v)vrMe>5qRa^6tQ2I$Uf{YjPgk{w&OV+v(8oqsKIUTzhlq*1w%zJ-#2-{ydtTDlyq$ y>z?PDpDS7(v0QyFRHY`$!XZ%SbKu4|*2H$UvfXpr`4||0iOtj1&t;ucLK6VY-yHM+ literal 1191 zcmZuwTT@a|6yEzl1kPZDMrzZDrcP88(?uB*-a zdup2gLrvqKXnLusSKj;!eT%(24U^2bzHeO)`>eh8K8Ifp4iCO26Oo>w9>$n877eDL zc`~yBjA|H0#lc!ATT7Rp)V2#%jRi{OqUMY}FRW@Qtx$UP0#9kP;vdO)CIl~o6yOrV zqfoy5FCoiPIu+?#@8hZNvRou0*6ObD^xu^o&;DDUxm9*K#ja$SC&Rp(+!f{*7Wm|2 zK2_w?B|fvpeHHGn@<5G;c6qqLBTXJ@@o0<3Xw?OxxK4M;>rjF`l_*J+(y7x-hp0=w zNVL>VG=$E6m1|k$mZtbNmH90tvTKMn4fI089gyQG==26?pb8q?0Sz^XV8EH9t!A< z3V+4EE}WbRD*O5MwzOfgOe0Z;wZsGNe(3MdB2cS__J@5hf^HF2!Si}>6W)p*!7++p z#vE^?^6>irRIR^sH!A=NwVhrl0WB9gj0eeSEV0rP%{Z|qEcmpci z=vb(W_NTo^5Wf>-8ClIi1gMW@oW?_c&%)eh(0l+iY`z2r*6cgO^ah~)aSwbPHYQJS zd3K!I{`npx&<82Q9^9sHQwOC-jdC45`#R?wy{<Mj4`EA_+r8?= z8>)*oEwD5tbdfGBASWmSooQ6`NeHZH18_WgOdF9eqj3QC`ot-t+18}5O5j)lYTDA{ QUR+QX3nhZc%+Ue<0h$@MbpQYW diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index dcc72a372467ad8df67e4b73be684a7b9798721c..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c 100644 GIT binary patch delta 918 zcmX@k+s>ib8Q|y6%O%Cdz`(%k>ERLtq$hwd2Q!eoFhi(oqPCL7$y6H#2FBn3pAc7| zsOGkBAxD2e5RlCnG?_7cHm64cL|n395s+cE=Q~ir#H~s74U8U*jGjQ$#OT?~=-I;P z)y(MC!sye^=+nXI3q+lae%*|IJ&gW9)XNyq#~9ep7&w73a3W*iB*vhLj6pzhGGj0h zO<@d~$`~?@F?2d(=nTd%AezY-Hj6PFh-R~!1#?(OaXKb*x@B{D6><4ha0k|Mhcwo6 zhqZ8rw{u5!az}M>NA>VT_oytmsj~2<>Y_WUOYW&IeW14dq1uYaYAc_pt$eDs>Y3VV zAbPG2LN9^Z$_R$HZK%euM1o;Is2naYNG|UHq{pZi0UpMjcD+UH8eNPw1kcwMx zFQf+t2a2>l)ZpR>6LEFgTpz$AHATp&rN!mI0blEl4YoHjgns;=?_oHprTG0_+-L21a4MkEV^7h%Y{#_>jbxd^NEX(^*$X7RxkRvqjS%vKf*h!=D6Og{MW@Hr#^A| zysnNX8^tSMYj$?XSx>w!mmAd|r}FY*XNs-5>!o>V6Zb3+OlevkSD(`MJR+rQxth`O zV9}XRG`k~g_MLX|FWi6m_+`;q&(CiUSnauJ@A}K9Uz!!WRL3uiUs`-h;^MpKCtb9b zPtja7*Z;iu+MII|7rz}(C@~FYovCo^mq5kNq|{9}xjf>&R441m_(#2z@`(D9U27o{ zyNdl}SKYpPkvZME<_#*Y_V>Ql_n&o1@;9f5H2cT-xGtiaWNsV~0C-xpSAh za8oL{QJn)1##9(YrNR&@6}+fa@S#${k1B8hsHe|>fM3Dg&4_HFKJF zMcX}|Yn#b+Eb2UKI&V@R*wN!;J&xAnK>ZlP_+Q9-49W~GL$%~(Qym5Woh&p#khr~0 z3W_=a=i93`D38KK(5o%=(_zLgHM=ESD4CATD@vf0yn3B>q*S(p$Dq?wnl0a_kgEU=%lC zT*fM##G{<-&-Pg4pKmeEWC7eH*rec5!F3NHs9d8?TyRvRQu4(qNGL`ef5blyf7^4` zzAmMvAchU^yy9%XbcZ~#Va!4~v?XYnanp%5lq_QZz!FM+@x;`kuKFzWP{j+Dj_jAuZ=bo8!&&(Y(tixCo z&?sJdXj3!8FM(Otl} z2N*wszmn>Ljuqk(i*ZR6XH&!`X>}$y z?wh1HnBHtQh1*OsJMi2teD)(euN$B97@yOF&+RqK?K8h6d;224pN~gj4a!d=bHSzt zP#BQDg~N%FNRx}occv&{H$#xNi;uf&AZK1Nqs#b^Zj>A4PHL)#zafOQUuugQ%+%MX zXV>NnPi2)ph!Qo;*{7{bJP%r9#vM*|JeRzhNLa2cQ))nZ6+0~rgLXJGw&rVlxY}H6 zl%al+Xa2td|ED-sgSi^pBFtrJYC7)^d_X)nbj3n`$Rt5r@mB#9zU(X(C-VON@}siS6a<-ROKZ zX4!IgFa3g^bOW#6O}=KZ!W9$dHKT>EjYAGyJNtR@1A-NWWRs^Kj(I|Ks@PgIM4T@Z zF+rT-Jzjh3ivxXPZO2lD)=X{ApFb zFcAhk-JbE|Tt}sx-HGz~ULDxR;-Y0TKPKyM7PF^iU)KHu96V!0sS8mpO8b))Rd2>? zcu9B(w+kL>&`Z4H7BhqX{czXc;G9z^su;dQji5G1cE!CMCfC!|TtlO32=xgGplO*}@7yx2Gj$K)?b=`UL!=P$p&-b|gW}%e7Rmh= D*SJP# literal 2371 zcmc&#O;21^7(VABv>8MJVQ5jqv}vfNFawrvh8boU2Bs}Dd=(HV%(M*OUxk6;!!m}A z#)S(vMq@%+6Bkya3s)M#qEQnXO-w^jH|#X&rVIao&ok$6uXbVFNuKk(&-QpZ^a#< z`PgKnr02^a0sWA;)FH~lqC6rhx`eY^ID3SvSGf8_WxuEb2E>&iQ8OxPqoOV7J3zbFz6}dVmG# zS(IL2NwzFY--`4lq<>ZV*JNNr1~z3IuqA_U%Jyy9o{}9nr=k#5nyyk=WL?%$*SW-^ zPP!I_=~@(_o2D)*i_+P*sE4y@>ZN*ym`!O>I`Pj?x{wyJEa}=9&WKUfZ&VK(by1^n z+;C4Bo>`-1!SLNN{3}N5su5T-+SZNWh7sH}+BfY}c+x%%Dw-!PfzGUe&aRO*NL!%d zyQCBe191n8#!RKei(X|}?%Ct};G@0Z4_`8u09T){ zP`Yzw`|yF1Gf7tPhEsXq<4>P_u*WyRb@E_PXL~`dNwT|vrY2>t*p+3dupV4=!3-$j zWEWnU3helAKgmH+Bo{pvZ$B8(TJ)|)-b zLITnHd~i&Ea5nf^FwxO^P3ep7Xpt_kIjKZ(B&$)W4DKy3_`|i#&P|NjxrVziOd)S( zLRTxAc>MnSAv34&=$;3{J7Wea&OkD~%espoFPgK%GU)&1y&2!ZKD+a$kAC|mD^=!r z{lYRlewTnTcI4l&nPNv5@XciPkM}`b5Bzu!w4}QQGWFeOIrFW4?xfEP)tPs$X^3}Z z&Lg8tcN9Y(nF;G+rz;F|vz)ls448r&9(=7_y*W3{X8}a!Yc0~of0Bmj($ODL{xFcs S<1^v-#~?y&;Q*wcNBIj*+R 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 d={xN#0001NP)t-s|Ns9~ z#rXRE|M&d=0au&!`~QyF`q}dRnBDt}*!qXo`c{v z{Djr|@Adh0(D_%#_&mM$D6{kE_x{oE{l@J5@%H*?%=t~i_`ufYOPkAEn!pfkr2$fs z652Tz0001XNklqeeKN4RM4i{jKqmiC$?+xN>3Apn^ z0QfuZLym_5b<*QdmkHjHlj811{If)dl(Z2K0A+ekGtrFJb?g|wt#k#pV-#A~bK=OT ts8>{%cPtyC${m|1#B1A6#u!Q;umknL1chzTM$P~L002ovPDHLkV1lTfnu!1a literal 593 zcmaFAd;k0WdjtI3xum!l7#MgxJzRo-vRzt(w%M&0X))2~GC|-b1JORRikU2n#7l^YtA$(_0G=P*lL->qP zF9iU(ocAU|1c9U*gyjMk5aee_t@1Oz*aH*+>5+iQl&}KnWRWN!Sq#J{Rse}`P=uE2 uNCQbAk_BQ=5M=|gKM+fJ$pcAdAO<29AO?9CWF63-44$rjAS<0fegFX9PKkj4 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index 125aebea1f7dd8d7f1af6dd8cb0578d63345b328..797d452e458972bab9d994556c8305db4c827017 100644 GIT binary patch literal 406 zcmV;H0crk;P))>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 795 zcmaFAd;k0WdjtI3xum!l7#MgxJzRo-v<3)sFat@Ttb#{8gc0Bq;tJ$LPzZ!#3&4~-A!mcUsMMj{#?&dr9iAdFfxJ|;H+O(+J!H$)RwgYb>YfwX=pnj{+6vWIHy@b6A$m>jTET)1$8mbmVU7sBcBvHbp9w=~Q zH;_O^vgi7ek`jO-eAkvp>9Hlr)LH{Mf>}V~$V4Ck;sH?wgp$q+0x}Hq#ew8)bfZ90 zKvZDwQ3j2sNKibmXB#3s4NVH51jhkU4kY7%m?^CW!e<6jrE*4!An|A*5g=~_k$@(@ zG$0S;K}U!vE0D_02NDT^>1IF*nsf_5#sCp7gyIHLS674L7#Qjdp00i_K&BJO+W@V? B4$}Yt diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index d21dc4b6ad925d3badd52c6bbe719aea95345a30..6ed2d933e1120817fe9182483a228007b18ab6ae 100644 GIT binary patch delta 431 zcmV;g0Z{(g2EqdciBL{Q4Uq{Se}qs>R7L;)|5U~JDYo_jSDRPH_*uvJ?fL$s;QQnD z{*>GM-ShrilfUZt{^9lhT*&z4_x{-O{Rv#2V9EI}xb^~1iQe@7)8g(7UZ4B@|4zgB z>+<*9=S>kp@eB z0YY{d5q}&2008+(L_t(Y$L-VE4uUWcK+#$ju~Ifca6tuk{r~^72119Jlni|!MD8QW zN!uwUQ&ZpUIV{6jZzeODhUGYGLF=Qe+p>;^^)>d)H7pzGjuM>Jnezy3`@G2r?{~a! zFj;`+8R`uN@LQxfhx0qnWKpE+bn~n7;-89sa z>#DR>TSlqWk*!2hSN6D~Qb#VqbP~4Fk&m`@1$JGrXPIdeRE&b2Thd#{MtDK$px*d3 z-Wx``>!oimf%|A-&-q*6KAH)e$3|6JV%HX{Hig)kuLT-RhftRqAsRpP^ln%6zCFRSWlHn zUj#x!>3kf*k!SI-=!#GRqQvqqt_+&q8q_dRXP3LPEJGWA4qJA#<&4&7a~*w=e)&jS z>&rL$yr<7kv-h%8S=28u({_yOO2mEX->porT`i6d2%`KE%>3Ons<&ZID9H~9-qHodW9foLB9*h81Q)y8b0GPr2zeL zEuh|~6UJ%;(OrcB#3D?oFz(monoS|hJcxx-buf{63y=7GEPYUbN_ou}7AC4szs z3yLY~146DOXTTS9un+1XE)Df<2yOMmuD(9xbQ(gUA%QvQ<6QK+h?@F1j`!Hp>(^bcu7P-R4C8Q z&e;xxFbF_Vrezo%_kH*OKhshZ6BFpG-Y1e10`QXJKbND7AMQ&cMj60B5TNObaZxYybcN07*qoM6N<$g3m;S%K!iX literal 530 zcmaFAd;k0WdjtI3xum!l7#MgxJzRo-v@8g7Faya%U!c4#kP#c;6XFVFLr@5W(u7cq z;cy8cBNds0pB)2{R>;AsEDx(FP>?YUtBeyw)Dc3Np{c2Y@GBvd41^M`1=3=rK!OqE zB}Pw(FoaYEdb`5Y#W6$!S(FdRG2n0r1X8IIvOp4K1Q6K+ageaEFodTLq=cCuY>*5D z$pa~GB{xMKKL|e!LK*Wz=yC`JA^kyt>m}*wq6bnH=A;Mpo&=C5=@FP7!{r2$kOXGM(K{+7BkPakRe7JRhR1VOO44$rjE-}iV`2<;=$?g5M=KQbZ{F&YRNy7Nn@%_*5{gvDM0aKI4?ESmw z{NnZg)A0R`+4?NF_RZexyVB&^^ZvN!{I28tr{Vje;QNTz`dG&Jz0~Ek&f2;*Z7>B|cg}xYpxEFY+0YrKLF;^Q+-HreN0P{&i zK~zY`?b7ECf-n?@;d<&orQ*Q7KoR%4|C>{W^h6@&01>0SKS`dn{Q}GT%Qj_{PLZ_& zs`MFI#j-(>?bvdZ!8^xTwlY{qA)T4QLbY@j(!YJ7aXJervHy6HaG_2SB`6CC{He}f zHVw(fJWApwPq!6VY7r1w-Fs)@ox~N+q|w~e;JI~C4Vf^@d>Wvj=fl`^u9x9wd9 zR%3*Q+)t%S!MU_`id^@&Y{y7-r98lZX0?YrHlfmwb?#}^1b{8g&KzmkE(L>Z&)179 zp<)v6Y}pR8kNYZKJIebBmX zgb+ln-L!~)gMXoOxx-XqAl!S-J?Gwee2?-|v0QwPYtuH5O%Mc0Rpdo*fU>b3i0&5B z!)1I6Fi5nbUi#%9o1JJFqe#B$8Tk9p4*umEr-_Z=;CWzKfE4br2|=<_Wb|z`~RBV`-<24{r>;E==`tb{CU#(0alua*7{P!_>|iF z0Z@&o;`@Zw`ed2Hv*!Fwin#$(m7w4Ij@kM+yZ0`*_7{1p0ZWAeKytX}fBZVU_j;$x zb)?A|hr(Z#!1DV3H@o+7qQ_N_ycmMI0acg)Gg|cf|J(EaqTu_A!rvTerUFQQ05n|z zFjFP9FmM0>0mMl}K~z}7?bK^if#bc3@hBPX@I$58-z}(ZZE!t-aOGpjNkbau@>yEzH(5Yj4kZiMH32 zXI!4~gVXNnjAvRx;Sdg^`>2DpUEwoMhTs_st8pKG(%SHyHdU&vf6Kl*kcW}Ae>{w#C7G6oLq&Y11G<;XmV&ThF&p_e7~%V%kX`%63A*@p()WE; zJ;Ml_0nfffn=X!+grC{*bQ1N~z8Z%y#pAoAn`E)XG)%H@uhZzGiYBJPMw?dg#O71f z=T%JcN(Dm^x8?>fVv60B@podBTcIqVc!?s0VFTxE&YzEpAzM(4k4NAXIXSt1xpx7I VC@PekH?;r&002ovPDHLkV1gAVY#aap literal 1379 zcmbVM%T7~K6us9CLl#L?Z?S(ps#FmPaX7M5I(IPz0i(3L+)66&0L27N?r% z9~ei(lHia8hm3UM#2LTfTCS7pO$QE4_Fj*D&*^!0cYR}bvpCSe6Y=^mGoVozAmdR{H+~nVmN?T#-9wM!R5-9CFv7 zGsxh8igi`s+{slrVAveeR_Tgr(eRQ)aG%rY7*uETo%2qCQ$JxgaX!E3 z7OBRNO-Sz7Y2*}_G`IZ@h!`_}8FA?9NCe13De`HZGl$1VjDJfj5gXt_x+Vd?0ok;j ASpWb4 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 125aebea1f7dd8d7f1af6dd8cb0578d63345b328..797d452e458972bab9d994556c8305db4c827017 100644 GIT binary patch literal 406 zcmV;H0crk;P))>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 795 zcmaFAd;k0WdjtI3xum!l7#MgxJzRo-v<3)sFat@Ttb#{8gc0Bq;tJ$LPzZ!#3&4~-A!mcUsMMj{#?&dr9iAdFfxJ|;H+O(+J!H$)RwgYb>YfwX=pnj{+6vWIHy@b6A$m>jTET)1$8mbmVU7sBcBvHbp9w=~Q zH;_O^vgi7ek`jO-eAkvp>9Hlr)LH{Mf>}V~$V4Ck;sH?wgp$q+0x}Hq#ew8)bfZ90 zKvZDwQ3j2sNKibmXB#3s4NVH51jhkU4kY7%m?^CW!e<6jrE*4!An|A*5g=~_k$@(@ zG$0S;K}U!vE0D_02NDT^>1IF*nsf_5#sCp7gyIHLS674L7#Qjdp00i_K&BJO+W@V? B4$}Yt diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index f47a38b84d83e7b81b95ac158c8541b82e630cdb..502f463a9bc882b461c96aadf492d1729e49e725 100644 GIT binary patch literal 586 zcmV-Q0=4~#P)+}#`wDE{8-2Mebf5<{{PqV{TgVcv*r8?UZ3{-|G?_}T*&y;@cqf{ z{Q*~+qr%%p!1pS*_Uicl#q9lc(D`!D`LN62sNwq{oYw(Wmhk)k<@f$!$@ng~_5)Ru z0Z)trIA5^j{DIW^c+vT2%lW+2<(RtE2wR;4O@)Tm`Xr*?A(qYoM}7i5Yxw>D(&6ou zxz!_Xr~yNF+waPe00049Nkl*;a!v6h%{rlvIH#gW3s8p;bFr=l}mRqpW2h zw=OA%hdyL~z+UHOzl0eKhEr$YYOL-c-%Y<)=j?(bzDweB7{b+%_ypvm_cG{SvM=DK zhv{K@m>#Bw>2W$eUI#iU)Wdgs8Y3U+A$Gd&{+j)d)BmGKx+43U_!tik_YlN)>$7G! zhkE!s;%oku3;IwG3U^2kw?z+HM)jB{@zFhK8P#KMSytSthr+4!c(5c%+^UBn`0X*2 zy3(k600_CSZj?O$Qu%&$;|TGUJrptR(HzyIx>5E(2r{eA(<6t3e3I0B)7d6s7?Z5J zZ!rtKvA{MiEBm&KFtoifx>5P^Z=vl)95XJn()aS5%ad(s?4-=Tkis9IGu{`Fy8r+H07*qoM6N<$fhv8FA&pjZ4E{@LbPie67j7=bm%tcIM5Uo9=wv*xC5xrW1j1Kq<8+ zm5lczy5fEx5Ua2XIE8y5<1h!zkR4&LE}I3AA+G=*rhZbEHZnY6C`fhIs|>$tSQ#lj z`y5w~mK7QKi0pw$c*#KuYtWlCe4H%G;FBWjBEZ*mohdKQQ|jYwE*;hHc&2W|uIG9lIS?fStZptAA9dcgJzKqVa34wrq7|9tlh zVSE8_08YE#ZD*^x^`V8uaHI+O<~g(eKS>~U$fWCowcvZ<(u#Z+Ko01E>&8`sy1_sp z83b{Hqk1k5L&5Bc2H?$^k)a=JAYWDi^YE6`U#$;{Ap`sRenI(3rTw<*2QJAVN!AYO zvc~Nd$V>3kez`qO8U%Y>5?XIayJ)j9`BYkG^qApoWU{&J37chb8awm|QWsxM-vQhD zOevi_G3Vw-L)71v5p(1+95NZX?{E7oraDhHWu-UM@O?~8RTiHo_k-(Sffe6O$_-*Q d>9Jibs*{;lG7b0OGSc{yP$?%J2R$20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 1682 zcma)7Nl%ke6#Xg!wG5&pB7-0iq##4V2oh#e3Kb}bAY-L!i;RjWQe;@TbMMxz3teek z7zmQEGBLrpQWJ;08~%dlcwRoRx-hx-o_o%H@AbX!-S6w(=Jww9R&Su)mF2Q5E5+a8 z?E^;X&N#$Wlw}|s+ST7?OZ}!Y2rRZ$B||aXAH#j(12OV~xb=tLB{5<2;NV`7@`D<3 zi$8Q$VqZ+{Z+hczNlKZZM35u6Bd8WQt^l))^blxuiYP7}B*+anzj#7b2ajeo&YxTc zI(is<>yFA{Rat9^T6uLg%~Y0l59qke`Xz>%uvOBn(tpMYjk_tR5u6g3Gl~2&j!1Qm z1FPpmN?OlY)}boDx21p5o;1T})SD)L0Z>rX>~a8yOc#xC|E_5bSQpr_;UZGA{MFEh z*Sl}?Amn@MH6j2wVt#81c~Ek4feWpt^Y^hm%AR z*;L%EZRMF9G!MTEFEKel_Vf7*C7$l!BC>%&0n*(KRS;cpE;CnXOXhCCN7u|zBZ;bx zvc+cMOX4H7zzlfw$CIyom1QA58gt~r#83*@{-w@Wasn@7IR`;@n-uPZk0p5|x>MJX zj9)`&s6c3xj5y3K!>Vk>v;O_f`%TfI)d{W#Beb+las}=*#ySTfa5G~n1Oc5Z2&Hh& z$zY$$c&Ti=dTyju8e(9Iu@6B;h#R{%F(ev$!5bf}t$GM0{>uwdj+qjMlwj8ZS?8s&#$d1_= z61F_Q20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 1682 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 GvOfS`PeMrm diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 12fd0148001a0df286826bfea9049c7ed90c2352..84ac32ae7d989f82d5e46a60405adcc8279e8001 100644 GIT binary patch literal 762 zcmVOTza`!S_YK z_v-lm^7{VO^8Q@M_^8F)09Ki6%=s?2_5eupee(w1FB%aqSweusQ-T+CH0Xt{` zFjMvW{@C&TB)k25()nh~_yJ9coBRL(0oO@HK~z}7?bm5j;y@69;bvlHb2tf!$ReA~x{22wTq550 z?f?Hnw(;m3ip30;QzdV~7pi!wyMYhDtXW#cO7T>|f=bdFhu+F!zMZ2UFj;GUKX7tI z;hv3{q~!*pMj75WP_c}>6)IWvg5_yyg<9Op()eD1hWC19M@?_9_MHec{Z8n3FaF{8 z;u`Mw0ly(uE>*CgQYv{be6ab2LWhlaH1^iLIM{olnag$78^Fd}%dR7;JECQ+hmk|o z!u2&!3MqPfP5ChDSkFSH8F2WVOEf0(E_M(JL17G}Y+fg0_IuW%WQ zG(mG&u?|->YSdk0;8rc{yw2@2Z&GA}z{Wb91Ooz9VhA{b2DYE7RmG zjL}?eq#iX%3#k;JWMx_{^2nNax`xPhByFiDX+a7uTGU|otOvIAUy|dEKkXOm-`aWS z27pUzD{a)Ct<6p{{3)+lq@i`t@%>-wT4r?*S}k)58e09WZYP%P2@ zZn`N*sJlXhE&Uv2aob&G8`h%wT`^C-0KvYBUO3FxoG=PW})rw+-)Ic&_-B8Aqx3Bqv|3cnwArHlmlR?$yCO7klF#-eoJjnNK|OuIygyn2sBhb2b57P zF$pZAiplMeYoU%J(#8^SQY*VRmd>@$F9d$BJ=Vz*sGdr|d6@>S!WGkc`ZlEefi~3( z#4E|*fSihEZU#$hmOMHKp-v**sTp=(VQJ8{>`_BQqKnBpvcb0v8OB{^fQ#@dMx&oz z$(?9}Cz%26HS2)RWgYJyA-H7*#I7;@A%6;DMUG~HmrlteK7hko+{l;=FW`j#mYc~6$#qbYw(Yk>KM+CZtu~{y3^v8DX1G*3JFus)()v&QmAFPOtmlFIP-N4 z0v0|CkWZ6(80jiawuq+|%i>KLi%rdW*2&tr5pa2T-xti&Y0IH^o}c)<3YLKs7XdE7 TVZ+q`e433=Anb?ilJ5Klk*w$z diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index fef8cb9677a2786f9507d9820eb215c40f606a7f..8953cba09064923c5daf2d37e7c3c836ccdd794b 100644 GIT binary patch literal 1226 zcmV;*1U37KP)0{{R3FC5Sl00039P)t-s|Ns9~ z#rP?<_5oL$Q^olD{r_0T`27C={r>*`|Nj71npVa5OTzc(_WfbW_({R{p56NV{r*M2 z_xt?)2V0#0NsfV0u>{42ctGP(8vQj-Btk1n|O0ZD=YLwd&R{Ko41Gr9H= zY@z@@bOAMB5Ltl$E>bJJ{>JP30ZxkmI%?eW{k`b?Wy<&gOo;dS`~CR$Vwb@XWtR|N zi~t=w02?-0&j0TD{>bb6sNwsK*!p?V`RMQUl(*DVjk-9Cx+-z1KXab|Ka2oXhX5f% z`$|e!000AhNklrxs)5QTeTVRiEmz~MKK1WAjCw(c-JK6eox;2O)?`? zTG`AHia671e^vgmp!llKp|=5sVHk#C7=~epA~VAf-~%aPC=%Qw01h8mnSZ|p?hz91 z7p83F3%LVu9;S$tSI$C^%^yud1dfTM_6p2|+5Ejp$bd`GDvbR|xit>i!ZD&F>@CJrPmu*UjD&?DfZs=$@e3FQA(vNiU+$A*%a} z?`XcG2jDxJ_ZQ#Md`H{4Lpf6QBDp81_KWZ6Tk#yCy1)32zO#3<7>b`eT7UyYH1eGz z;O(rH$=QR*L%%ZcBpc=eGua?N55nD^K(8<#gl2+pN_j~b2MHs4#mcLmv%DkspS-3< zpI1F=^9siI0s-;IN_IrA;5xm~3?3!StX}pUv0vkxMaqm+zxrg7X7(I&*N~&dEd0kD z-FRV|g=|QuUsuh>-xCI}vD2imzYIOIdcCVV=$Bz@*u0+Bs<|L^)32nN*=wu3n%Ynw z@1|eLG>!8ruU1pFXUfb`j>(=Gy~?Rn4QJ-c3%3T|(Frd!bI`9u&zAnyFYTqlG#&J7 zAkD(jpw|oZLNiA>;>hgp1KX7-wxC~31II47gc zHcehD6Uxlf%+M^^uN5Wc*G%^;>D5qT{>=uxUhX%WJu^Z*(_Wq9y}npFO{Hhb>s6<9 zNi0pHXWFaVZnb)1+RS&F)xOv6&aeILcI)`k#0YE+?e)5&#r7J#c`3Z7x!LpTc01dx zrdC3{Z;joZ^KN&))zB_i)I9fWedoN>Zl-6_Iz+^G&*ak2jpF07*qoM6N<$f;w%0(f|Me literal 2326 zcma)8TTfh76yAqHxwkU|RywrhGMxY&ZeqD@S`^?hrtv(M~()?RzV zqi=3Ky0seZ>CAQIDy0g{W1(Isa>Cg*X#F0}dm~TB}B`oJv@r*7jlkS|7z|K+jVUXJES0&Ay<$q%KapQDL9Fpe;-hj4EgH#)d zHB{vt;7DXZDceOe)E=8bDCl*y+u_Y863NWdyP^l3;e$^iE`x<&9Jn8LNmsnP(H+w} z&(}ETnMF>Kj*VqR1}sr*5u6HEnQz&u6ID*ATkR+vfG)zGfH|0C3ve6qV79aSzyfwp zP~6h)V5XIale_-56`DW1#U}J}(dS?zIo$492gn(lW|qx0eDB)ne5jy5+j8MJITm2Y z1spF(AY3T&{gpqKK89N_q1)6>xx~WbB3Tf>xVpI)I=8;=Xkl+wz$)dL#XMlV4E~J^ zNU@%PpIcxHHG%cHko^72P;PZ2Y<~$TgEcQ}+X;TK#N*OX3L1r-jm(80-P&PGq|fjBpDK?RV06(XZ?#fd@h~c9bS7^UtS}KINzS>dsiVqjR=R% zB*dRQ1|8-W3kunTz~(2S`2i?55@0nG6Tf~7`Q>v^+4;>Ch=6Og5aqXWH7pcx0M>T` zG$t|k_Q$2&;I+?U1v;6BP|u!I-!%R6N@(M{4A;Bdv=`w74+wCFeZW_OzRng&HJ0vx z6X*WdbaLj!QNHOXdAPp*bF2qo6UqB~W?oM@Fs=wF5&`R0wXLrnN5uLS@mpMTp0Qm} z?-3B&y5a7JV8QL>tomxW^QXag-VE KVR?clL4N|3*a2_= diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index b7f1b3d265950521b5c6e5ea925f934a471df6be..0467bf12aa4d28f374bb26596605a46dcbb3e7c8 100644 GIT binary patch literal 1418 zcmV;51$Fv~P)q zKfU)WzW*n(@|xWGCA9ScMt*e9`2kdxPQ&&>|-UCa7_51w+ zLUsW@ZzZSW0y$)Hp~e9%PvP|a03ks1`~K?q{u;6NC8*{AOqIUq{CL&;p56Lf$oQGq z^={4hPQv)y=I|4n+?>7Fim=dxt1 z2H+Dm+1+fh+IF>G0SjJMkQQre1x4|G*Z==(Ot&kCnUrL4I(rf(ucITwmuHf^hXiJT zkdTm&kdTm&kdTm&kdP`esgWG0BcWCVkVZ&2dUwN`cgM8QJb`Z7Z~e<&Yj2(}>Tmf` zm1{eLgw!b{bXkjWbF%dTkTZEJWyWOb##Lfw4EK2}<0d6%>AGS{po>WCOy&f$Tay_> z?NBlkpo@s-O;0V%Y_Xa-G#_O08q5LR*~F%&)}{}r&L%Sbs8AS4t7Y0NEx*{soY=0MZExqA5XHQkqi#4gW3 zqODM^iyZl;dvf)-bOXtOru(s)Uc7~BFx{w-FK;2{`VA?(g&@3z&bfLFyctOH!cVsF z7IL=fo-qBndRUm;kAdXR4e6>k-z|21AaN%ubeVrHl*<|s&Ax@W-t?LR(P-24A5=>a z*R9#QvjzF8n%@1Nw@?CG@6(%>+-0ASK~jEmCV|&a*7-GKT72W<(TbSjf)&Eme6nGE z>Gkj4Sq&2e+-G%|+NM8OOm5zVl9{Z8Dd8A5z3y8mZ=4Bv4%>as_{9cN#bm~;h>62( zdqY93Zy}v&c4n($Vv!UybR8ocs7#zbfX1IY-*w~)p}XyZ-SFC~4w>BvMVr`dFbelV{lLL0bx7@*ZZdebr3`sP;? zVImji)kG)(6Juv0lz@q`F!k1FE;CQ(D0iG$wchPbKZQELlsZ#~rt8#90Y_Xh&3U-< z{s<&cCV_1`^TD^ia9!*mQDq& zn2{r`j};V|uV%_wsP!zB?m%;FeaRe+X47K0e+KE!8C{gAWF8)lCd1u1%~|M!XNRvw zvtqy3iz0WSpWdhn6$hP8PaRBmp)q`#PCA`Vd#Tc$@f1tAcM>f_I@bC)hkI9|o(Iqv zo}Piadq!j76}004RBio<`)70k^`K1NK)q>w?p^C6J2ZC!+UppiK6&y3Kmbv&O!oYF z34$0Z;QO!JOY#!`qyGH<3Pd}Pt@q*A0V=3SVtWKRR8d8Z&@)3qLPA19LPA19LPEUC YUoZo%k(ykuW&i*H07*qoM6N<$f+CH{y8r+H literal 2676 zcmaJ@TT@$A7(FKm2+@ENK)}*cZlP4JfwloHmxP-QAwWu6ZnY2z5GVtQq)8e&&ghFi z_*h5lD|SYG(iums_Mu*9Dx<9}Q>X1;=wEQHe%k})0cP#B*8cXn?EUR;pYZhiTTgHO z;P(w!%dDEF*@gx^V^G9|bIefpZ#RvA-y7&dM-UJ>CZY$S!98DL4Uq0S1pMwh-j~i#;-s%%`!IR=?Uz;FEVa#Da^)@ z{e)b%BC-jY)t{f`_7_JYSuD6M83IQ*dzERp(0WIzpjJk!ZeI(F16$N2jKIOBzE#E# zL8{OuETI0uQ_1-4kK@07jm~RmOvV}-FdLz1Qh`xuq!T1KRvkMJw;q+Q4sj-qzXb_N zR3t2+t+*{ZnYAZjir~`8F^-(g3g0^hjNek9^j{K(1Y!K z>D8*0`Ahg{&Ov35g~A2>{RzlX6HfBNf(zNK#SL5a-EBuZ+|E~^p)?3!HM&Yc55EAh zqPy=go)7Dw3BEJo9T*mM?EKfmGcA2Ui#xlal$6ZqSzyWGcWFb z`S3gRvLuqheiL`+9&-mUtw7J%R#X+Enq2$*Bziw6ZL5@GaWTDB)Qh$C--~t^}B>TLb4N^1yo!dA4<-U${4d)s(vj?pZpQHhCiE__Zr+lVK~w zyAax7{V=gWzKD8_bim9CYi{|@&Cr9-VJwRp*gFJ@mDhs-CmJVjfLX~!JEw9I%s<4f z@AF<0bKC3 zyDnE9o+fmY6;Ym&5Yxa{3p|TvGhEKk-~88y4x=^Iq$L9O)QM#UZL!#DdtU)3)z3;7 z4*_2;2-+`JzAV;Lr`zYlmBtW^s?~6#lXX%T2l0a;80POuhxm?hBMjr!2d4Rogb~cC z_A|Mwokj$vVqP5>?&iuJwJ1jp6Q*5`MONivbtci_7tdN1P_y4GL|0Eot@l4-%G6H5 z33fgcUG8IsX0kwMdCDsS;bIx#7O|e3dq0KaJ>{ol@Kwmpb#H!Nv2OrYrKKv`QO;rp z)R~vg75+AGJDCTkpGk6Xn``;atZC!X_oBH}x_q3CfNKJZxEO%7pi;~k0Nv4*G=y2; zAS>c(HV7!45e*$?Suw$Y3yn|Un}L2b-n08bCASZFa>H8m9Mm^b?q#TjXWYk``BI>} zpMnbc35^#txYdN2lvEG|@Lp9+5=iyW!>D4`18Un43ddN)0N2hB?NS;vgI3kq7B@iw zKI(J=WbW2RA-ony@I;oVBP$`!sX(m3R?q)R3UQtH49=x2uE40O38%Yv?@w;M(9Dx0 Tn1(FiKS*t;&*y>feG~LA_2}F+ diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png index 4f087bb1d6397f6aa8bcd00161c2a3c07f03a369..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 100644 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 86 zcmaFAd;k0WdjtI3xum!l7#MgxJzRo-G$ROeumDM*tPBqmkiqTg;uul^Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 86 zcmaFAd;k0WdjtI3xum!l7#MgxJzRo-G$ROeumDM*tPBqmkiqTg;uul^Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 86 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ⅅ8MglG&ER{i5lN315cO?EdHNLrg? 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 z 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 Pe7HEdAEg|=c=LY&YVNkY literal 182501 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

    #=%dKEQuhVzZb40a)_6NKV7Mr_7WF+oCOgq)+ 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%0A>h#M4@NnD=ufG5W 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 literal 10178 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 diff --git a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png index c9057c3aba656f325ec2cb4b061b51e4a2aee294..f083318e09ca1b6b8484b1694a149f0c5d5cac1d 100644 GIT binary patch delta 1056 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 literal 65196 zcmeFa_jg?7y)Qg78ui|Lw|ei*l17$f^=9>6tY-DzrQw8dNCF9=1rkUMArM-C07)Ql zU@cP(4#qTNjPaY?gp=IdBc3w7kJjcImk<|&!Qft3TXo7{FhMmLoE#u9x&;EzFs`1eIl(R;dnhePp zb}|^zdB$MoR8R=WV6a1<(O?J7$X>KehcirU+1Xm0?ussf!C*1eRaJCs@vM%ZW7S~g zLtyXy$0m4s1DIf}w5L|;D@~J#IT7WVBEjR> zMJkc5i@%$K^7&7s)tnI_8rUA~rVVf83 z&4N~vX{!Y?c9e&sQG2vQ^u^(GFQxB6PXnzRFw%@@?ruDDRAZa zGc1F7AQnqjI$zH126eplLnnyq&wv5Tpj6Pc+atkGfnNI-7;xn&k>Kv3`J!)dBS0N! zkFJgegBNITKNyNCBbevpT&`g189IUsSh1D`!T%^(`NW{Ak_)uRH*z7B|SL*&ub3gq8s+DOBUHKiZRw zHgGB{k*Bs@H-N^=+y|q}LP49L+GIC;S6b{ zO-yBexgIV|3LQpnw*|yF>?-Bs!%>9BasNpluruGexI={leFJQH8)HP{#<>Q83W0@S zy=NdLV&|_9K8SWEh|diPyl^5zcl88=F~}bbh!xQ);wTT!nVieuG95wm`y#!qR+I(x z!YzEp@NzLir>8p)Xc~bd)0tKm^v2RC?WaPEAu7Dows}6fZvm7G0zP?Iq|Qsb2W%Vl zO^8Sy#89LRt6+$c#~b|+x{SFm_)1JjR~!V*!NhR;;M>v(KF!4h{_7Vnav-j2+jCMM z62%WJeMfr1xnw$H!CKsN!00fVN8BK6DRtq;XmVK@4E!iM-{*um z#1L(PW?;1(8YctknAf#oXuF_(o;y8U`g?uU!$edjBZ?;nsz52AQfY!`2h#1HpaNbj zbFUWM!K`k7?%P~A;8X|}{mJv-%Gb)lOyThXuy^kO6V%mJ@OlPsFb}#qT>9rWXmzHK zV5*k>$-VXqXiUeH1FHrK_WAwHH zH->{Pft;DyU^3FP&<+aR~BS??OAD6+RcliqK+$~_Xa_> z!}if)W~h5;bID*d*8xno9gH{V-btph#u>4Ivhc99G>@PEmNdXm%y1#Rj3AGhCg8UI zc=K6Rr=*YBV;`@lJ;x4sO9PrjgajDu6I?|HA57x?V;ppn1_Z9$Gt65m<5e9g{opMP zyk^Pg-v&>Ri>yU+F9LOi(`c1~=JWwt3P=ELncg|;4jEAHMsutiEC}m`{972w@okQ;`j=!Z92?mKCZr*^v$}015hLMP@=QaPK^{iyP`>_0qg< zf#L)LSZaXEbdd~Z_u63aWX@JTNTHYi&z(2_hMDVKGnb=o^4mUW5AXDX`>GeOvtAZ% z0dS05L~27fN~Kb9$b`NHXRKVCU5kJ#tO_$3HCi*X+vqEPcITxdygW@*`%EkT@ypnZ|@p# zJpH7hXL-otW;tW1qOX{?!|Ke8Pj1$#!ftx5wu#o|`RW+JK!*r$I*69!nt`{T=4Kcq zfVY=-Ylr~~6D`SF2VTPYpZ}ECn9E_BzotF#Sj;pV&)ztcV(Il*td#|j1XBa0-OUbAe!2fX8A7>&`+BKxu6zM(Bb=8(EUtf z<}gTQ42lV^FY=6;)9p1^20;TZ|7u?p6?eX;m|qN|)+1+3H0|%Jc`{q)Ev33Tp(>O; zdagdyHErO<0GqMVV2J5pgAt^5UoZyUOBEZcUa{Z|>z&IlfivzIAXV?bx>HDZE8{`a z(vP;KdzgxXooqMvRXeB5%vm5DRQ&fR&qDO3^+Y)B^DK*(6Msy zLFf^xQbDDgfR=R&AKmD%D3=rJTzx}ZyhNQ9Oc2Uk0vNUNQDD(>i#c>gqYN7YMJ9+i zIn3xT;!=T1!;C2JY42^(-EDLdEyege1_GFrRC7S;X$x9x6mxVR1bqJ6@$+}QaldCK zbawY-o$i3(>a9IsHIZr}bRaTua=AD8FtrT~yKT@cD4$WEcm@n`6k$K;*jnIeEJSOV zbx=nOBPIakCS59fOuj1F7%5Byl^M_~=`QBqdM&qW9O+lSF3;o&fPN9+y(6}ijnQ`N zN&D~0gu(p1*M0~!gl7x|Ie->&4XqH&WCpa3L6Qb=HK6-Z5jZp@a z>7!8Q50`2&&p0tIfiGXZw`_k0irEsl0nute%rAV66Ono5@semX8A4KppK(kkd` z_nl6)85SARx&O)t^hmv3?%C;zMjpt1vw?0EWYme|66k#8yt=7TG!AckbWj$nDxcsU}a8)G+41@k?(Jm)UEb$R^tcu}`yia)m7ce;R z_D_^k#Sr-nzc;_Hy#-1ebMJ#7S0+USh{0h6>3H|IP-%45sRI>?QY~c;Bf~Kw5uE29 zELNuE$vE37amCZZOGM6=s*1Q>y}#0%eppTma<*fJQ6ZFyspOO6HwuO7-Fkuz;y6LRUju&Dj zxE+PFTDbI`y!3=VNF%K3tttAI>zScjOLN}52ZH_rF1!H7&CzBJAi${+EECi{v|Vkx zXuTu4Vge4|@Id1z!b|j4Cp3AV(;#uHs+`AVl~o>?aJuBrY=z}qiE=1ersna7i$(W+aZ!qJfoE*M}qI)i3t`~i^m48~yeNtpEJ zDsxzxqjH$Xp%}x(SdmS`F&vgXTmo`7q`GCq- z1~SX3i}O48@ie?Z80aVtpOCsD_1+J^3-x^lijJn73ehjW#9$JnLKH@ig69-@gCD*P zwQ!*345G6X1URU?iI!%`wn#>r;7q(l6niJ`v|S&7vXLS!y1=KvE{}db2`Xl=a<+2z z3A$=AeG+^}nJbYeDgyzrp~c{8pLB!4dm7x*%RI{ixq*%%fjJ|ntJ77^>JAFoq!WQQ z(AzJAMMYhD5+V)+1b2W9ZA~RX0fGb0lSGV~=a@q~agcL_9s{&eTJ za4WA?ds-cr5pWjyVZ8;V3pC@z(4a=&xK#R{Jh|7y8^#F}Se0W-Is{Wdz+mD;AeEF* zPOIn`GJO2wtz#?JGovfK(u|Q6U*Ji@vgUpC7#NeZHPz93I?rS~!6|eCy!uh>p)sfK z7&H0+vxspj*k-ISy!mL7C4GbSlU(E1Kwo|nPSV9?sVhOtVL^ENPB5mnz;^hjx7qt{ z_-e}^!r13O1XHoa`yk`*42WR_SV5hofy&`6(wVt!FA5I;RB4>rfo@g}8DW43x=-41 ze+&Zc6}$QENAaqoZL_VB?DQ%sfEwNB`} zOqoPx+;I@#-9sgYV@J`LjFttI9g^f|*W`8S0osiA0Lo8@1b1=}b#e*Pg*N%?L%#-J z1nm^iGr*+lC$_w$b z8?1PqwDK8d##|^f#xEDFqdHS%&sO>F1Ui7BD=&`*vUbYf8e&aB(mw|A`OBh%d%7?P zfqqaR^O=`ZF#yffzvjy|XYx7#D^4V+o8hdA1l!-lWnLuDab89?rWp~-pke9oh#qV^ ze1(f1o=VvPn#ZC?+Xkc;2&m%j!bRu$)ddR^rK{A?90F}sd)Iki`h@5DdeaCxFm`g)U}Vu1m9-A)#i|S-^he0Ou7+ zs|_O4)baP5?y}cDZgebK4al%3?K|%3>q!>?Qw_`jK_q?7h{%uM);mSvViH5OcP1L4 z(sye0tPD=2T#|SaCv2^)w`}$V~=-=tWigKKUK=br8qmwD)|}2-+9# z0@LBi>$a__sG%WvFaPK)*T*x49s_Hn2DGG{za64NxhK{n-B+Jt6tr`Hw5nF0`j`yf zOJGLFB|fzs2MvONI9t{1lAa9hZ{E;dyeAj~08Pj1uqX<627r4SEX(N4byMX5?bv;P z@N+MMsR)NQ4*~)z85&t!>$nP%f4%ZBT6BvF+S2V*FK;xD;`%Gh;s5uZmw)cY7^_z% zf~u@R%j7f;@x~mP1}>#hM1e4UD2;&>RTp6;bZu)(TB6F3}2|zK9BE z!Q!$3KE<=M7E}rXzOtDnuIjTJWkh&NJ!E4#vrEu_^@&4=!-#(@d0t`S$%g9f0i z3~hg&9{%S&-<1JXF*>e&w)~zvvm2eB8ZXBI`B)6_%lX>K{=^|K@pGuCQWg#MCAh_W!P{_yt`R(hn?H&y#-1aH3DGc7UkP#eK5d&aAi9pzDS)v`q;T#? z@cw;}@BJEVAf_Gstrxqv9G;vunc7l|i>1Y4_rZXcJ+OR#ur}$4W^@${sX&1~$Y=#R zM1aqwHG$`VmO;a(R81J7QReAA?oyzxGRI5$EHPIEix51?mQ$;}FJwk0Zxezx74|HC z9Sj#v1Zc%f#%+-8{49C`WryCO<|1zC(hIy~vp&p<3S6^AC|YUKIrsMmAB;Y}BaL;{ zhg#WTTT}kkC)H=$JDCE2lb^3K(aKD_{?ifZip*|>LMjEFq{lUz({d^zQ&m}MVDc<6 zJkA7hyWyY|5YWl^42jjApq7ITqbkklkWD*o3NUf8W1@3I=_JI9Z^c-o5^!cZ-b1GU%4A1y;t~5R*dX%)X3kX>@#Eg;EwePfvhZQ)O5<<0)z+ zjjk(=*w)_KJ~|BD=1zkOR;%_w@X<01p1)USr?FHn+OtUcF;}>q{$U1eU2Fz;5pPU_ zPw&#+cQ2O~?c#p;#vs$#I#&Q*eenr~^$18XwY3%GXk2Dxj;Z7f%^Z-YWL)_5AEeYl z3zyb*m2#McHwj>!S7Wf%NSiKJkv!)xzG(KNiFJe;*vvA0^7QcHI6dj0hKp!xvyo*0 z$X^6g?qejy_vX?JK&A^=G>AS{zJW%2Fe8DO{d4yvK^ADYx@Bl2z_H9>H!71ccZ~Tm zAiW>lI6EcUh`}HVeb1bv{Ug#<2Ckwp(0<}8yFnL_(clvY(Rk?*qbFn?Lnspj1oeW^ zvMdB=I$FSi!sVDBd}%w_NJLyMrn!UZI;%md6&AP=CB^o zOz+(e!E{=%(wy16jEW0r?jRt!cm1_TAR7X~oM;^#m8@n!u?X&k5n#t9@YEOw%a{z+?V8Cv8(?i@Vt>SQe!vsO&9K?XFGZ%n`E#6`T%euy? z+M9{d!##9TR%;*lFl*{~GZ-)>LgyZ$)o7my=4F_0md~E734mOeL6v(6(gKgRd6s_E z;oma|og2G!&w&4KPvYb|j2c1h^=Fnub2gP#8k$Z`a9xLQO+xKqd1daO@-_x?D}q=N z%r{^pk_JAC?${{SC0Y#F*N3v8soacrGp$6mdZXjLpMr5~QJ}-1iQ@*nc>=o8=Gt(y zfC*Q1Nd`5by{t`Zhj#cTi1e$X#D$hi5BO+w{GgNh&0C?;RLbAb80R?)pT7Wc{bsNZ z8XgFwhd+AyU_qKJiOr>8%iV`HDF`p~k;G z@ss{Um(x7S>oi06Np3C1Mcr5#EdbYQ&9SG6dqHp0E{0LR6}pzi894t0%a0D0oUEuk zGb3inDJqY}h(1r+2QwU_eF3JTVMFxNbBxCMZfU7KFwok$bN_KOFBUGN;D?Xh+!t)|iA=EmZj@(D~(5=?3R>+B7a?HeZH)Ay1dhG-i<1^eu2IJ)-`70n4ODn}lj!*mS;l_=Y<%3$@;ImOPcXs)G<|K+~l>iz1vY3Ps#yRdm{ zXaHIa8Q?Q|3qhcY%hK}=4dO9Z%Dic$Mi-Z69(S8ahetBc7z?pb^7w^H2( zb!cKGWs-|xqRfF*hD<|U-BtZ@kbsk$r{~q*^UerFf|#Yos0Nk~KE3g_0wi#O+y=lq zonTM|PYFzl0Pkb~he~tw@NEz6`Q(dxR4+vApsV-Wzk%YIE`JE(_3#+QbPu3$#zETW zEi&Aom7E3>q=-l^gd6~Qe*Bd52v19ZY~LHwJ}3|M`mZkD3PHck#FlawRUrHlg$snL zXTir=2nChO=sYzr_pg^28-fFfN>NWi(2s(;T|*yjUh9!rEImyJWi}Vb>Jzok>8lJz z=V8rOLF$UG($oJu`*?byS_L`^$0O*6^WQ1>%VQ_kSj1;Jl}#vP!LmTMTM{@7#-aB`8aK`PW9*1Dg>&G{++7PdDFBQ?UtX?_fBJ zF1%gkfZj*P2iP@%FMENds5r^2XDk_m64fO*R&}@x=vL4UXff-&hBoJGh`l!A+)L$6DW-!Ksm9KbAW;+un2>9A5)4k z0o2iE<x0`N8D5U=lWSSh2TpSvTZ3rTAW&CUy^$9O4tVe!cLy-e z1h#;ZHsj8A!Rn?!H9^IrEdX2?H5To|tz#+&yew_#^8qoKG6xU;wx){eIywa%!SPM> zDW^uVa;qywLsiLm{k!c9FAkK|ffX^HQ+vUHRS`Cgm64Wja5H!qA>V%>A&D-bVWL+r z-a&_Q|8)$K&wkRJJPawY^GcX!){KB6c@7=3&}e_4r2X(UJ!^hWT&ro+MMm5`Jb3YR zm55v_U|_zS{^EzyDi;Bsyil?a5dkXnHPEy?pNVl14g&so`zzJEq7Ff@M4x*M3~!rV ze^~m3d&j)?)Zq{E%%mP2f$jiOj%(m4fEvbsgyHc1C!MM4Qqtnm1fxujG=>+Teb9Z{ zoanQ5n!&dqy(=Pgo?MpMWHVnvW5tK}>tmlkH!gZ%(Wf`tCdJsI3Bv^~U|jU{rSFXy z*8Hj_p&My99H%ye%KF>Le3oOrrHdwn5O zS&(=!pmw-(Z=nE6CMaKdpUdPjfV6j?5=AWu4VDvu@`5WPkSXEH11pdI@je3`Ng!sE zXa1k>VufW~0v#a6|0<6hVYD+7#>pH(Kxjm+1FMw>r$tcVh2~1YR01wS6{wSRD9@i_x(xos75^wtYd<3_b2OHyn&JXaiO>;8c}G z?N>PseGBT;`!dBAW5>|JrBKeuAlJ*D;gWy+;91dyN7C^?n+T_IJ7b99%A<}9gLv~2 zxH79Pp&2^7Z3((6qoDNUgBAYm&PSG07=(fXXXYeJ3h(5r+^E2X{@)0O4G_X-Cpm6f=At>O@}#YWkD2zvfRC=Lru9fq=WV<^q7g=Qy}e= z5L~5z(ZE1v!UuyGk$|K1?WZBi7idluT+nKV!E~scq&H)lSdh6vfZh}wKE)OD)U-;y z2Uy4X$3D14Ce(@$zQkQ{@2v$aYgcbgmi}#sVJTTgm<7f~B!~dl{50Zex%$B5Ni?YV)s-EtnJz0`)}#sfe!Eq$*o z3{ssR+8_v^)zZDe>}Vy&C{OUJ;8@n%qhNq?y=pJ>tU_)B%&tH;u;w8!fbr>;ybGSo zXlkVUBGZ^yfajV>ZdG+LYKs^Of&mCivi6SjpfAH-`?V2$7|I-jKzpkYk`=~FB{WnW z(a>^1uiw2}Q>6EbvdF8^Kh>aBg9}qMwFm4l1JS-3?GFn4ju&iqe@HfR&OyX^D~c zkoNl+JQi?n7a89T8N(F7`@lx&n=Q)RgVyhnl{4*cq8T?qbV>=&DX=ARYaSiV#2B2H zu|bxK7446LP{uEur4<3%aEYraH%}|8(dh^G3c$r z;7la%LPPFrG62q4=7|b@a@_IV_g;p$gQbi4Pv5Eim)mkXCC%DTqqa?h3A}Z!+i&8^ zt=#bz&nrk@We{l}CFEJBF8?|k!d6tr8h3aVN9^m*5B@0ewEN*(Q0eFeRIEzFUxe^X zh#J+y#dWmPIu=9}HHd8ELbM-hIj;68{XMgT$*W8g9juk{u^Sfc zfyxDq2~#ekp^BxY(=LG))ILCP{nyZd0w&V9Dd|)9qz&3<17wSo zuNa&u6O=E9s9g`BwHRAd?wy!!f@;_L`R^h2LGSz=Y#AhQh2VydqSvlT#a{}#xyo#Z zb?_FMr0i>s_}hKIQR&6)0Gt{jY6XKt`zZ+RV|LO1=Z4?l)^dQ(F8Y&pO6A!F&bp?; zReKIwk$YV!Aac95)Ctgz3Cmsaw zs7=P^F3pLzIKjCEtx$L!ep=!zb7L6f0*dJZV~qj+arQ^vhDy<$f{H%)U3(m(vkK(2 z=413QuKDak9|UP1t>cvhoQBUibV^J4@_0C!8N9b9tMx(Ub+7)EN4nS##=QR<#w6?4 zXODw%ErJ6E;Za1!p~d{2b)K?!R$fB04y4Ymy_mRo|JU!TAXq)$udvR7FTuElW1w?Sf&tpQVve~j)zVC{ znaRU?W>7l8n?Q@IGC^f{O@UY(1&7HZt!;+nSPTn1?WIgDH?%C7BAkl`YC*~r>i%R# z4=vcT-OuF?AV~AV z_3yLP`FVm>f#{1Ui`|IX70PEfShT=|`uU4nnQf}vqsgEY(2fyKytQZ#0jf;s!%#Q| ze5?+DN*7H_FSwJLt79B8-7?t&V%piRhlaJ=1kUG@6?JQ$DnJ9Mj|8(%XDIMmzTAHf zs1Oty!IKL3;vf|2Bt3EXDsmu>xlk6eygSUTSSoDRcRhg)phf$Ol;}m(@uGldSwk5P zfc6_`7ATbl`YJPV(42q%UitI*u|M7Z$`Crs2f+mH5L`2GCd9}=?Y*bWtA`IK=;7Xd zS>99Rbz0x5Eid1Dbq)hPeg_v`rQ@$Z0S2hs&nc+8AnncELZ$^^mw`xRQW{$9=Io`f zw~!Hi6s2mm^j-Mg(XmB_(%?|ZafnD2tn&;R;NwTZih7&DLwSlaH!wi^u`X`H7Tiqc zg$nJZQ}?^~%Cur@=QuP|pfpoN2xrXJB!Pt{(80MjE66xFjd4+a0x`sRkbR=E`rI=N zAsWIFq=OFL=DC2;QIQNP9r0~Y`vSn;czTo>2e3A9(XF7XT(JDUV4>NCsa^s4(;dt- zUJ)n&c{dJiv{$egriQuyipP~KA3F*02ApY@_O%b56lE(5p- zHi0}4=Q`4u<%|sFXlU#7#6U9ZN+BrH#LVyl0p581{LT$f2HAN3;RA?# zkl>V38`=x%d=f(RekjEto(*qZ)Ve~dnQ8?WZ`R&9L;q-_llIQD^{rbf(G0kJuN6X& zaOp>)bTKUQQq{rBR&KIOhFE`S#M}Zf{GLLTi4n4G$YO0u)A`Gy{36|E}gY&Y(19&{9R3Xo;^;ARLO^p&mB1Ugo9t$%c3C-_v5wCOH@ z#UkU~+w3Q_@0u_j94xHSz$*7kI|4jOi>Tlw30#m$^zMQtG*}H;Cy$~`8j(Cu73FF( zbc;XkwtIdjVrj3#j}1VjSCwO+@r*h)eV{5ksneok3KYXA25?V|%3y+xs&(0-N+ygt ztwB-QGH+$T#BVHmNI6>iB89spaCjB}Trd)Y~_Av<=`FibRsL-vn z;<8NPay2X9JG$YxbM&D-A6;1KJSO8`;~8|x9^;x9V`%Jw#_Yj#sGw>@NBO8NDDBgH z@naEQ-Y~W|@3HYKtixP)btG8QUIXj3jtE_2)-k4lGXr2-ApOZkv&D4jn=hi1XBE8r z*ny|^)us1usn$FHb=PxjbV|pDf4e&AzH|(8-BLD77`{B42Z#mp$ZtBL1^Dmn4u3rh zK7LBo7~3VYWVZ4H>!^i$)!y|R;zD9T8!UrqZeTzjD0QoYzRn8rl)jzWX?$^Ec5FhwEmN0*fH`bB`TV)3PcHKY2QNe?9N`d^as0c>Pxn5I~X$aC!v@ zIe$wX#A^?LWhIQ~GhxUUAVMvP(iyPXB<*syA};*?O$i?MzrbUP#BN^gEZ2_ zEjfc!XD?Ks+sOEN{f?qD49#HWtFW9?Xq^N(Smyrvy}Pw8O#0!I5V$TbaYBiI&c zsWNU|<9d&RTb4&Q_Q4_-_GwYU5YKXEi+K)YieS`z4Ikc)j#d!kU%-&FZ8LR9 zdapbUS#c(}c^h(nx}YAStTAtKeIE+r6|k$+zB@yQ(IdXAxm-n{+sSe5aoeDr+?Ntn z*3*L#+f~p2{IkFUKp`fc9AK zs3*qe12ir@&LG%kUHrOK_Z?9CSDs-(XOE`Tdu_`UM0zh6S%&)WtQCN4fURK$TCY2AQL+ zqg;6kD~i9&q_x?MIU(&cB9=us7jgRnyK&B?;X-g*;=;3eZ56Pe|88n;(aHt6fm$URzS;Z=jpN< z%^&)-Z+savJ!459)D_>qzrqN7;|{PhF^voXKYb8Nl{BI)c2Ma1Nl=b-EcnPJum0$f;bv$CZ@uf}UXu_5gV-^Abms3{=&QhOa+FJs__ zcOKDxxk2x69yF_{N^7VnFG0Ub?i{Ge>5KI4;orwPr}e`cL_0>O1C1c<^V$p<;Oebl zTs`pFEh2^UK-%UC%M1_+isn)6+p3J!aXs51V8D!*$O0CT_#8j)tq~uGKB)5aW_9MdvTT+Ez|N<2uHmIg}2E3Sgip6;fATC5;w=avA**!)9~6aF8M&|BB|X$ z1sFV)hhKzs^jD^mF>rbyR2BC^+CzJI)qa?ujgA_l@i^WM;@$*rK9x8D&El8NZ7@q2 zK0pAd_r2%985BC0+uWMwoE~vb*Z#?LcYQ_^v^>xPXx^-SEDIW=rhp}Aw2q5tq4%fW zzIP!45}<9h&k}#~Q|Zuo^O-r?YxLkuU$}HeLulXMIR4s?pjuQ^*o~HNFRxA%)1e{q zCt3%n19bfBzlc5j22F8RCM{6lau^3_WU>@wsUQkg#RgrRS5qSjxC$I-!ysCMu|^ww z4YAT@p;+hQ1z{s1X&~V8D`0zj;|xxq(s)vo7%ebFpGsJT;tZl!)&~xDP5u8K6d^Gy4qB$tNnet3PmllJRN$44D5aM&>Jr;@H7tEkGg&( z0zbTg*C=2tCCGGdju#}2NeldgXTd)ESzJzhO}>xb%M2>NeiQh<#;<=ew6;#@P zAD|(W0ig-XyqK$jp0nUH<*0R^-L?&tQ@ufLz2V?MkrB*RhNRPFfZ@2iA}yV>BmoS_ zcF;LxD|)GQ59~xGPYooB;HiPg6p_M9MR0W$Q8n`rYc7p6C6C=VfeC2YO?#W+I~cK1 zAYNMgWhG`k&>u)Ya$~k|l##FT!DHy?vd+aTW1y_>h2nG!hF5-BOl^0~#>1a?_r0oWKiVO6CwYP4DPERDMsA6PR%6QC-$p0&!AM(N+ z6+h7a=MV1(PcW1?@VdSrfc82HUQhcsBpVDaV4gj!Of2$jgH+Hkh5-)hu%#oqBFYZ` zbEZDNYjdi9WYTEq@~M37&l{MaF4zi{5x`*N6;%1P#T)tr+=hc?6I?Cf@Au!(i`Hpc ztER0SJRbx^{})Hg2+iOps?N7Vq0;(*iZ8kdPy$+Psv6w5_U}zlEg;t8`6#deFEGJ} z&qjB1%W;03r4AXJ4yd&4A}`!en{YGt+o>d65bvt-Nt-JeT; z5RG%~p^Qz2DD5}E0%_%jA|0(CJp{R^f}aIOd!f++Wh|HFq_LNsKrk!S<%iyS2?DnV zZh?1LhE7)45;&mh*j(sb3hRpsfl;3QfLAV?W&P2isu!bWmx}|mr9o<+W^&~1?V}r+ zwBH2%2hd_bWQIua^plK6yCL4>kO1qDpe{#OlVZ7g9ezE947(P3y;SdIti+U7(l&w8 z$pww#$zdFl=1gXpumkDfx@m9T+9o@}GC8jcq$BIv%c7r#V2FS5yWS%0hk_;@2qib>pg+a1~aE07P^iOG=M6`$C>OfX@PHpxE}5C36fi9 z-ygo;bN~Tli3rSF6om%ntgjS18TuNpL%VH;XBTj-K%NNN2?&g0a?n;lkfD^Tj$cVs z(cwGZh;~tF{noI|D4$h1JF8OIwiWGz8>2E!_}DbhOP?nkFsM?i!8#)P{jNT}2Q3_= zy)EKg=Wd*6VufbZ31(MQl>yM^UVE#9Lqd}KWt0z9#w?}^P^A5o5tNC-nf%DWeCa)< z2D#or(ZLsK+_{Bb?N5)TLrgI5UB+?Sa6W6@^?NJ9y_{INfWZK;NIG3v2pV(1jV_PO zphf8xt}kQ=tivlPp_|ha8$DUH1l|zM%zN!oCUqJbHvp*1Xc=DDpo~?ir@|J z%J0D#T!JglKz0=6H~1z;Kw~xV$@7sh;p}o#`5}MO#g%*Ad5TD0Ege)35*(w!vkc>A zuAJ^I1{pwhWl7+GBNqxZix7@y*QD;F9ik^deEG|#J9c_Lxdp1)RWx%M7{2-)QNZab zUIqvjQ3r9Hk5>+VyXzi^`b_Q5%vN>@I?5SKfTIe6H*Y)^$zko!rjAjOPy>6ow{WIB zeZx|A#tg=l37CxnZnc7rD<~_af3%yc+m?%__73vs7}Yh_jLXl0vDTbq$^hk{Op{uyL50QCdyjBg zI-I$6_pt^K>2Z7yYU)Fr!+P7>6rQ)ZbnRq6WM ze>@fuM?Le%U#tH4UU6B_33y zeLl(#8c7FlVqEqP=r2FGGlH?i^$D{4mDGDS7K=TM%F^1m2{BUN2F9BmO_-&kF`dx@ zEYHU>Fmfj9xZb`E-V(||?>+zqRIhYDmMZbS5OZiqN*ay#mDc@^f|3Op5Av7A7Cv619 zn6CZ6!r0+D0d)uV-VkbU*QvH5Uv9-~_U4lu9xse5!XS%FHB ziWmJ?r5(^`oCK?8XtRVELGSz)3^;bYK8VIRQ0HZ+@BZV?8)Z~@0T23rUU;T%c2z~P z^fO`^BH8BHEFaf{{1(l+tE#NF2kaedkcpNB@3-;oc&5&T&&WawWWRk)3!}jfr2TCG z5;*)(M70{_Aq-r)$9P?dDUGM?Kj}dKfBvzoU8;DbiQ6Q%@&yjJ_x$>Luoof@ScAZd!@WY-0A56 z<{y{N%`jHEg9x@e>IafC8Q11BmtKX)OR%K$4yHl_;>&F}B;H~Koc&Go{quzvIOnbV z^|AR-sLg+U<+hYomkH@*-2L%)XZ0z`x~3~bnOUj!=0fL8doT1&R@g-ye!kZ8NN5}8 z0x(MJ0a>8aH+@2u=Hkg_CSMZ-D_VwoqW616iAI{1W1n@>{lAELZ0zGr;YSbLAH8 zKhbHg3+%j@U#i$ILA~-U7fJUSqFGe|+6Nfl9q#?-+55Cl3`x&XzLaL|oLp8L*9RE- zq#|PsFYHaf);aa%HJ*SXnASBY-#B?JItTW^rp)}!NwrXi(=B#UK}Qcv98LY-_dWXn zy23!~El0;hf9D>^6l)@Q?ngiBPdW*OYhu|IXn*+RbH)b`f}Q&T?^8{n!lcP1#@PZ0 zC<&Vq9$GyV2Y_6@Q;=*iwMKje_MfeywEW!X5?5)IF|n`u!K)yz$x{=veJZp}7RbQIHMqKD-ceT>BjoTY0eUHNN~zR71qI z?-?-Fur~XL=RSXo)}$2$TJ22In^*t6(gzK0t#kYEWr#{F?ipy`)?OJLXONEaR-vO| z(iY&RB%Z^feUCWH5W<3|{l!@O)l)PUx!SpOFl`0vP;}6hyff8-7zVs82>g4wdL4XD zRC&0zp=NPwzAWw5<1$bAmD>WGxI_a(R{P<=DJagqG$ey+R+Y#Tv%ACnqv+t(fy0mJ zLw)lW=@QNwKEso-Tnq=UfLrSPHVai&t*97aHuC9*uJu(Wv-d~iv+u}PyS$(r0l6Z; zN1C;;gQnfoxyI;>EpYdQHE=*30UKpAU_9;5e=k(RzXYa&EVZ2z)HvID1f#pE$y>R|2X?1TIC*Kjg@Bb*w!G{ zW^LCzpC5=h01Sv2hFD>6Qt4EkL)Tu|vl$x$^z6A8hR$d&pP|znfcCxR>CazYDyN_K z$~If1AN<@cqg7F9@<(kn>3_cv?OVFT35)`oF3ZXgz-%YW zM9X>0yM&K|I(V#dHZ-<)-ZRF=G6+Uhr&?v*q?6Q380k6^ zq0##83E8HO$+w@70a~$vhAyIa0QwR*mUsSnh$?AmpG{wAlm>HnUeptry->6|0eSIf zU^GJ{2;h>M{fGR@s4y}Z-v^*Q#?rp_K2nj9N$Ugx`bB6z)yxRO_p+o1oMFF2b0nL< zf=#vl{@L0$6|}W+o;n&DLqw2o=K{sOn}wiH@AZt}YAU$x6c5ek&4VXx(`Zrsy}vVR(X%p{!`c`5r0L$` zE=q9&q{(UU@S|HPwg=ya<&%@iDx4UegGKeMZDw<3jo(3Ex*X4K>3C23@Sp|l?g(Wi z?JX+2r6+S7A+jeUjcdHa0JdAQwC5nEzv6)m^srn57k}g{%6CP0Z3IPwfU;V8Cp_)bvt`k=(w8^i2d=$I;*thUK<(J} zbRS~}2+pHn?Ldj6^s)Rw0t!&hh}Ge!y)Wu)#;<*@nYfMKF!^Q_REE*8%+x-xMLW?F z+0s`8vB}U@(ILIUL%w|Y2EDz;2<$DY=j{dH=7A9rI$xyO0k4xG#B2pRI+ z#xal^D7whU9s*!&3Ep^0eyEPt*#RB6(|yUbekdq`*4P69+yTJbdM@a_J0gr8$Gf1h zE-(lGOB_U?n~8OTR$!!`v|M={0=WLptEAOr%#$kc@rA>QCaz}98;#0aqV}CY0ftv3jvQdrBy;4 z{z9Xd<=vmjJVr8$02jm*>gy|GS=>1MVUc*6R|kFLMQf;V*`^+;4~z2V_eJhT%2v|^0_4sq>Rt9WC5kt z(vGU0lw9~Z8Yv(kaz`W&ES&_a+2EGw=&3McGsAm?VXVEY3kk4<027TOb?!MYsyDOv zVVwwPXc!Y3HBl4cyPy?&wwBB@=Nqc z{jm0p1!$lBMqOL21YLl;h^w!%cVPM2(-2%$ki*7th{L;GAao$qKyLtcjB!DbllC_6 zu`CmB`2a0K0^a!*PhcxfXiU-=Yaqsqz%zKBg%;q3=t-5)(9Zu_bwgBx80$czxI}`*$GhkK|qeW{6dJa3C$Q*CZ1P&q?@5-fJ717ECPTSQ*`h= zH%A6MU<56I=vg3vX{3XmZ_5}2_k4pMjG{&Il!d8hfq?aK7D2T(85 zN-mj;;^6{XH!6%d1n}gMpp()B_npdbcI$|Pw$K-6D%bm&tEcrAl-vz49xK>{U;?QG z3{3Bhpl!Ugza~Mc0cl?xfm|9Ju`71de(;3dncDa4I%c5Gl!9G&u#gT7hy?>m8^Bt7 zV}h7MB`o|$@&4m`b=!IE=o$jOe(%w-0yF|H-v+LI=RR(M4A69Sym9MT z=%IyG&~cF?XXfdm5M%vUVvp(i*Pr}bW}+ENDd;GiZKvdYgqepQ2sGmJa(#y6-T+V9 zOZzFfp~L@jxper3^kC0;uAC}V1pOhHhhU2ZO4%*&BF9n(zyKfZhjT^u9-$3CJR8nj z2iiNhi>SlPKzEb@dlB0IU$Ez9fOozX#$=P%^8@L;=&27L<)&&QxprsJ5{Tvl`ngFS zY6oIY)-rN{!`JmguRSCkU*nfv;_7;N$l&Ca$Ma4M$pjXc`6DlW(43YL@NQ5b1LEB$ zuRoIn$)RZcuz&-vnq}ZVfjW?7+^qdYLVDzldC_&=!7~V&8S~#n@(v9SFruvbxb|xx z%*+;LLAM!JJwW@ZEC%XMv~&oc5W$<6nJ#|q29H=qtM@;j`OY7o{iV^%BjFUYDZ~`y z0Rb44i2F(tjX&OYhq9FR3YgIv{r+>KGEL`dU8mf;$Jfn%E~jxvqxP@1K7R@AutY7I)Jk}w(PgIaQ4~re zON91Yu==ozXqgagdMCq6hp%0Q=tC>CSie4?EAQR|mA4Q<;nwm*kT-%fc%d0RXFyy5 zL%kBD$^p#)ENV9c&v}0)mX0|q?;*$3irh-I9X!ST0v|ss(#geMm5Au=&Yia&Lob7b zRT#)}u+Z}zAX;Vp04!xcO(n%(pfU=21-un=iA(Di_b9DktT3C#3~s9_GQ-oZsH(;= zrBZfEI%^>gKP=CT$=>0Gl2{B_Vzr+pht&RmA*6uW15Auwe{`7U*zE*6I8qiaJTa0- zmrjC?;wmi-7$O)v_5om@eFv-zG=JgQyj}*jVcNYIqTYN$<$|wv!$TJkZpUkBAKRA> zaNEs-p$}|sfeoK~qJ}xpr-qsBz>#lwwyUms8DRuiJdagaIs+1*rh#Z39lp?<^_DH= zrHf^L9~1;y1}URgK`mwAtAY#-pm{9|Ox#Hoob7a0@|5GJw9qkHhk<(KE-)RmQbKWH zw~BeapH@}{3tB+PN$_zK&yffMY_X!E-&CAnXk&Gup#i5LQ?qG;Nz{MjH=<=sc$VG> zh8CU_x8GYMT`Vv|Obozj&A{BFmEL($y1+lVyU5r&3S}lWTsmprldE8ZA<_ZPs#q$m z?#oZo*Z|iEXun*R*q9dxz47z!onqhs6%jnq3DD~|f~};C`?Kf-d~|mM1e0ml4otvf zXsILr7KnFgfDs>4X!75$ippkwY5y|f@P8jW_o2tIV`3@z;|&jipR|DWT6iS~?mPb#4CCIa97p7c+6+MHJr zgFc$68pP}b^nW=AUHz_gH(d}ydncHRPL4D}3DQ1~2<0f05%sP)D}!iB+Jhn(M1Q^a z)j#~2fuj9+L;9I$X?so5;ED@G&5GplrFLQ9W9Cn9l3stGVNt+oY+y=6Ik&_5#>3oQ z!K$MCOw1peSBKM@_JR8#=CwM(r5`yZ)2_fKh$f+n)Vfol0$m_(s=kH|zpYN~f28L5 zp~V2>#gBnhLa`f29xFP|-h2;fGr*HY6>ci#9g4YC5DBKXB4fg7n4lo-iPH;e2%{>? zuob|_;VJ>76bJfbB3@Aag2s@Xg z@{*7&Y3%SKtU^Gk2=MFof*r3fOlA^(6Itcx^XkTjv=+=AQ2+DSKm6t-^r$%Ysi-;A z#UfHKvqBF4vm=^C+z!Cp;Qi_-YR2^zjVV~*1%YE_qgi8BdN-6{WzbmY%0SS{^eOsB zOv*jc$5&pNGRC5i+2raC5dk`PYo2!Jq?6N6C4BsJqw6eGfu+&RAX1Bf#v|-`8+8H! zU7cfDS8i^JPlG-oUDl7k2PIt^e8mN5|8>olmcb+MKDp}1@X1lx#+c%1>p)zI;QBMo zTsRPz0LBZfXy3>$$dGPu23u%8813=t1KHpi%o)J#lZU~%cpngr>f``smj}jl5sYPN zf9TuSJ3hJJpzd|buF4*}m|;t#ucS3bxDG)39Tn|eQM$j1X$X|;^Lokw$+l}p(o9_k ztul*2BbXiN39NqqEE)_L^8rm~9*62q0EIPJHFxpdbEN50`D3*8bN5 zXT(NC`4!s*j1*hQw2PW6yzo~&b;I@>q%(ysmpP_#M?yJ(yhhi#K zfvy~;k0#r}0zk?p41#J9ot6aZ9srw-VD>xGGpD0z0HZ}2%L|Rc8ed-B0P58KMJkk| zpec%ss(db@Q5X%zlhI(gdtg8crP?+$7QGn|YZt)%Fx~{o+S6h4fln7LyUBeBCe$vn z(KPaYK~n+8L2jaEU3$__v~?~FD9RE^RkTP58eoGJ>R7mRf=8Ot2c_Yd0_kAkkSfp6 zcnHfnz#abahFd%!RH>P;Woq8+AD-=B$eHEhXm8-lU;Rg6o~TD2Wz<5YKjhNgQ0l|f zs_Q3f(JZq~sZ69#JbCZ@CWdLYvyo~O zXmV#E@nG8L`55|b131>=tcV z3$+muu|-8epnG|`TTh=}>;8oMJp0}GD%j`VKX5PWd58V(ufA{Zcls(t4H-S^2cq*l zjxk|*uK;o`zBYH^B$OjE23J3Z#!B_ok%aoUf4^Jir&$}ojkj;U2EoPvaM1>e*mwf_ z>GU<7EHYQLV;3U}G=Nx(Te*trAg~%x33oC|%NVa5l~)c9eDE5Rp{EZlJwr_3*>d;? zZyT1tIL3xe!E<8zaOzlCVou;p#Q}LFnr3@tcdI>Up|w;}G?OK;ydR_{bx{>OY!mEbc>c&?qxgz)rw$ zSwZFmvGp#C1aA|qqEb(N`HM_gww2&nW2|00#apPfJSwUSOz*S8(-|>X19oi&SFg4eLD>od0y~d_)5*@Ju{|>-u}r-`#6u3^vXj|o#^E$LXmxZL&tD=RVufZo&W9Dvf*sZc=*$rqfwEf!?->jVz1K44M^uIv~Z>jv!VcGfJq17Zxv1fY%DXN>b*>Loy9c`&<7ZNHV~jpytLQ=0PEf}A_sx*`P-{+7=zf6+TKKr@~eA03?r0tkAN)^`eR1-M<|yuogQSCPkf3cF^%0hv9=nA2@R14>6lMw_wC;Zkwv~x5>=K2Sx7Osol!67lK&SzyNbczzqPb2Nsi? z@y4TCj285j)K8?d?*Y@*AH66V_@uMH8Ma$rZEkdl#Y~Y47+sNR95%?kad`~P&3nMu z^SDspun6!97NwxqE^-E*xAJF;>-*QNg?Zz*m zrON2I2=LyxG||;(PelzaEoDBh{L8O0oqw`6zLKuM+_;1~a?dFbPzM0N>XKR%{HR3_HL&>Bc=`rrUv< z|9IvBh#(K{jSCSBuD0Y>^z$sF@x4q2py%?hJDt&mLH)mrMf-^R;n}?wV!qse!2W|g zF>vi97*jJM=-mA&u25#1zz$qE8SXda$B8XWSV1@M0TrIRz`H@!C9^R+qLY~@h`sa( zbKKnoW)ahr2=H>y$T7B|qt;%rmND-PFzc+KI1jUfeuS;>{}dJ`M1A)D zQJE~<+CKt~X$kP*dav|^YI9Lc{F*hebdW{849{`_K6&iJN2j<>)sfUukV_4z6oRe=qHK4YpGC}mar={+#UO_w1w)-lkeGp!)Malf+?8K1)gyX+9^ z7r2?q*B=H0QUl%A>gx2>FP_N^%TfOcn%2&O82y`LckO6M=WRM4JU1~szN6tPAh2Zu6v zynJoIesJ|f4-z>0^xhq!f&1?%0Ur)E=WkwWpJ$PM{1_O!qdN%jUKE)mLZ^Dd_22B{ zHqAi}a4X1JT#PDx8yo|vz#YinPz>r%H)*#s+Mc_W0ZOG zUGO3hQ=6;KUflD=yTyEF15hk!7qRaEV>%98AwZ$s$z<5k2o}!@SpSoDim8{!XXOUi z6M*>T9fJ^N=Nxa=-gMWchq-9o#%Kg-k3pjkyAvur9s8iDYP;_YG(o8Dn9Sdiz#0at zC|0Iwm|J5e{`qAU%a%0tJpV98E?kv|B?kO2w>_l($1}*At`6a&f^>#MZ7b^qZwDFh zzVa&c12V4D?!ZV#iiHd8s-K?-wK8DOXzNy0-p%1=LRbhytx9v z^w~YfL<3)o1Jh4nU7^ws>Qy22oqy998CW?m_FvEZ3`5r_vC-`Uw=(yIL}OH zQ0$e1EMqGu85CuW9)S?-TxezC`Rb;4<;oq6VB5mCx3hIEGtZfrwRC~{lXoPW&L ze~uvw2w+h&C|p_p`_Fe|aVazctjG_ZrN^grbcRDQhz&M%Ff%iC^SgR#93z0&_XpAc zX7kZNZu=m8HpQx}2NgQ_)QkkUTaSMDwoaaLzxgnjbbUc%p4Jcgwm<+BQ4G#u&#TWv z(9efK0-GIj7L=4LhFKS`6KIIZ+f=MeeY>t!t}b|3x5hA22X`I_avT9OFyhN$spaZ@ z5SjD@z|&uPcXU%`0hE*#))kNz(gl9;p5#1sQNa*IZLu*ll+PY$%;(}q)dG5;{rROc zA3rxkm+*E3u#NB@3}l1+L`{Wg1DTfCBO=7e^^7)+U!rB#OTuhOfx)>08crfM96^Gs)%Ivw={q;9Vg38_)8j!?ri$VL)Rbw z>ON1H1zr&2A(b+SI{4+&3s9K?bng~WP!wxWyT4)qX5(cAt0zz0P_k@b zCZ1woY1nzet|+!wf%ct=8|mPhhZDiF+%wwsG3(i-o_@$L3V{ePvyk} z3_JbQsw42(iM?W9U<~)}<^9Og(kM2A2ejq0FZ?UgVd@og@~o~Zo_-C)jq0oDf^gdb z6Po}qxAc!!ewQSuA06+1<@o{ z^_{<{quyOZ9v%@8-~dEEEItJVo<@cX76u+OC{{ zQp)`ROn`;(@1J-cG9IKKy4wN0K4SSg+v)6w_fJ3=*vr0?7WLO(-d4Ue6VRwDQvKks zd{ybD=s0~b<1uxj6HV%l&%`}b< z=LJA6b3pG2crE$Cp(t~B0?*DX^Ko(N|0T=x*PgHXSo(Wg_`?x z{nmlOu1)joO8VfTaOhl23rMdq&Bn8K@zEDggN51iGFXpv*wT0Ry$aE#{s{TIniDUDbMYjEb5I4%vOPC43h*10rk-*0Gk6a-dzcP z<5{pE#`ud@zP$q?D#sffs9@dz>{WmtA9madcJ&ux;i9;PeGD%zU`v>FSsTeY%6$tC zW zTks(PXIZt1p>;o`OAgx)^C?ZN2A^bTm=-Z0CWZP8?GY#d9|SCb7$lE=S23_$TDx~m zS^D+m984f!y{|#70!>=*$^$)VV8Ye3*4%|58@q>kk!2G!rmvu-ts6?J47TFGXv}7O zoPc*912^89WljOZpqh53jt|$jt1c8A(3i|T|2zi8wo8wT`3Q5Tw`wfp>&L_pW`&$N zQd%Ozy&^vP8DtoPTfgGMk~mdn4#$L6u%l1>=(r zsunu~xCXMw5S&@wt(VN}O?ZK&v3hvbCSJ7|#9Rmj0qW~Jf@nsO0X8Ov_Y;!+CeRUz1;Y^AMjM#dBrv16De}C^i?hdHo znGD23O9DmcJJq!pWlB9MgqqvM69GdXJsbxS<@nDRUuYInMfR9(G%+x||FcHpC0P2& zi#rm8L;Ur&GhW_q$Z1U{3>B+T&~U;NRc(9(WEY5d<_d z`2_Q$9c|q8gsZpDs=NENSPS)C4I?J)&0mPw6C!}&^wq9}Y8q2Nkp|5tqaR#5w=C1t z5W~dq>ShiAj1J>HvBdkEE4Q~DB+%Ezfad`0|NI~C9oIY3z48FetA#RMcwD_BlWWOi z`Sj8u>D74U9x+V%8*@;YO9HzH_tn@h9y5%ha0R-Qp-t}l(X>Y- zFBiL2yYl@IV`XHCH{?$u}oO=v+Gc z#A4Q0p-!u> zbXd9g6PX;!N$nblT-J%s>=@q))*!R=fi6xls4tR&+6>BN=`g`VKy-(9ltrh+OeThm zK2NY#$O8}1H>(e&^LQFlc(?kGQ!j&Ge-;dg2d%k<`K$bkTP)HGvw7vqd=tZTJVpkd(VXUv zbfr7ec*c#$#emBK;t#0a0gYSR2$q|fDFgJlFm-$MmaJY{(VOyiXD2cTCxGjSL=-My z00i+y093I?nfroRmr^LG(+$tf={~`QGmuQ8kAI`yq99hi9Sm~bKUoZMoc_0;eH~nV zdo?7$tYoVMGSz=HnW5>;Ia?ZR0sp+?5eW3pV%B(ZB$ML%XMYC19poJWW@Gy=0WtA+ zf_Sn3kh^K;7Wx=qil)@$?{4D;*0-fj=|ivShE1Oz&+Gsf6hSa->Tg>y@%(^0Xu_iY zCSa4^EmrW^mP{^#UMsd-{W;WdW(K3MV;6&NHnr*G^xzZ3F3?A>Rq}ityr-$JX;fd^ z$2OBa&XsNUIscHH5QC%PZCn-*ySfr>;p?+<%m)naa4V=@lCo`pBS1=ed^6@iqNUZGx92XzJ1wTUIT^R>(_Ubh(!#TT(uxUIGq6` zg49o_n$RaoO&%CtJ0nwt+$hlY;mes28S1Y`)AVNO6FiR5HDEfzNCGaPR#0O5wYPs* z|CAaHf&^Rzn)*J8EMG427${99nG@?Z&;wn&jqYD&-k2JgxwPh!ErA4VU(2F?^q|P< zN=PF(ViSJhM9&IuIKY>8s5crzqi1lo|s$y>8b!lj;sQp~!M1>yMUCoPnV6~C&z#hG!LtM3zC8=x=?UhyUb2g^(K5*!xq&uA`#&lD z?Myac{oNLQ#*y=h&X|P3dQ@hH&%FSpDwy|LDC%jWdb?<8P}llT{=lAO-p{3&8!G1@ z#!N@Ry>@!ruDw3H^U#VpM+Z#@x`hqE2(a#d^-P$zsHSx&2@{d|U>tq=T9ufaHP>c5zd7U}J>( z1+0PP&7O3mj@bnsWM`XRZP#w&0N@?(o2Nzp5${s@+PeL`7&ji z;kgDv0x#TkXlE~zVebzoA1a4rw*%_)z@lidm_6_%nr<;ZG6Bvl0b3YXfn6sfMpvFS ztWaoI71~@*CjcuTmh5KGI0&FOwv49L>m$U-EH&T=De!dR0!)_8Y#KnWh;N>lZl?UBsQ-Jkh=I z4X=Qcvs|v+Zc7byZ)j)g*gyvSc!3tsF)=MbY`1mf=+4PYXJ2_YV33Y9FuS00p^7dN z?1BgzaWtrRf*97I27hj?pHC2h+6dFC4pBdbcCp$5g8eMfa5#pnw0IB;23XZ0kK1s-?rO%TLYRvKTcqo0WYr5M<2p~3G2H(sZMWP_W|}%L2d=4ly-JC4`#cr zmpS35`#Up)mT&<#cgT+c$p z?jaeOun^IbL^R#9`zc3Q8soeXm+r)9BF-JWPwZT1)~4tWpU9Q5Ils&+H8r&-up&zg zbAxm2o<2+u3;R2x3h;QIp4BMeHURDypm)s2n)4uZ(iNH(ERF5cTr-{PQ$me7^wlZe zYgkx<;3baN7^zfakMTY+#sQ+FL+mkZ%#U7QdT+njc;>Qs6FWtYST3K0Oo&|n3mSvf z0l)M2Br_+0Di&Y~wkkvLSP*-WpywE*n=$N~)^Ql=g)L6(pFQK?D7Mga7^1q+ZNan? zib=g7Acuf6%{UKa^`E_6G*+JKnSDpN0`5o9ZfF;un1DWPjBPfk+@}E@oC7YkFkL?l zRs`~AQx%kL3uAtkR)XVws^Z>}+4QyN2XBCnr-6O{?9<=? zuNeWl!l@3Bg&AgG^ElM`^LK6dRGoU8Rf2H@UE$aZ77e=iXa=9D8i?Xvq^GdE6dM!c zAKc}u_pb%leC_n2aRijEq;MJXac(Pl#Ww%-xYHHZ(3=nNepBJv%Y~1DY@nOJ1k<}t zhpKLuwpnO^8;C2>_bF%vAb=Ibg5ZL^K>&LRkl`tkTc)=Fb4|T&zcOY`071QA;e&Ni z+)LIdi~H~)SK~g2p_E|0#aAoWOrVdcU<;~~2%rK{b z2oT+|$}Onx?DS*^x979XxbE+RF1Ylxb~T1qe?L9Q&;r>aHgZ=CVtOLH|9D2Ms_2>F zfJwyo9Ls1ssKO$aeXHeALP1=Oz|p!JN;Yp$k_E2Ce}3+M?)$@EfiYd#UFa6(tF!ym ztYByZ0a02_%rh|*rD7G%X9HY>_RYqri%)DELI3W-w;I-;M5XJX7S->SqjV5vF1%zs zisu!yL4<>jet+f#_L2Tb_C-Dsc)te|6tJa$nGWFT!0T5Ms$PumIusfQQpJK#>(JK)o6P#p=j+38oda zH<*bU0s?gQG>%%e!&#vQI;TXAq%|`uSY(hPnmt)SE$tp!!Q^*b9JNB830v9j_d&gUY;~2I=y%gnKpglyEPD z=YBq+(UhZ2^766IA zY7Ij)G|Lga_!RHaWQ-5!bG8^q{i~whq-&TX8=<M6CTfhMpmcK84ABj} zAemfaI_&`kJAA=QW-h(O7Ud5DmXrOWuRma_a1Gb(Ot%Y8t2gplVlYK8nBL{oTY#f_qoLQeDzA_^(P>QY#}T8Cg!{@6h7u(F?97I^-X%)F~z(9{BXP<$k$wg`*kJ~9L>NO4ua|A)}bnwxFP@UBWSt>X0yondU z&Fb&{XuENYp)fBq^-~bm216=HgjhDO)ixLwD63AFYbgR`aNZjEC32{y4gIp;92 z*ZPIi7|+0$#eVkQ;fs%R7kKBvnQN!U+jM2PM!Qb26zf2O2;L?E?#8+8HSO$i?NTo} zs7ypW1RDrI3!8{3#_Hdf1Z7V?7*IF3bxRgxIL9%Ox?w=y!ibE5${Oli& z*jRnrSeW5%x<-=fC-Y=3EXsN6yzlNkvsF70vnKk*q;nr?@0vUWJc?=s^Ol?12wi<% z$H&CFB7*nXRpU6fab30UM|~DruDp|8QB`PWIqHb~uNNM;O%CSLcZ28zHl(B+-Nl%( zy8A;DWXvBhbiBs0ukYGh6I%?6!?{tGpaE9(MlhgE|2i?QhJ_ptvqRsnqVv$3Vg{$< zzkaG6oV6GSS_@?k#r^r+CoTC~JGf@1&CJsI7cM=PIkHw8xHkb~mA;UrAp7;xx^gJG zLBJsqI#$;nqMrqf2>k>sf_h8L>O};o-eMK5`|p--PA*q70R6_~UrxNqh4Nyo2_|?R z?+@qh2TM_JZ|#Go7L%LS!+Spy-VKC1>DG3al_~Yi8Dqc-`t~`|!Kbcj=Un^4QkeQ^ zg)zlkor~aFTp7j*koz&l@F=K@UNNAbrrKffpeG6{Xi=XBb>=4X3DAMe)=A-N6Y~&6 zS*_D;Ov?2?D4-scqrmm?CElsa7;!y7Pcr+K;F``uXYRrtVFF9&ZflHT832qV5D(f1 zV!JD8VjjiNnLrP>$z6ssp#ipv0+;T((!KdS8W;eLTzbkXBVKRl>YJmvkPH|w5XL84 zQ1)p9)XAIg$>bKUeFkKgv33YIuGc7b;c5d=6NbSU3qf0tp^6d_cKpJx_d`!}$!Qc* zBt&?%=-`&GA7%TWaz;j%@a4OVV^YqYG;~ABlGi8s;Mtj4R&oHt5(V-H0o;+_`ip|B zFbgOf)CS_FMnDGY8A^3CPZ3)bYj}PCfBD@57=_xy)f&9=E*_-mU8QV|YXE1+9?@{D=8?=bc)tHN37(Z>mXbI+!eFK!=RC z9$=9*@9YY^Q>ky1@6NdT+t$zT#L(AV$W%2|g4KfP$vCDei}CthI?5Rs%2FU@9cbj~?k+V+?>!9$F;2 z!9ROJ)N8-z1vg@`TShIcI`;*A_5{`<%N$q*X&*ACf&!O?9iP7iJ%g*ynii|O`pn>k z+cBc^te}j#g0-MO3~Do|ujcAqBVG=At6Zl_&bQpjkI=7s zjn6F}i(z4@K zlG&JS41-weKJyh3G#><2So-Nnpzml3cwD%?P{KYFQ?|a?-5M?jY~;KS;O!Luy!*Ep zM2uhg4MeO?odYu8najKYR5^<3&`C0x%=(UCX-phzVqK&p4^AYPXs=#)O^1{j;!?Od z7{a78h(2wgb7CXGfD)a(*B-^dy{Fs;k<0=S=sN)hTwV}UyslfOf<9nwUpPI=`!mqc z7$39#gIHpzo{9Bmneckd4BcgTi}Ccz00-#M(&l|KaIFj#1)P53B)|s%J0_2A6-{`< zW|31?!^&`EG|z!&8MYpVGKZ(i&6sFitb)?B1?^(!S+jRuDjU0GwveHc$v{jn<7gu40`~w$Y|O(A*FvCWaqi zab2d9=xjO4DuU5#zw{7eusi3o2Ya|0 zRz(fBti5^dZRm4)+fa|Q^5Q@yGk0BKT1i`g?9p9q0Qv-|zO*7MzV6C*J{eVzyO%JuTGOKA8fq zqQCN{!1N{>S6JVyv9DfmXErvy&$Hi>O&EXpJQ%=~i{Y(Tz^(6S*~UC+1toxnyq2=# z7zjpy4rOCeM{pbQAb>TcGZ&gG*W0nySCi$T=OFrToCXKzu3GgSSWvvg)~Ih%SvMaN zgK)n|MvSZJ289pMwbyS41Nvw3)K|oE2fIhF-w8oqa3!vw)EcmMJ`5-mvHpoP)lJxD z03IRvyWGFHq8H#Iy8#-%p5ckC{Kq>dP|fY*Rm%8k64a34{8a#8)p2>lE*rw5Ayky8Lp! z`uzbI7M(RZ8`-XY&&@bYl=q(znGL}dS^t*caWR84)&`b&!Qm#b)`f^=hIG5kZ5@H6 zkJ@ES_vkFR@d$LLWDYmW(=88q@nM~yAdoi*V6p;xKupmUW*u<(l*oy^-UFiPO)(dW zL3D8ps5LDWd@`A(n|k?mef1)Y*ep1-fDGtF;8_6o6>h5S+&kctVq!o943xXtt)F50 zk-|g%Tg>n@8+VIg-G6)J`_G1`AAl^L@>*aO2l&M%d8z*u;STv~?*AYBKk0*P-o?FF W!PqqfF$*UAt17E2#aR94)&B+&g*MXw diff --git a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png index 0f94b155cb9877f3b8f55bdb8295895c5fca5234..2f1632cfddf3d9dade342351e627a0a75609fb46 100644 GIT binary patch literal 2218 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 literal 53585 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
    yUGdlkE9 zt@?bkP%d4pjL<8gIfwmve4Fc9;7oJ(VUY3tW Date: Mon, 14 Sep 2026 07:01:21 +0800 Subject: [PATCH 5/6] chore: bump version to 1.0.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sync the iOS and macOS podspecs and the README dependency constraint to 1.0.1, document the partial web support in both READMEs, and add the bilingual 1.0.1 changelog entry. 同步 iOS 与 macOS podspec 及 README 依赖约束至 1.0.1,在两份 README 中说明 Web 部分支持,并补充双语的 1.0.1 变更日志。 --- CHANGELOG.md | 70 ++++++++++++++++++++++++++++++++-- README.md | 34 +++++++++++++---- README_zh.md | 32 +++++++++++++--- ios/zero_network_kit.podspec | 2 +- macos/zero_network_kit.podspec | 2 +- 5 files changed, 121 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 923e1c5..c602e1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,52 +1,114 @@ # Changelog -All notable changes to this project will be documented in this file. +## 1.0.1 -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +### Added / 新增 + +- **Web platform (partial)** — the package now compiles and runs on Flutter Web. + Connectivity is backed by `connectivity_plus`, ping falls back to an HTTPS + round trip, DNS resolution uses DNS-over-HTTPS, and the speed test, quality + score and benchmarks work unchanged. Capabilities the browser sandbox forbids + degrade gracefully: native details (SSID / gateway / MAC / VPN) report `null` + and TCP port checks return an "unavailable" result instead of throwing. Call + `NetworkCapabilities.current()` to discover the supported set at runtime. + - **Web 平台(部分支持)**——包现已可在 Flutter Web 上编译运行。连通性由 + `connectivity_plus` 提供,Ping 退化为 HTTPS 往返耗时,DNS 解析改用 + DNS-over-HTTPS,测速、质量评分与基准测试行为不变。浏览器沙箱禁止的能力会优雅降级: + 原生详情(SSID / 网关 / MAC / VPN)返回 `null`,TCP 端口检测返回"不可用"结果而非抛异常。 + 运行时可调用 `NetworkCapabilities.current()` 查询当前支持的能力集合。 + +### Fixed / 修复 + +- **Speed test on the web** — download and upload requests no longer send a + `Cache-Control` header. It is not a CORS-safelisted header, so it forced an + OPTIONS preflight that speed-test endpoints reject, surfacing as + `Failed to fetch`. + - **Web 端测速**——下载与上传请求不再携带 `Cache-Control` 头。该头不属于 CORS + 安全头,会触发 OPTIONS 预检,而测速端点会拒绝该预检,最终表现为 `Failed to fetch`。 + +### Changed / 变更 + +- **Windows VPN detection** — adapters are now also recognised from the driver + name in their description (TAP-Windows, Wintun, WireGuard, OpenVPN, …) in + addition to `IF_TYPE_TUNNEL`. `IF_TYPE_PPP` is deliberately not treated as a + VPN because PPPoE broadband reports the same interface type. + - **Windows VPN 检测**——除 `IF_TYPE_TUNNEL` 外,还会依据网卡描述中的驱动名识别 + VPN 网卡(TAP-Windows、Wintun、WireGuard、OpenVPN 等)。有意**不**把 + `IF_TYPE_PPP` 视为 VPN,因为 PPPoE 宽带拨号上报的也是该接口类型。 ## 1.0.0 -### Added +### Added / 新增 - **Connectivity** — `NetworkDiagnostic.checkConnection()` returns a `NetworkConnectionInfo` snapshot with transport type, IPv4/IPv6, gateway, Wi-Fi SSID, signal strength (dBm), MAC address and VPN detection. `NetworkDiagnostic.onConnectivityChanged` streams a fresh snapshot on every change. + - **连通性**——`NetworkDiagnostic.checkConnection()` 返回 `NetworkConnectionInfo` + 快照,包含传输类型、IPv4/IPv6、网关、Wi-Fi SSID、信号强度(dBm)、MAC 地址与 + VPN 检测;`NetworkDiagnostic.onConnectivityChanged` 会在每次变化时推送新快照。 - **Ping** — `NetworkDiagnostic.ping()` measures latency with TCP handshake round trips on every platform, and can use the system ICMP `ping` command on desktop (`PingMode.icmp`). `PingResult` reports sent/received, packet loss, min/avg/max and jitter. + - **Ping**——`NetworkDiagnostic.ping()` 在各平台以 TCP 握手往返测量延迟,桌面端还 + 可使用系统 ICMP `ping` 命令(`PingMode.icmp`)。`PingResult` 提供发送/接收数、 + 丢包率、最小/平均/最大耗时与抖动。 - **DNS** — `NetworkDiagnostic.resolve()` queries `system` plus any explicit resolvers over raw UDP, using the built-in DNS wire-format codec (`DnsPacket`), with concurrent or serialised execution and per-server `DnsTestResult`. + - **DNS**——`NetworkDiagnostic.resolve()` 通过原始 UDP 查询 `system` 及任意指定 + DNS 服务器,使用内置 DNS 报文编解码器(`DnsPacket`),支持并发或串行执行, + 并为每台服务器返回 `DnsTestResult`。 - **Speed test** — `NetworkDiagnostic.runSpeedTest()` measures download and upload throughput plus latency/jitter/packet loss, with progress callbacks via `SpeedTestProgress`. + - **测速**——`NetworkDiagnostic.runSpeedTest()` 测量下载与上传速率,并附带延迟、 + 抖动与丢包率,通过 `SpeedTestProgress` 回调进度。 - **Port check** — `NetworkDiagnostic.checkPort()` returns a `PortCheckResult` (use `isPortOpen()` for a plain boolean) and `scanPorts()` performs bounded-concurrency TCP reachability checks. + - **端口检测**——`NetworkDiagnostic.checkPort()` 返回 `PortCheckResult`(仅需布尔值 + 时可用 `isPortOpen()`);`scanPorts()` 以受限并发执行 TCP 可达性检测。 - **Quality score** — `NetworkDiagnostic.evaluateQuality()` and `NetworkQualityEvaluator` produce a 0–100 weighted score with a `NetworkQualityLevel` and actionable suggestions. + - **质量评分**——`NetworkDiagnostic.evaluateQuality()` 与 `NetworkQualityEvaluator` + 产出 0–100 的加权评分,附带 `NetworkQualityLevel` 与可执行的优化建议。 - **Full report** — `NetworkDiagnostic.diagnose()` aggregates every probe into a `NetworkDiagnosticReport`. + - **汇总报告**——`NetworkDiagnostic.diagnose()` 将全部探测结果汇总为 + `NetworkDiagnosticReport`。 - **Benchmarks** — `NetworkBenchmark.runAll()` and friends measure the diagnostics API itself and return `BenchmarkSuiteResult`. + - **基准测试**——`NetworkBenchmark.runAll()` 等方法测量诊断 API 自身的性能, + 返回 `BenchmarkSuiteResult`。 - **Configuration** — `NetworkDiagnosticConfig` centralises hosts, timeouts, payload sizes and quality targets; `ZeroNetworkKit.init()` applies it globally and `dispose()` releases the owned HTTP client. + - **配置**——`NetworkDiagnosticConfig` 集中管理主机、超时、负载大小与质量目标; + `ZeroNetworkKit.init()` 全局生效,`dispose()` 释放其持有的 HTTP 客户端。 - **Native channel** — `getPlatformVersion()` and `getNetworkDetails()` implemented for Android (Kotlin) and iOS (Swift). + - **原生通道**——`getPlatformVersion()` 与 `getNetworkDetails()` 已在 Android + (Kotlin)与 iOS(Swift)实现。 - **Desktop platforms** — Windows, macOS and Linux are now supported (`pubspec.yaml` declares them); `getPlatformVersion()` and `getNetworkDetails()` are implemented for each. On desktop, SSID / signal strength are `null`; Windows additionally exposes gateway / MAC / VPN via the native layer. + - **桌面平台**——已支持 Windows、macOS 与 Linux(`pubspec.yaml` 已声明),并为各自 + 实现 `getPlatformVersion()` 与 `getNetworkDetails()`。桌面端 SSID 与信号强度为 + `null`;Windows 还通过原生层额外提供网关 / MAC / VPN。 - **Capabilities** — `NetworkDiagnostic.capabilities` returns `NetworkCapabilities`, so callers can query-then-call and hide unsupported cards (e.g. SSID on desktop). + - **能力集**——`NetworkDiagnostic.capabilities` 返回 `NetworkCapabilities`, + 调用方可"先查询再调用",隐藏不支持的卡片(例如桌面端的 SSID)。 - **Advanced API** — services, `ConnectivityAdapter`, `QualityEvaluator` and the `DnsPacket` codec moved into `package:zero_network_kit/advanced.dart`; the root barrel stays small (models + facades + config). + - **进阶 API**——各项 service、`ConnectivityAdapter`、`QualityEvaluator` 与 + `DnsPacket` 编解码器已移入 `package:zero_network_kit/advanced.dart`;根 barrel + 保持精简(仅模型 + 门面 + 配置)。 diff --git a/README.md b/README.md index 8aa221a..5c0ea78 100644 --- a/README.md +++ b/README.md @@ -8,18 +8,18 @@ A Flutter plugin for **network diagnostics**: connectivity inspection, latency probing, DNS resolution, port checks, bandwidth measurement, quality scoring and -micro-benchmarks — for Android, iOS, macOS, Windows and Linux (no Web). +micro-benchmarks — for Android, iOS, macOS, Windows, Linux and Web (partial). [![pub version](https://img.shields.io/pub/v/zero_network_kit.svg)](https://pub.dev/packages/zero_network_kit) [![pub points](https://img.shields.io/pub/points/zero_network_kit.svg)](https://pub.dev/packages/zero_network_kit/score) [![CI](https://github.com/zero-labsco/zero_network_kit/actions/workflows/ci.yml/badge.svg)](https://github.com/zero-labsco/zero_network_kit/actions/workflows/ci.yml) [![License: MPL-2.0](https://img.shields.io/badge/License-MPL--2.0-blue.svg)](https://github.com/zero-labsco/zero_network_kit/blob/main/LICENSE) -[![Platform](https://img.shields.io/badge/Platform-Android%20%7C%20iOS%20%7C%20macOS%20%7C%20Windows%20%7C%20Linux-green.svg)](https://pub.dev/packages/zero_network_kit) +[![Platform](https://img.shields.io/badge/Platform-Android%20%7C%20iOS%20%7C%20macOS%20%7C%20Windows%20%7C%20Linux%20%7C%20Web-green.svg)](https://pub.dev/packages/zero_network_kit) [![Flutter](https://img.shields.io/badge/Flutter-✓-02569B?logo=flutter)](https://flutter.dev) [![Dart](https://img.shields.io/badge/Dart-✓-0175C2?logo=dart)](https://dart.dev) [![Style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart) -> **🔔 First release:** `zero_network_kit` `1.0.0` is the initial public release, supporting Android, iOS, macOS, Windows and Linux. Web is **not** supported because the plugin relies on `dart:io`. Issues and pull requests are welcome! +> **🔔 Upgrade recommended:** `1.0.1` adds partial Web support — the plugin now compiles and runs in the browser, and the capabilities the sandbox forbids degrade gracefully instead of failing. It also fixes the speed test on the web. Upgrade to `^1.0.1`. 🌐 **[Official Website](https://www.zerolabsco.com/)**  ·  📦 **[View on pub.dev](https://pub.dev/packages/zero_network_kit)**  ·  🔗 **[View on GitHub](https://github.com/zero-labsco/zero_network_kit)** @@ -74,7 +74,7 @@ Design goals: ```yaml dependencies: - zero_network_kit: ^1.0.0 + zero_network_kit: ^1.0.1 ``` ### Android permissions @@ -266,10 +266,30 @@ NetworkDiagnostic.configure( | macOS | ✅ Supported (Swift native side) | | Windows | ✅ Supported (C++ native side) | | Linux | ✅ Supported (C++ native side) | -| Web | ❌ Not supported — the plugin uses `dart:io`, which does not compile to Web. | +| Web | ⚠️ Partial — see [Web support](#web-support) below | -> The pure-Dart services can be compiled on desktop, but only the five platforms -> above are part of the officially supported matrix. +### Web support + +The web build exposes the same static API. Capabilities that the browser sandbox +forbids degrade gracefully — they return `null` or an "unavailable" result +instead of throwing: + +| Capability | Web | Notes | +| --- | --- | --- | +| Connectivity | ✅ | via `connectivity_plus` | +| Ping (`PingMode.tcp`) | ⚠️ | HTTPS round trip; the target must send CORS headers | +| Ping (`PingMode.icmp`) | ❌ | throws `UnsupportedError` | +| DNS (system resolver) | ✅ | via DNS-over-HTTPS | +| DNS (explicit server) | ⚠️ | needs a DoH endpoint, otherwise "unsupported" | +| Speed test | ✅ | HTTP download / upload | +| Quality score | ✅ | pure function | +| Benchmark | ✅ | pure function | +| Port check / scan | ❌ | returns "unavailable" results | +| Native details (SSID, gateway, MAC, VPN) | ❌ | `null` | + +`ZeroNetworkKit.getNativeNetworkDetails()` returns `null` on the web and +`ZeroNetworkKit.getPlatformVersion()` returns `Web`. Call +`NetworkCapabilities.current()` to discover the supported set at runtime. ## Documentation diff --git a/README_zh.md b/README_zh.md index bb26a67..6ebb2a7 100644 --- a/README_zh.md +++ b/README_zh.md @@ -7,18 +7,18 @@ 一个 Flutter **网络诊断**插件:连通性检测、延迟探测、DNS 解析、端口检测、带宽 -测速、质量评分与微基准测试,支持 Android、iOS、macOS、Windows 与 Linux(不支持 Web)。 +测速、质量评分与微基准测试,支持 Android、iOS、macOS、Windows、Linux 与 Web(部分支持)。 [![pub version](https://img.shields.io/pub/v/zero_network_kit.svg)](https://pub.dev/packages/zero_network_kit) [![pub points](https://img.shields.io/pub/points/zero_network_kit.svg)](https://pub.dev/packages/zero_network_kit/score) [![CI](https://github.com/zero-labsco/zero_network_kit/actions/workflows/ci.yml/badge.svg)](https://github.com/zero-labsco/zero_network_kit/actions/workflows/ci.yml) [![License: MPL-2.0](https://img.shields.io/badge/License-MPL--2.0-blue.svg)](https://github.com/zero-labsco/zero_network_kit/blob/main/LICENSE) -[![Platform](https://img.shields.io/badge/Platform-Android%20%7C%20iOS%20%7C%20macOS%20%7C%20Windows%20%7C%20Linux-green.svg)](https://pub.dev/packages/zero_network_kit) +[![Platform](https://img.shields.io/badge/Platform-Android%20%7C%20iOS%20%7C%20macOS%20%7C%20Windows%20%7C%20Linux%20%7C%20Web-green.svg)](https://pub.dev/packages/zero_network_kit) [![Flutter](https://img.shields.io/badge/Flutter-✓-02569B?logo=flutter)](https://flutter.dev) [![Dart](https://img.shields.io/badge/Dart-✓-0175C2?logo=dart)](https://dart.dev) [![Style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://pub.dev/packages/effective_dart) -> **🔔 首次发布:** `zero_network_kit` `1.0.0` 为首个公开版本,支持 Android、iOS、macOS、Windows 与 Linux;**不支持 Web**(插件依赖 `dart:io`)。欢迎提 issue 与 PR! +> **🔔 推荐升级:** `1.0.1` 新增 Web 平台部分支持——插件现已可在浏览器中编译运行,浏览器沙箱禁止的能力会优雅降级而不会报错;同时修复了 Web 端测速失败的问题。建议升级到 `^1.0.1`。 🌐 **[官方网站](https://www.zerolabsco.com/)**  ·  📦 **[在 pub.dev 查看](https://pub.dev/packages/zero_network_kit)**  ·  🔗 **[查看 GitHub 仓库](https://github.com/zero-labsco/zero_network_kit)** @@ -72,7 +72,7 @@ ```yaml dependencies: - zero_network_kit: ^1.0.0 + zero_network_kit: ^1.0.1 ``` ### Android 权限 @@ -259,9 +259,29 @@ NetworkDiagnostic.configure( | macOS | ✅ 支持(Swift 原生实现) | | Windows | ✅ 支持(C++ 原生实现) | | Linux | ✅ 支持(C++ 原生实现) | -| Web | ❌ 不支持——插件使用 `dart:io`,无法编译到 Web。 | +| Web | ⚠️ 部分支持——详见下方 [Web 支持](#web-支持) | -> 纯 Dart 服务可在桌面端编译,但仅有以上五个平台属于官方受支持矩阵。 +### Web 支持 + +Web 构建提供同样的静态 API;浏览器沙箱禁止的能力会优雅降级(返回 `null` +或“不可用”结果,而不是抛异常): + +| 能力 | Web | 说明 | +| --- | --- | --- | +| 连通性检测 | ✅ | 通过 `connectivity_plus` | +| Ping(`PingMode.tcp`) | ⚠️ | 以 HTTPS 往返耗时度量,目标主机需下发 CORS 头 | +| Ping(`PingMode.icmp`) | ❌ | 抛出 `UnsupportedError` | +| DNS(系统解析器) | ✅ | 通过 DNS-over-HTTPS | +| DNS(指定服务器) | ⚠️ | 需要 DoH 端点,否则返回“不支持” | +| 带宽测速 | ✅ | HTTP 下载 / 上传 | +| 质量评分 | ✅ | 纯函数 | +| 微基准 | ✅ | 纯函数 | +| 端口检测 / 扫描 | ❌ | 返回“不可用”结果 | +| 原生详情(SSID、网关、MAC、VPN) | ❌ | 返回 `null` | + +Web 上 `ZeroNetworkKit.getNativeNetworkDetails()` 返回 `null`, +`ZeroNetworkKit.getPlatformVersion()` 返回 `Web`;运行时可用 +`NetworkCapabilities.current()` 查询当前平台支持的能力集合。 ## 文档 diff --git a/ios/zero_network_kit.podspec b/ios/zero_network_kit.podspec index cd87803..4719561 100644 --- a/ios/zero_network_kit.podspec +++ b/ios/zero_network_kit.podspec @@ -4,7 +4,7 @@ # Pod::Spec.new do |s| s.name = 'zero_network_kit' - s.version = '1.0.0' + s.version = '1.0.1' s.summary = 'Flutter network diagnostics: ping, DNS, speed test, port scan and quality score.' s.description = <<-DESC A Flutter plugin for network diagnostics: connectivity check, ping, DNS diff --git a/macos/zero_network_kit.podspec b/macos/zero_network_kit.podspec index 1d9140d..b00bc32 100644 --- a/macos/zero_network_kit.podspec +++ b/macos/zero_network_kit.podspec @@ -4,7 +4,7 @@ # Pod::Spec.new do |s| s.name = 'zero_network_kit' - s.version = '1.0.0' + s.version = '1.0.1' s.summary = 'A new Flutter plugin project.' s.description = <<-DESC A new Flutter plugin project. From a25036fdd7157246f87d78ab7e18cdca5cdea738 Mon Sep 17 00:00:00 2001 From: AmisKwok Date: Mon, 14 Sep 2026 07:04:22 +0800 Subject: [PATCH 6/6] docs: document partial web support on the docs site MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Platform-Support.md no longer claims Web is unsupported: the intro, capability matrix and NetworkCapabilities rules now cover the web, and a dedicated Web support section lists which capabilities degrade and notes that browsers expose no VPN API. FAQ.md is updated to match. Platform-Support.md 不再声称不支持 Web:开头、能力矩阵与 NetworkCapabilities 规则均已覆盖 Web,并新增 Web 支持章节列出各能力的降级行为,同时说明浏览器不暴露 VPN 接口;FAQ.md 同步更新。 --- docs/404.html | 2 +- docs/404/index.html | 2 +- docs/API-Reference/index.html | 4 +- docs/Benchmark/index.html | 4 +- docs/Connectivity/index.html | 4 +- docs/DNS/index.html | 4 +- docs/FAQ/index.html | 9 +- docs/Full-Report/index.html | 4 +- docs/Getting-Started/index.html | 4 +- docs/Installation/index.html | 4 +- docs/Ping/index.html | 4 +- docs/Platform-Support/index.html | 177 ++++++++++++++++-- docs/Ports/index.html | 4 +- docs/Quality/index.html | 4 +- docs/Speed-Test/index.html | 4 +- docs/Usage/index.html | 4 +- .../static/chunks/nextra-data-en-US.json | 2 +- .../chunks/pages/FAQ-bccbbb52a0b53bb8.js | 1 + .../chunks/pages/FAQ-c14e0ebd2147b3f8.js | 1 - .../Platform-Support-3994cdd8603e191b.js | 1 + .../Platform-Support-45a009c029992240.js | 1 - .../_buildManifest.js | 2 +- .../_ssgManifest.js | 0 docs/index.html | 4 +- website/pages/FAQ.md | 5 +- website/pages/Platform-Support.md | 97 +++++++--- 26 files changed, 279 insertions(+), 73 deletions(-) create mode 100644 docs/_next/static/chunks/pages/FAQ-bccbbb52a0b53bb8.js delete mode 100644 docs/_next/static/chunks/pages/FAQ-c14e0ebd2147b3f8.js create mode 100644 docs/_next/static/chunks/pages/Platform-Support-3994cdd8603e191b.js delete mode 100644 docs/_next/static/chunks/pages/Platform-Support-45a009c029992240.js rename docs/_next/static/{dF_UuZS4SBtufIwTYLshU => x-nTvOiGfo930-2DM2DH8}/_buildManifest.js (91%) rename docs/_next/static/{dF_UuZS4SBtufIwTYLshU => x-nTvOiGfo930-2DM2DH8}/_ssgManifest.js (100%) diff --git a/docs/404.html b/docs/404.html index 2ef2bbe..3b02e2b 100644 --- a/docs/404.html +++ b/docs/404.html @@ -1 +1 @@ -404: This page could not be found

    404

    \ No newline at end of file +404: This page could not be found

    404

    This page could not be found.

    \ No newline at end of file diff --git a/docs/404/index.html b/docs/404/index.html index 2ef2bbe..3b02e2b 100644 --- a/docs/404/index.html +++ b/docs/404/index.html @@ -1 +1 @@ -404: This page could not be found

    404

    This page could not be found.

    \ No newline at end of file +404: This page could not be found

    404

    This page could not be found.

    \ No newline at end of file diff --git a/docs/API-Reference/index.html b/docs/API-Reference/index.html index 3002734..5885879 100644 --- a/docs/API-Reference/index.html +++ b/docs/API-Reference/index.html @@ -1,4 +1,4 @@ -
    📚 API Reference

    API Reference / 接口参考

    +
    📚 API Reference

    API Reference / 接口参考

    A condensed field reference for every public model. For copy-paste examples of each method, see the capability pages.

    这里是每个公开模型的字段速查。每个方法的复制即用示例请见各能力页面。

    @@ -95,4 +95,4 @@

    API.md 与 API_zh.md。

    -


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +

    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/Benchmark/index.html b/docs/Benchmark/index.html index 6de4b96..f05c80d 100644 --- a/docs/Benchmark/index.html +++ b/docs/Benchmark/index.html @@ -1,4 +1,4 @@ -
    📊 Benchmarks

    Benchmarks / 微基准测试

    +
    📊 Benchmarks

    Benchmarks / 微基准测试

    NetworkBenchmark measures how fast the diagnostics API itself runs — useful when deciding whether a diagnostic belongs on your startup path.

    NetworkBenchmark 衡量诊断 API 自身的开销——可用在判断某项诊断能否放在启动路径上。

    @@ -33,4 +33,4 @@

    minDuration, maxDuration, standardDeviation, operationsPerSecond, failures, timestamp.

    BenchmarkSuiteResult: suiteName, results, totalDuration, timestamp, and -suite['name'].


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +suite['name'].


    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/Connectivity/index.html b/docs/Connectivity/index.html index 7bf2c01..95b88a3 100644 --- a/docs/Connectivity/index.html +++ b/docs/Connectivity/index.html @@ -1,4 +1,4 @@ -
    📡 Connectivity

    Connectivity / 连通性

    +
    📡 Connectivity

    Connectivity / 连通性

    NetworkDiagnostic.checkConnection() captures a single snapshot of the current network; onConnectivityChanged emits a fresh snapshot on every transport change.

    @@ -145,4 +145,4 @@

    }, ); } -}


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +}

    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/DNS/index.html b/docs/DNS/index.html index c1ebdff..0d16ac3 100644 --- a/docs/DNS/index.html +++ b/docs/DNS/index.html @@ -1,4 +1,4 @@ -
    🌍 DNS

    DNS / DNS 解析

    +
    🌍 DNS

    DNS / DNS 解析

    NetworkDiagnostic.resolve() tests DNS resolution across multiple servers in parallel, so you can spot the fastest one. Each result is either the system resolver or a raw UDP query against an explicit server.

    @@ -72,4 +72,4 @@

    final fastest = results
         .where((r) => r.isSuccess)
         .reduce((a, b) => a.responseTimeMs <= b.responseTimeMs ? a : b);
    -print('fastest resolver: ${fastest.server}');


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +print('fastest resolver: ${fastest.server}');

    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/FAQ/index.html b/docs/FAQ/index.html index 1c0bb3a..823addf 100644 --- a/docs/FAQ/index.html +++ b/docs/FAQ/index.html @@ -1,4 +1,4 @@ -
    ❓ FAQ

    FAQ / 常见问题

    +
    ❓ FAQ

    FAQ / 常见问题

    Do I need to call init()? / 需要调用 init() 吗?

    No. Every API falls back to built-in defaults. Call ZeroNetworkKit.init() only when you want to override defaults (e.g. a custom reachability host or DNS @@ -6,8 +6,9 @@

    不需要。每个 API 都走内置默认值。只有在想覆盖默认参数(如自定义可达性主机或 DNS 服务器)时才调用 ZeroNetworkKit.init()。单用连通性完全零配置。

    Which platforms are supported? / 支持哪些平台?

    -

    Android, iOS, macOS, Windows and Linux. Web is not supported.

    -

    支持 Android、iOS、macOS、Windows 与 Linux。Web 不支持。详见 +

    Android, iOS, macOS, Windows, Linux and Web (partial — see +Platform Support).

    +

    支持 Android、iOS、macOS、Windows、Linux 与 Web(部分支持)。详见 Platform Support。

    Why is ssid / signalStrength null on desktop? / 为什么桌面上的 ssid/信号强度是 null?

    Desktop uses tier A: SSID and RSSI require system APIs that aren’t exposed on @@ -37,4 +38,4 @@

    用法 → 依赖注入。

    How is this licensed? / 采用什么许可证?

    MPL-2.0. See the repository LICENSE.

    -

    采用 MPL-2.0。详见仓库 LICENSE。


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +

    采用 MPL-2.0。详见仓库 LICENSE。


    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/Full-Report/index.html b/docs/Full-Report/index.html index e7b5d4d..422501b 100644 --- a/docs/Full-Report/index.html +++ b/docs/Full-Report/index.html @@ -1,4 +1,4 @@ -
    📋 Full Report

    Full Report / 汇总报告

    +
    📋 Full Report

    Full Report / 汇总报告

    NetworkDiagnostic.diagnose() runs every probe you ask for and aggregates them into one NetworkDiagnosticReport. A failing sub-test never aborts the run — its field simply stays empty/null.

    @@ -80,4 +80,4 @@

    includePorts 默认 false,默认运行不会扫描端口。

    The report is JSON-encodable via report.toMap(). -报告可通过 report.toMap() 序列化为 JSON。


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +报告可通过 report.toMap() 序列化为 JSON。


    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/Getting-Started/index.html b/docs/Getting-Started/index.html index 8f8ee2c..007dfb9 100644 --- a/docs/Getting-Started/index.html +++ b/docs/Getting-Started/index.html @@ -1,4 +1,4 @@ -
    🚀 Getting Started

    Getting Started / 快速开始

    +
    🚀 Getting Started

    Getting Started / 快速开始

    Quick Start / 快速开始

    Import the package and start diagnosing — no init() required:

    导入包即可开始诊断,无需 init():

    @@ -83,4 +83,4 @@

    Installation — Detailed installation methods / 详细安装方式
  • Usage — Global config & dependency injection / 全局配置与依赖注入
  • Platform Support — Capability matrix / 能力矩阵
  • -


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +

    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/Installation/index.html b/docs/Installation/index.html index ac93c8b..08fb703 100644 --- a/docs/Installation/index.html +++ b/docs/Installation/index.html @@ -1,4 +1,4 @@ -
    📦 Installation

    Installation / 安装

    +

    Zero Network Kit · MPL-2.0
    \ No newline at end of file +

    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/Ping/index.html b/docs/Ping/index.html index af0b75c..924668c 100644 --- a/docs/Ping/index.html +++ b/docs/Ping/index.html @@ -1,4 +1,4 @@ -
    ⏱ Latency / Ping

    Latency / Ping / 延迟探测

    +
    ⏱ Latency / Ping

    Latency / Ping / 延迟探测

    NetworkDiagnostic.ping() measures round-trip time towards a target host and reports sent / received counts, packet loss, min/avg/max and jitter.

    NetworkDiagnostic.ping() 测量到目标主机的往返时间,并给出发送/接收次数、丢包率、 @@ -75,4 +75,4 @@

    mode: PingMode.icmp on desktop to get closer to real ICMP. TCP 探测需要一个在监听的端口。对不接受 TCP/443 的主机探测 port: 443 会失败—— 那是“被过滤”,不是“离线”。在桌面上用 PingMode.icmp 更接近真实 ICMP。

    -


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +

    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/Platform-Support/index.html b/docs/Platform-Support/index.html index 2a6e0b5..352eda4 100644 --- a/docs/Platform-Support/index.html +++ b/docs/Platform-Support/index.html @@ -1,11 +1,11 @@ -
    🖥 Platform Support

    Platform Support / 平台支持

    -

    zero_network_kit is declared on five plugin platforms: Android, iOS, -macOS, Windows and Linux. Web is not supported — the Dart services rely on -dart:io, which does not compile for the web, and browsers have no raw -TCP/UDP sockets.

    -

    zero_network_kit 在 五 个插件平台上声明:Android、iOS、macOS、Windows 与 -Linux。不支持 Web——Dart 服务依赖 dart:io(无法在 Web 上编译),且浏览器没有 -原生 TCP/UDP 套接字。

    +
    🖥 Platform Support

    Platform Support / 平台支持

    +

    zero_network_kit is declared on six plugin platforms: Android, iOS, +macOS, Windows, Linux and Web. Web support is partial: the services that +depend on dart:io are swapped for browser-safe equivalents, and the +capabilities the sandbox forbids degrade gracefully instead of failing.

    +

    zero_network_kit 在 六 个插件平台上声明:Android、iOS、macOS、Windows、Linux +与 Web。Web 为部分支持:依赖 dart:io 的服务已替换为浏览器安全的等价实现, +浏览器沙箱禁止的能力会优雅降级而不会失败。

    Capability matrix / 能力矩阵

    @@ -77,23 +77,41 @@

    CapabilityAndroid / iOSDesktop (macOS / Windows / Linux)Connectivity (connectivity_plus)✅✅Local IP / IPv6 (NetworkInterface)✅✅Native details (SSID / gateway / MAC / VPN)✅⚠️ see belowTCP ping✅✅ICMP ping (Process.run('ping'))❌✅HTTP ping✅✅DNS system resolver✅✅DNS raw UDP✅✅Port check / scan✅✅Speed test✅✅Quality score✅✅Benchmarks✅✅ + + + + + + + + + + + + + +
    CapabilityAndroid / iOSDesktop (macOS / Windows / Linux)Web
    Connectivity (connectivity_plus)✅✅✅
    Local IP / IPv6 (NetworkInterface)✅✅❌
    Native details (SSID / gateway / MAC / VPN)✅⚠️ see below❌
    TCP ping✅✅⚠️ HTTPS round trip
    ICMP ping (Process.run('ping'))❌✅❌
    HTTP ping✅✅✅
    DNS system resolver✅✅✅ DoH
    DNS raw UDP✅✅⚠️ DoH endpoint required
    Port check / scan✅✅❌
    Speed test✅✅✅
    Quality score✅✅✅
    Benchmarks✅✅✅

    NetworkCapabilities / 能力查询

    Query the host platform before calling, so your UI can hide unsupported cards:

    在调用前查询当前平台能力,UI 即可据此隐藏不支持的卡片:

    final caps = NetworkDiagnostic.capabilities;
    -print(caps.platform);            // 'android' | 'ios' | 'macos' | 'windows' | 'linux'
    +print(caps.platform);            // 'android' | 'ios' | 'macos' | 'windows' | 'linux' | 'web'
     print(caps.supports(NetworkCapability.nativeDetails)); // mobile: true, desktop: false
     print(caps.supports(NetworkCapability.icmpPing));      // desktop: true, mobile: false

    Rules baked into NetworkCapabilities.current():

    • nativeDetails is mobile-only (SSID / gateway / MAC / VPN need system APIs).
    • icmpPing is desktop-only (uses the system ping binary).
    • +
    • On web the supported set narrows to connectivity, tcpPing, +dnsSystem, speedTest, quality and benchmark; every other capability is +absent.

    NetworkCapabilities.current() 内置规则:

    • nativeDetails 仅移动端(SSID / 网关 / MAC / VPN 需要系统 API)。
    • icmpPing 仅桌面(使用系统 ping 命令)。
    • +
    • Web 上的支持集合收缩为 connectivity、tcpPing、dnsSystem、speedTest、 +quality 与 benchmark,其余能力均不存在。

    Native details on desktop / 桌面原生详情

    Desktop uses tier A by default: the native layer only reports the platform @@ -116,11 +134,146 @@

    null and the rest of the result still arrives.

    无论在哪个平台,缺权限或原生调用不可达都不会抛异常——对应字段保持 null,其余 结果照常返回。

    +

    Web support / Web 支持

    +

    The web build exposes the same static API. Capabilities that the browser sandbox +forbids degrade gracefully — they return null or an “unavailable” result +instead of throwing:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CapabilityWebNotes
    Connectivity✅via connectivity_plus
    Ping (PingMode.tcp)⚠️measured as an HTTPS round trip; the target must send CORS headers
    Ping (PingMode.icmp)❌throws UnsupportedError
    DNS (system resolver)✅via DNS-over-HTTPS
    DNS (explicit server)⚠️needs a DoH endpoint, otherwise “unsupported”
    Speed test✅HTTP download / upload
    Quality score✅pure function
    Benchmarks✅pure function
    Port check / scan❌returns “unavailable” results
    Native details (SSID, gateway, MAC, VPN)❌null
    +

    Browsers expose no VPN API, so isVpn stays false on the web even when a +system VPN or a local HTTP proxy is active.

    +

    Web 构建提供同样的静态 API;浏览器沙箱禁止的能力会优雅降级(返回 null 或”不可用” +结果,而不是抛异常):

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    能力Web说明
    连通性检测✅通过 connectivity_plus
    Ping(PingMode.tcp)⚠️以 HTTPS 往返耗时度量,目标主机需下发 CORS 头
    Ping(PingMode.icmp)❌抛出 UnsupportedError
    DNS(系统解析器)✅通过 DNS-over-HTTPS
    DNS(指定服务器)⚠️需要 DoH 端点,否则返回”不支持”
    带宽测速✅HTTP 下载 / 上传
    质量评分✅纯函数
    基准测试✅纯函数
    端口检测 / 扫描❌返回”不可用”结果
    原生详情(SSID、网关、MAC、VPN)❌返回 null
    +

    浏览器不暴露 VPN 接口,因此即使系统开启了 VPN 或本地 HTTP 代理,Web 上的 +isVpn 仍为 false。

    Reading native data / 读取原生数据

    final version = await ZeroNetworkKit.getPlatformVersion();
    -print(version); // e.g. 'Android 14' / 'iOS 18.0'
    +print(version); // e.g. 'Android 14' / 'iOS 18.0' / 'Web'
      
     final details = await ZeroNetworkKit.getNativeNetworkDetails();
     if (details != null) {
       print(details); // SSID, BSSID, gateway, MAC, VPN flag, RSSI …
    -}

    Zero Network Kit · MPL-2.0
    \ No newline at end of file +}
    +

    details is always null on the web, and usually null on desktop too (see +above).

    +

    Web 上 details 恒为 null,桌面端通常也为 null(见上文)。


    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/Ports/index.html b/docs/Ports/index.html index 8c4498c..dfc3dac 100644 --- a/docs/Ports/index.html +++ b/docs/Ports/index.html @@ -1,4 +1,4 @@ -
    🔌 Ports

    Ports / 端口检测

    +
    🔌 Ports

    Ports / 端口检测

    checkPort() returns a full PortCheckResult for one port; isPortOpen() is the plain boolean convenience; scanPorts() runs many ports concurrently with bounded in-flight connections.

    @@ -65,4 +65,4 @@

    checkPort() 返回 PortCheckResult(含 isOpen、responseTimeMs、 errorMessage);单端口布尔诉求请用 isPortOpen()。需要 RTT 或失败原因时可直接 调用 checkPort(),或给 scanPorts(..., ports: [443]) 取单条结果。

    -


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +

    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/Quality/index.html b/docs/Quality/index.html index eab92a5..abbc709 100644 --- a/docs/Quality/index.html +++ b/docs/Quality/index.html @@ -1,4 +1,4 @@ -
    ⭐ Quality Score

    Quality Score / 质量评分

    +
    ⭐ Quality Score

    Quality Score / 质量评分

    NetworkDiagnostic.evaluateQuality() returns a weighted 0–100 score plus a level and human-readable suggestions, computed over whatever metrics are available.

    @@ -128,4 +128,4 @@

    ); print('${score.score.toStringAsFixed(1)} → ${score.level.label}');

    Tune the ideal values globally through NetworkDiagnosticConfig(qualityTargets: ...). -调整理想值请通过 NetworkDiagnosticConfig(qualityTargets: ...) 全局设置。


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +调整理想值请通过 NetworkDiagnosticConfig(qualityTargets: ...) 全局设置。


    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/Speed-Test/index.html b/docs/Speed-Test/index.html index 593b2a6..215d430 100644 --- a/docs/Speed-Test/index.html +++ b/docs/Speed-Test/index.html @@ -1,4 +1,4 @@ -
    🚀 Speed Test

    Speed Test / 测速

    +
    🚀 Speed Test

    Speed Test / 测速

    NetworkDiagnostic.runSpeedTest() measures download and upload throughput and samples latency during the run, reporting progress through onProgress.

    NetworkDiagnostic.runSpeedTest() 测量下载与上传吞吐量,并在过程中采样延迟,通过 @@ -87,4 +87,4 @@

    downloadUrl / uploadUrl for production. 默认端点指向 Cloudflare 公共服务并会产生真实流量(默认下载约 25 MB)。在按量计费 网络上运行前请征得同意,并为生产环境替换 downloadUrl / uploadUrl。

    -


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +

    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/Usage/index.html b/docs/Usage/index.html index 579821a..fe50b5b 100644 --- a/docs/Usage/index.html +++ b/docs/Usage/index.html @@ -1,4 +1,4 @@ -
    📖 Usage

    Usage / 用法

    +

    Zero Network Kit · MPL-2.0
    \ No newline at end of file +

    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/docs/_next/static/chunks/nextra-data-en-US.json b/docs/_next/static/chunks/nextra-data-en-US.json index 4e0dcb1..63fc8a0 100644 --- a/docs/_next/static/chunks/nextra-data-en-US.json +++ b/docs/_next/static/chunks/nextra-data-en-US.json @@ -1 +1 @@ -{"/API-Reference":{"title":"API Reference / 接口参考","data":{"":"A condensed field reference for every public model. For copy-paste examples of\neach method, see the capability pages.这里是每个公开模型的字段速查。每个方法的复制即用示例请见各能力页面。","networktype#NetworkType":"Member\tNotes\tvalues\tnone, wifi, mobile, ethernet, vpn, bluetooth, other\tlabel\tHuman readable: 'Wi-Fi', 'Mobile', …\tid\tStable English identifier (name), safe to persist\tisConnected\ttrue unless none\tNetworkType.fromRaw(Object?)\tParses a raw platform string","networkconnectioninfo#NetworkConnectionInfo":"isConnected, type, ssid, signalStrength (dBm), ipAddress,\nipv6Address, gateway, macAddress, isVpn, isReachable, timestamp,\nplus copyWith({bool? isReachable}).","pingresult#PingResult":"Fields host, port, mode, sent, received, times, timestamp;\nderived getters lost, packetLoss (%), minTime, maxTime, averageTime,\njitter, isSuccess.","dnstestresult#DnsTestResult":"Fields server, domain, isSuccess, responseTime, resolvedIps,\nerrorMessage, timestamp; derived responseTimeMs, primaryAddress.","portcheckresult#PortCheckResult":"Fields host, port, isOpen, responseTime, errorMessage, timestamp;\nderived responseTimeMs.","speedtestresult#SpeedTestResult":"Fields downloadSpeed, uploadSpeed (Mbps), ping (ms), jitter (ms),\npacketLoss (%), downloadedBytes, uploadedBytes, downloadDuration,\nuploadDuration, server, timestamp; derived duration; static helper\nSpeedTestResult.mbpsFromBytes(bytes, elapsed).","speedtestprogress--speedtestphase#SpeedTestProgress / SpeedTestPhase":"phase (download, upload, completed), bytes, elapsed, speedMbps.","networkqualityscore--networkqualitylevel#NetworkQualityScore / NetworkQualityLevel":"score (0–100), level, metrics (Map), suggestions,\ntimestamp; NetworkQualityLevel.fromScore(double), level.label.","networkdiagnosticreport#NetworkDiagnosticReport":"connection, ping, dnsResults, portResults, speedTest, quality,\ntimestamp.","benchmarkresult--benchmarksuiteresult#BenchmarkResult / BenchmarkSuiteResult":"BenchmarkResult: testName, iterations, totalDuration,\naverageDuration, minDuration, maxDuration, standardDeviation,\noperationsPerSecond, failures, timestamp.\nBenchmarkSuiteResult: suiteName, results, totalDuration, timestamp,\nand suite['name'].","gotchas--常见陷阱#Gotchas / 常见陷阱":"type.label, not displayName. NetworkType exposes label / id.\ncheckPort() returns PortCheckResult. Use isPortOpen() for a plain\nboolean, or scanPorts(..., ports: [p]).first for RTT / error message.\nincludeSystemResolver defaults to false. Pass true to add the\nsystem DNS row.\nA TCP ping needs a listening port. Probing host with port: 443 fails\nif that host does not accept TCP/443 — that is \"filtered\", not \"offline\". Use\nmode: PingMode.icmp on desktop to get closer to real ICMP.\nPingMode.icmp is desktop-only and silently degrades when the ping\nbinary is unavailable.\nThe speed test moves real traffic (≈25 MB download by default). Ask for\nconsent before running it on a metered connection.\nMissing permissions degrade, they never throw. A missing location\npermission yields ssid == null; the rest of the snapshot still arrives.\nincludePorts is false by default in diagnose().\ninit() is optional, but dispose() only closes the client the plugin\nowns — an httpClient you injected stays open, so close it yourself.\nFull source-level API docs live in the repo:\nAPI.md\n(English) and\nAPI_zh.md\n(简体中文).\n完整源码级 API 文档见仓库内的\nAPI.md\n与 API_zh.md。"}},"/Benchmark":{"title":"Benchmarks / 微基准测试","data":{"":"NetworkBenchmark measures how fast the diagnostics API itself runs — useful\nwhen deciding whether a diagnostic belongs on your startup path.NetworkBenchmark 衡量诊断 API 自身的开销——可用在判断某项诊断能否放在启动路径上。","all-at-once--一次性全跑#All at once / 一次性全跑":"final suite = await NetworkBenchmark.runAll(\n iterations: 20,\n warmupIterations: 3,\n host: '1.1.1.1',\n dnsDomain: 'example.com',\n port: 443,\n);\nfor (final result in suite.results) {\n print('${result.testName.padRight(12)} '\n 'avg ${(result.averageDuration.inMicroseconds / 1000).toStringAsFixed(2)} ms '\n '± ${(result.standardDeviation.inMicroseconds / 1000).toStringAsFixed(2)} ms '\n '${result.operationsPerSecond.toStringAsFixed(1)} ops/s '\n 'failures=${result.failures}');\n}\n// Look up one benchmark by name / 按名称查单个结果\nprint(suite['ping']?.averageDuration);\nprint(suite.totalDuration);","individual-suites--单个基准#Individual suites / 单个基准":"await NetworkBenchmark.benchmarkConnection(iterations: 20);\nawait NetworkBenchmark.benchmarkPing(iterations: 20, host: '1.1.1.1');\nawait NetworkBenchmark.benchmarkDns(iterations: 20, domain: 'example.com');\nawait NetworkBenchmark.benchmarkPortCheck(iterations: 20, port: 443);\nawait NetworkBenchmark.benchmarkPlatformChannel(iterations: 20);","result-fields--结果字段#Result fields / 结果字段":"BenchmarkResult: testName, iterations, totalDuration, averageDuration,\nminDuration, maxDuration, standardDeviation, operationsPerSecond,\nfailures, timestamp.BenchmarkSuiteResult: suiteName, results, totalDuration, timestamp, and\nsuite['name']."}},"/Connectivity":{"title":"Connectivity / 连通性","data":{"":"NetworkDiagnostic.checkConnection() captures a single snapshot of the current\nnetwork; onConnectivityChanged emits a fresh snapshot on every transport\nchange.NetworkDiagnostic.checkConnection() 捕获当前网络的一次快照;onConnectivityChanged\n在每次传输方式变化时推送新快照。","snapshot--快照#Snapshot / 快照":"final connection = await NetworkDiagnostic.checkConnection();\nprint('type : ${connection.type.label}'); // Wi-Fi / Mobile / Ethernet …\nprint('connected : ${connection.isConnected}');\nprint('ipv4 : ${connection.ipAddress}');\nprint('ipv6 : ${connection.ipv6Address}');\nprint('gateway : ${connection.gateway}');\nprint('ssid : ${connection.ssid}');\nprint('rssi : ${connection.signalStrength} dBm');\nprint('mac : ${connection.macAddress}');\nprint('vpn : ${connection.isVpn}');\nprint('timestamp : ${connection.timestamp}');\nField\tNotes\ttype\tNetworkType (none, wifi, mobile, ethernet, vpn, bluetooth, other)\tisConnected\ttrue unless type is none\tipAddress / ipv6Address\tLocal IPv4 / IPv6 (Dart NetworkInterface)\tgateway / macAddress\tNative; null on desktop except Windows\tssid / signalStrength\tNative; always null on desktop\tisVpn\tNative VPN detection\tisReachable\tOnly filled when probeReachability: true\ttimestamp\tWhen the snapshot was taken\t\nUse connection.type.label / connection.type.id. There is no\ndisplayName.\n请使用 connection.type.label / connection.type.id,没有 displayName。","parameters--参数#Parameters / 参数":"Parameter\tDefault\tMeaning\tincludeNativeDetails\ttrue\tAlso read SSID / gateway / MAC / VPN from the native side\tprobeReachability\tfalse\tMake a real request and fill isReachable\tprobeTimeout\t3s\tTimeout of that reachability probe\t\n// Skip the native channel (cheapest call — good on hot paths).\nfinal quick = await NetworkDiagnostic.checkConnection(includeNativeDetails: false);\n// Prove the internet is actually reachable, not just that a NIC is up.\nfinal verified = await NetworkDiagnostic.checkConnection(\n probeReachability: true,\n probeTimeout: const Duration(seconds: 5),\n);\nif (verified.isReachable == false) {\n print('Interface is up but the internet is unreachable.');\n}","change-stream--变化监听#Change stream / 变化监听":"final subscription = NetworkDiagnostic.onConnectivityChanged.listen(\n (info) => print('now on ${info.type.id} · ${info.ipAddress}'),\n);\n// Later:\nawait subscription.cancel();\nIn a widget:\nStreamBuilder(\n stream: NetworkDiagnostic.onConnectivityChanged,\n builder: (context, snapshot) {\n final info = snapshot.data;\n if (info == null) return const Text('Checking…');\n return Text('${info.type.label} · ${info.isConnected}');\n },\n)","connectivity-only-minimal-example--仅连通性最小示例#Connectivity-only: minimal example / 仅连通性:最小示例":"If all you need is \"am I online, on what transport, what IP, and react to\nchanges\", you only need this page — no init() required.如果只需要「在不在線、走什么網络、IP 是多少、切换时通知」,只看本页即可——\n无需 init()。\nclass ConnectivityScreen extends StatelessWidget {\n const ConnectivityScreen({super.key});\n @override\n Widget build(BuildContext context) {\n return StreamBuilder(\n stream: NetworkDiagnostic.onConnectivityChanged,\n builder: (context, snap) {\n final c = snap.data;\n if (c == null) {\n return const Center(child: CircularProgressIndicator());\n }\n return ListView(\n children: [\n ListTile(title: const Text('Type / 类型'), trailing: Text(c.type.label)),\n ListTile(title: const Text('Online / 在线'), trailing: Text('${c.isConnected}')),\n ListTile(title: const Text('IPv4'), trailing: Text(c.ipAddress ?? '—')),\n ListTile(title: const Text('IPv6'), trailing: Text(c.ipv6Address ?? '—')),\n ],\n );\n },\n );\n }\n}"}},"/DNS":{"title":"DNS / DNS 解析","data":{"":"NetworkDiagnostic.resolve() tests DNS resolution across multiple servers in\nparallel, so you can spot the fastest one. Each result is either the system\nresolver or a raw UDP query against an explicit server.NetworkDiagnostic.resolve() 并行测试多台 DNS 服务器的解析表现,从而挑出最快的一台。\n每条结果要么来自系统解析器,要么是对指定服务器的原始 UDP 查询。","basic--基础#Basic / 基础":"final results = await NetworkDiagnostic.resolve(\n domain: 'example.com',\n dnsServers: const ['1.1.1.1', '8.8.8.8', '114.114.114.114'],\n timeout: const Duration(seconds: 5),\n concurrent: true,\n includeSystemResolver: true,\n);\nfor (final r in results) {\n if (r.isSuccess) {\n print('${r.server.padRight(16)} → ${r.resolvedIps.join(\", \")} '\n '(${r.responseTimeMs.toStringAsFixed(1)} ms)');\n } else {\n print('${r.server.padRight(16)} ✗ ${r.errorMessage}');\n }\n}\nParameter\tDefault\tMeaning\tdomain\tconfig.dnsDomain\tDomain to resolve\tdnsServers\tconfig.dnsServers\tServers queried in parallel (or in series)\ttimeout\tconfig.dnsTimeout\tTimeout of one query\tconcurrent\ttrue\tQuery all servers at once\tincludeSystemResolver\tfalse\tAlso add a system row\t\nNotes / 说明:\nA row with server == 'system' comes from the OS resolver; the others are raw\nUDP queries against the listed IPs, encoded by the built-in DnsPacket wire\ncodec.\nserver == 'system' 的行来自系统解析器,其余是对指定 IP 的原始 UDP 查询,由内置\nDnsPacket 编解码。\nincludeSystemResolver defaults to false at the facade level — pass\ntrue to include it.\n门面层默认不包含系统解析器,需显式传 true。","pick-the-fastest--挑出最快的#Pick the fastest / 挑出最快的":"final fastest = results\n .where((r) => r.isSuccess)\n .reduce((a, b) => a.responseTimeMs <= b.responseTimeMs ? a : b);\nprint('fastest resolver: ${fastest.server}');"}},"/FAQ":{"title":"FAQ / 常见问题","data":{"do-i-need-to-call-init--需要调用-init-吗#Do I need to call init()? / 需要调用 init() 吗?":"No. Every API falls back to built-in defaults. Call ZeroNetworkKit.init() only\nwhen you want to override defaults (e.g. a custom reachability host or DNS\nservers). Connectivity alone works with zero setup.不需要。每个 API 都走内置默认值。只有在想覆盖默认参数(如自定义可达性主机或 DNS\n服务器)时才调用 ZeroNetworkKit.init()。单用连通性完全零配置。","which-platforms-are-supported--支持哪些平台#Which platforms are supported? / 支持哪些平台?":"Android, iOS, macOS, Windows and Linux. Web is not supported.支持 Android、iOS、macOS、Windows 与 Linux。Web 不支持。详见\nPlatform Support。","why-is-ssid--signalstrength-null-on-desktop--为什么桌面上的-ssid信号强度是-null#Why is ssid / signalStrength null on desktop? / 为什么桌面上的 ssid/信号强度是 null?":"Desktop uses tier A: SSID and RSSI require system APIs that aren't exposed on\nmacOS/Linux/Windows the same way. They are always null on desktop; Windows\nadditionally provides gateway / MAC / DNS / VPN via GetAdaptersAddresses.桌面采用 A 档:SSID 与 RSSI 依赖系统 API,在桌面上不以同样方式暴露,因此恒为 null;\nWindows 额外通过 GetAdaptersAddresses 提供网关 / MAC / DNS / VPN。","why-does-getnativenetworkdetails-return-null--为什么-getnativenetworkdetails-返回-null#Why does getNativeNetworkDetails() return null? / 为什么 getNativeNetworkDetails 返回 null?":"Either the platform has no such data (e.g. desktop tier A), or the required\npermission is missing (e.g. location for Wi-Fi SSID on Android/iOS). The call\nnever throws — it degrades gracefully.要么是平台没有该数据(如桌面 A 档),要么是缺权限(如 Android/iOS 上读取 Wi-Fi SSID\n需定位权限)。该调用绝不抛异常,会优雅降级。","does-the-speed-test-use-my-bandwidth--测速会消耗我的流量吗#Does the speed test use my bandwidth? / 测速会消耗我的流量吗?":"Yes — the default endpoints are Cloudflare's public service and download ≈25 MB\nby default. Ask for consent on metered connections and override downloadUrl /\nuploadUrl for production.会——默认端点指向 Cloudflare 公共服务,默认下载约 25 MB。在按量计费网络上请征得同意,\n生产环境请替换 downloadUrl / uploadUrl。","how-do-i-test-my-integration-without-the-network--如何脱离网络测试我的集成#How do I test my integration without the network? / 如何脱离网络测试我的集成?":"Every service is injectable. Implement ConnectivityAdapter (or pass fake\nservice instances) and call NetworkDiagnostic.configure(...), then\nNetworkDiagnostic.reset() to restore defaults. See\nUsage → Dependency injection.每个服务都可注入。实现 ConnectivityAdapter(或直接传入假服务实例)后调用\nNetworkDiagnostic.configure(...),再用 NetworkDiagnostic.reset() 恢复默认。详见\n用法 → 依赖注入。","how-is-this-licensed--采用什么许可证#How is this licensed? / 采用什么许可证?":"MPL-2.0. See the repository LICENSE.采用 MPL-2.0。详见仓库 LICENSE。"}},"/Full-Report":{"title":"Full Report / 汇总报告","data":{"":"NetworkDiagnostic.diagnose() runs every probe you ask for and aggregates them\ninto one NetworkDiagnosticReport. A failing sub-test never aborts the run — its\nfield simply stays empty/null.NetworkDiagnostic.diagnose() 运行你指定的各项探测,并汇总为一份\nNetworkDiagnosticReport。任何子项失败都不会中断整体流程,对应字段保持空。","basic--基础#Basic / 基础":"final report = await NetworkDiagnostic.diagnose(\n includePing: true,\n includeDns: true,\n includePorts: true,\n includeSpeedTest: true,\n includeUpload: true,\n host: '1.1.1.1',\n dnsDomain: 'example.com',\n dnsServers: const ['1.1.1.1', '8.8.8.8'],\n ports: const [80, 443],\n);\nprint(report); // one-line summary\nprint(report.connection.type.label);\nprint(report.ping?.averageTime);\nprint(report.dnsResults.length);\nprint(report.portResults.where((p) => p.isOpen).length);\nprint(report.speedTest?.downloadSpeed);\nprint(report.quality.level.label);\nParameter\tDefault\tMeaning\tincludePing\ttrue\tSample latency / jitter / loss\tincludeDns\ttrue\tSample DNS latency\tincludePorts\tfalse\tScan ports (off by default)\tincludeSpeedTest\ttrue\tSample download / upload\tincludeUpload\ttrue\tInclude the upload metric\thost\tconfig.pingHost\tLatency / port target\tdnsDomain / dnsServers\tfrom config\tDNS target\tports\tconfig.probePorts\tPorts scanned when includePorts is true\t\nincludePorts defaults to false, so a default run does not scan ports.\nincludePorts 默认 false,默认运行不会扫描端口。\nThe report is JSON-encodable via report.toMap().\n报告可通过 report.toMap() 序列化为 JSON。"}},"/Getting-Started":{"title":"Getting Started / 快速开始","data":{"quick-start--快速开始#Quick Start / 快速开始":"Import the package and start diagnosing — no init() required:导入包即可开始诊断,无需 init():\nimport 'package:flutter/material.dart';\nimport 'package:zero_network_kit/zero_network_kit.dart';\nvoid main() {\n // Optional: apply your own global defaults once.\n // 可选:全局定制一次默认参数。\n ZeroNetworkKit.init(\n config: const NetworkDiagnosticConfig(pingHost: '1.1.1.1'),\n );\n runApp(const MyApp());\n}\nIf you only need connectivity, you don't even need init():如果只需要连通性,连 init() 都不需要:\nfinal connection = await NetworkDiagnostic.checkConnection();\nprint('${connection.type.label} · ${connection.ipAddress}');","what-you-get--你能得到什么#What you get / 你能得到什么":"Every method is a static, non-blocking call on the NetworkDiagnostic facade.\nThe plugin is pure Dart under the hood, so it is fully injectable and testable\nwithout touching the network.每个方法都是 NetworkDiagnostic 门面上的静态、非阻塞调用。插件内核是纯 Dart,\n因此完全可注入、可脱离网络做测试。\nNeed\tCall\tAm I online, on what transport?\tNetworkDiagnostic.checkConnection()\tReact to Wi-Fi ⇄ cellular switches\tNetworkDiagnostic.onConnectivityChanged\tLatency, jitter, packet loss\tNetworkDiagnostic.ping()\tIs DNS slow or broken?\tNetworkDiagnostic.resolve()\tIs host:port reachable?\tNetworkDiagnostic.checkPort() / isPortOpen()\tHow fast is down/up?\tNetworkDiagnostic.runSpeedTest()\tOne number for \"good or bad\"\tNetworkDiagnostic.evaluateQuality()\tEverything at once\tNetworkDiagnostic.diagnose()\tNative version / SSID / gateway / MAC\tZeroNetworkKit.getNativeNetworkDetails()\t\nSee Which API do I need? for the full map.","lifecycle--生命周期#Lifecycle / 生命周期":"ZeroNetworkKit.isInitialized; // false until init() runs\nZeroNetworkKit.config; // the effective NetworkDiagnosticConfig\nawait ZeroNetworkKit.dispose(); // releases the HTTP client the plugin owns\ndispose() only closes the HTTP client the plugin created itself. An\nhttp.Client you injected stays open — close it yourself.dispose() 只会关闭插件自己创建的 HTTP 客户端;你注入的 http.Client 不会被关闭。","next-steps--下一步#Next Steps / 下一步":"Installation — Detailed installation methods / 详细安装方式\nUsage — Global config & dependency injection / 全局配置与依赖注入\nPlatform Support — Capability matrix / 能力矩阵"}},"/Installation":{"title":"Installation / 安装","data":{"from-pubdev-recommended--从-pubdev-安装推荐#From pub.dev (Recommended) / 从 pub.dev 安装(推荐)":"Add the following to your pubspec.yaml:在 pubspec.yaml 中添加以下依赖:\ndependencies:\n zero_network_kit: ^1.0.1\nThen run:然后运行:\nflutter pub get","from-github--从-github-安装#From GitHub / 从 GitHub 安装":"Alternatively, install from GitHub:或者从 GitHub 安装:\ndependencies:\n zero_network_kit:\n git:\n url: https://github.com/zero-labsco/zero_network_kit.git\n ref: release/v1.0.1","platform-setup--平台配置#Platform Setup / 平台配置":"","android#Android":"The plugin manifest already declares INTERNET, ACCESS_NETWORK_STATE and\nACCESS_WIFI_STATE. Reading the Wi-Fi SSID additionally requires the\nlocation permission (ACCESS_FINE_LOCATION) on Android 8.1+, otherwise the\nsnapshot reports ssid: null.插件清单已声明 INTERNET、ACCESS_NETWORK_STATE 与 ACCESS_WIFI_STATE。读取 Wi-Fi\nSSID 还需在 Android 8.1+ 申请定位权限(ACCESS_FINE_LOCATION),否则快照中\nssid 为 null。","ios#iOS":"No additional configuration needed. Reading the Wi-Fi SSID additionally\nrequires the Access WiFi Information capability plus location authorisation.无需额外配置。读取 Wi-Fi SSID 还需开启 Access WiFi Information 能力并授权定位。","macos--windows--linux#macOS / Windows / Linux":"The plugin is declared on all three desktop platforms. On desktop, native\ndetails such as SSID / RSSI are always null (tier A). Windows additionally\nprovides gateway / MAC / DNS / VPN through GetAdaptersAddresses; macOS and\nLinux report only the Dart-side IP/IPv6. See\nPlatform Support for the full matrix.插件已在三个桌面平台声明。桌面上 SSID / 信号强度等原生详情恒为 null(A 档)。\nWindows 额外通过 GetAdaptersAddresses 提供网关 / MAC / DNS / VPN;macOS 与 Linux\n仅提供 Dart 侧的 IP/IPv6。完整矩阵见平台支持。","import--导入#Import / 导入":"import 'package:zero_network_kit/zero_network_kit.dart';","requirements--环境要求#Requirements / 环境要求":"Requirement\tVersion\tFlutter\t>= 3.3.0\tDart SDK\t>= 3.11.0 < 4.0.0","next-steps--下一步#Next Steps / 下一步":"Getting Started — Quick start guide / 快速开始\nUsage — Full usage guide / 完整使用指南"}},"/Ping":{"title":"Latency / Ping / 延迟探测","data":{"":"NetworkDiagnostic.ping() measures round-trip time towards a target host and\nreports sent / received counts, packet loss, min/avg/max and jitter.NetworkDiagnostic.ping() 测量到目标主机的往返时间,并给出发送/接收次数、丢包率、\n最小/平均/最大耗时与抖动。","basic--基础#Basic / 基础":"final ping = await NetworkDiagnostic.ping(\n host: '1.1.1.1',\n count: 5,\n timeout: const Duration(seconds: 2),\n interval: const Duration(milliseconds: 200),\n port: 443,\n);\nprint('received : ${ping.received}/${ping.sent}');\nprint('loss : ${ping.packetLoss.toStringAsFixed(1)} %');\nprint('min/avg/max: ${ping.minTime.toStringAsFixed(1)} / '\n '${ping.averageTime.toStringAsFixed(1)} / '\n '${ping.maxTime.toStringAsFixed(1)} ms');\nprint('jitter : ${ping.jitter.toStringAsFixed(2)} ms');\nprint('samples : ${ping.times}');\nParameter\tDefault\tMeaning\thost\tconfig.pingHost\tTarget host\tcount\tconfig.pingCount\tNumber of probes\ttimeout\tconfig.pingTimeout\tPer-probe timeout\tinterval\tconfig.pingInterval\tDelay between probes\tport\tconfig.pingPort\tTCP port probed in PingMode.tcp\tmode\tPingMode.tcp\tPingMode.tcp or PingMode.icmp","tcp-vs-icmp--tcp-与-icmp#TCP vs ICMP / TCP 与 ICMP":"PingMode.tcp performs a TCP handshake to host:port — the portable equivalent\nof ICMP and the only mode available on Android/iOS.PingMode.tcp 通过 TCP 握手到 host:port 测量往返,是移动端唯一可用的模式。\n// Desktop only — falls back gracefully if the `ping` binary is unavailable.\nawait NetworkDiagnostic.ping(host: '1.1.1.1', count: 4, mode: PingMode.icmp);\nping.isSuccess is true when at least one probe answered; check it before\ntrusting the averages.至少一次成功响应时 isSuccess 为 true,读平均值前建议先判断它。\nA TCP ping needs a listening port. Probing host with port: 443 fails if\nthat host does not accept TCP/443 — that is \"filtered\", not \"offline\". Use\nmode: PingMode.icmp on desktop to get closer to real ICMP.\nTCP 探测需要一个在监听的端口。对不接受 TCP/443 的主机探测 port: 443 会失败——\n那是“被过滤”,不是“离线”。在桌面上用 PingMode.icmp 更接近真实 ICMP。"}},"/Platform-Support":{"title":"Platform Support / 平台支持","data":{"":"zero_network_kit is declared on five plugin platforms: Android, iOS,\nmacOS, Windows and Linux. Web is not supported — the Dart services rely on\ndart:io, which does not compile for the web, and browsers have no raw\nTCP/UDP sockets.zero_network_kit 在 五 个插件平台上声明:Android、iOS、macOS、Windows 与\nLinux。不支持 Web——Dart 服务依赖 dart:io(无法在 Web 上编译),且浏览器没有\n原生 TCP/UDP 套接字。","capability-matrix--能力矩阵#Capability matrix / 能力矩阵":"Capability\tAndroid / iOS\tDesktop (macOS / Windows / Linux)\tConnectivity (connectivity_plus)\t✅\t✅\tLocal IP / IPv6 (NetworkInterface)\t✅\t✅\tNative details (SSID / gateway / MAC / VPN)\t✅\t⚠️ see below\tTCP ping\t✅\t✅\tICMP ping (Process.run('ping'))\t❌\t✅\tHTTP ping\t✅\t✅\tDNS system resolver\t✅\t✅\tDNS raw UDP\t✅\t✅\tPort check / scan\t✅\t✅\tSpeed test\t✅\t✅\tQuality score\t✅\t✅\tBenchmarks\t✅\t✅","networkcapabilities--能力查询#NetworkCapabilities / 能力查询":"Query the host platform before calling, so your UI can hide unsupported cards:在调用前查询当前平台能力,UI 即可据此隐藏不支持的卡片:\nfinal caps = NetworkDiagnostic.capabilities;\nprint(caps.platform); // 'android' | 'ios' | 'macos' | 'windows' | 'linux'\nprint(caps.supports(NetworkCapability.nativeDetails)); // mobile: true, desktop: false\nprint(caps.supports(NetworkCapability.icmpPing)); // desktop: true, mobile: false\nRules baked into NetworkCapabilities.current():\nnativeDetails is mobile-only (SSID / gateway / MAC / VPN need system APIs).\nicmpPing is desktop-only (uses the system ping binary).\nNetworkCapabilities.current() 内置规则:\nnativeDetails 仅移动端(SSID / 网关 / MAC / VPN 需要系统 API)。\nicmpPing 仅桌面(使用系统 ping 命令)。","native-details-on-desktop--桌面原生详情#Native details on desktop / 桌面原生详情":"Desktop uses tier A by default: the native layer only reports the platform\nversion and an (often empty) details map. IP/IPv6 come from Dart\nNetworkInterface. As a result:桌面默认采用 A 档:原生层只报告平台版本与(通常为空的)详情 map,IP/IPv6 由 Dart\nNetworkInterface 兜底。因此:\nSSID / signal strength are always null on desktop.\n桌面上的 SSID / 信号强度恒为 null。\ngateway / macAddress / isVpn are null on macOS and Linux.\nmacOS 与 Linux 上 gateway / macAddress / isVpn 为 null。\nWindows additionally implements GetAdaptersAddresses, so it reports\ngateway / macAddress / DNS / isVpn (SSID still null). This is a bonus\ntier-B fragment kept as-is.\nWindows 额外实现了 GetAdaptersAddresses,因此上报 gateway / macAddress /\nDNS / isVpn(SSID 仍为 null)。这是保留的 B 档赠品。\nWhatever the platform, a missing permission or an unreachable native call never\nthrows — the field simply stays null and the rest of the result still arrives.无论在哪个平台,缺权限或原生调用不可达都不会抛异常——对应字段保持 null,其余\n结果照常返回。","reading-native-data--读取原生数据#Reading native data / 读取原生数据":"final version = await ZeroNetworkKit.getPlatformVersion();\nprint(version); // e.g. 'Android 14' / 'iOS 18.0'\nfinal details = await ZeroNetworkKit.getNativeNetworkDetails();\nif (details != null) {\n print(details); // SSID, BSSID, gateway, MAC, VPN flag, RSSI …\n}"}},"/Ports":{"title":"Ports / 端口检测","data":{"":"checkPort() returns a full PortCheckResult for one port; isPortOpen() is the\nplain boolean convenience; scanPorts() runs many ports concurrently with\nbounded in-flight connections.checkPort() 返回单个端口的完整 PortCheckResult;isPortOpen() 是便捷的布尔版;\nscanPorts() 以有界并发批量扫描多个端口。","single-port--单端口#Single port / 单端口":"// Boolean convenience / 便捷布尔版\nfinal open = await NetworkDiagnostic.isPortOpen(\n host: 'example.com',\n port: 443,\n timeout: const Duration(seconds: 3),\n);\nprint(open ? 'HTTPS reachable' : 'HTTPS unreachable');\n// Full result with RTT and error message / 含 RTT 与错误信息的完整结果\nfinal result = await NetworkDiagnostic.checkPort(host: 'example.com', port: 443);\nprint('open=${result.isOpen} rtt=${result.responseTimeMs} ms '\n 'err=${result.errorMessage}');","bulk-scan--批量扫描#Bulk scan / 批量扫描":"final scan = await NetworkDiagnostic.scanPorts(\n host: 'example.com',\n ports: const [22, 80, 443, 8080, 8443],\n concurrency: 8,\n);\nfor (final r in scan) {\n print('${r.host}:${r.port} '\n '${r.isOpen ? \"open\" : \"closed\"} '\n '${r.responseTimeMs.toStringAsFixed(1)} ms '\n '${r.errorMessage ?? \"\"}');\n}\nParameter\tDefault\tMeaning\tports (scanPorts)\tconfig.probePorts ([80, 443])\tPorts to probe\tconcurrency\t12\tMax in-flight connections\ttimeout\tconfig.portCheckTimeout\tTimeout per port\t\ncheckPort() returns a PortCheckResult (with isOpen, responseTimeMs\nand errorMessage); use isPortOpen() for a plain boolean. When you need the\nround-trip time or the failure reason for a single port, call checkPort()\ndirectly or pass a one-element list to scanPorts():\nscanPorts(host: 'example.com', ports: [443]).first.\ncheckPort() 返回 PortCheckResult(含 isOpen、responseTimeMs、\nerrorMessage);单端口布尔诉求请用 isPortOpen()。需要 RTT 或失败原因时可直接\n调用 checkPort(),或给 scanPorts(..., ports: [443]) 取单条结果。"}},"/Quality":{"title":"Quality Score / 质量评分","data":{"":"NetworkDiagnostic.evaluateQuality() returns a weighted 0–100 score plus a\nlevel and human-readable suggestions, computed over whatever metrics are\navailable.NetworkDiagnostic.evaluateQuality() 返回一个加权 0–100 分,附带等级与可读建议,\n它基于当前可用的各项指标计算得出。","basic--基础#Basic / 基础":"final quality = await NetworkDiagnostic.evaluateQuality(\n includePing: true,\n includeDns: true,\n includeSpeedTest: true,\n includeUpload: true,\n);\nprint('${quality.score.toStringAsFixed(1)}/100 — ${quality.level.label}');\nquality.metrics.forEach((metric, value) {\n print(' $metric = ${value.toStringAsFixed(2)}');\n});\nfor (final suggestion in quality.suggestions) {\n print('• $suggestion');\n}\nParameter\tDefault\tMeaning\tincludePing\ttrue\tSample latency / jitter / loss\tincludeDns\ttrue\tSample DNS latency\tincludeSpeedTest\ttrue\tSample download / upload (heavy)\tincludeUpload\ttrue\tInclude the upload metric\tpingHost / pingCount\tfrom config\tLatency target\tdnsDomain / dnsServers\tfrom config\tDNS target\tdownloadUrl / uploadUrl\tfrom config\tBandwidth endpoints","lightweight-variant--轻量变体#Lightweight variant / 轻量变体":"final quality = await NetworkDiagnostic.evaluateQuality(includeSpeedTest: false);","level-thresholds--等级阈值#Level thresholds / 等级阈值":"≥90 excellent · ≥75 good · ≥60 fair · ≥40 poor · otherwise bad\n(NetworkQualityLevel.fromScore).≥90 极佳 · ≥75 良好 · ≥60 一般 · ≥40 较差 · 其余为极差。","weights--权重#Weights / 权重":"Metric\tWeight\tSource\tlatency\t0.25\tPingResult.averageTime\tjitter\t0.10\tPingResult.jitter\tpacketLoss\t0.15\tPingResult.packetLoss\tdownload\t0.25\tSpeedTestResult.downloadSpeed\tupload\t0.15\tSpeedTestResult.uploadSpeed\tdns\t0.10\tmean of successful DnsTestResult.responseTimeMs\tsignalStrength\t0.10\tNetworkConnectionInfo.signalStrength","pure-function--纯函数#Pure function / 纯函数":"If you already have the metrics, skip the network entirely:如果你已有指标,可完全跳过网络:\nfinal score = NetworkQualityEvaluator.evaluate(\n latency: 42, jitter: 6, packetLoss: 0,\n download: 88.4, upload: 12.1, dns: 25, signalStrength: -55,\n targets: const QualityTargets(),\n);\nprint('${score.score.toStringAsFixed(1)} → ${score.level.label}');\nTune the ideal values globally through NetworkDiagnosticConfig(qualityTargets: ...).\n调整理想值请通过 NetworkDiagnosticConfig(qualityTargets: ...) 全局设置。"}},"/Speed-Test":{"title":"Speed Test / 测速","data":{"":"NetworkDiagnostic.runSpeedTest() measures download and upload throughput and\nsamples latency during the run, reporting progress through onProgress.NetworkDiagnostic.runSpeedTest() 测量下载与上传吞吐量,并在过程中采样延迟,通过\nonProgress 汇报进度。","basic--基础#Basic / 基础":"final speed = await NetworkDiagnostic.runSpeedTest(\n includeUpload: true,\n includePing: true,\n onProgress: (progress) {\n print('${progress.phase.name}: '\n '${progress.speedMbps.toStringAsFixed(1)} Mbps '\n '(${progress.bytes} bytes, ${progress.elapsed.inMilliseconds} ms)');\n },\n);\nprint('download : ${speed.downloadSpeed.toStringAsFixed(2)} Mbps');\nprint('upload : ${speed.uploadSpeed.toStringAsFixed(2)} Mbps');\nprint('ping : ${speed.ping.toStringAsFixed(1)} ms');\nprint('jitter : ${speed.jitter.toStringAsFixed(2)} ms');\nprint('loss : ${speed.packetLoss.toStringAsFixed(1)} %');\nprint('server : ${speed.server}');\nprint('duration : ${speed.duration.inMilliseconds} ms');\nParameter\tDefault\tMeaning\tdownloadUrl / uploadUrl\tfrom config\tEndpoints used\ttimeout\tconfig.speedTestTimeout\tPer-request timeout\tmaxDuration\tconfig.speedTestMaxDuration\tSampling window per phase\tuploadPayloadBytes\tconfig.uploadPayloadBytes\tUpload size\tpingHost / pingCount\tfrom config\tLatency sampled during the test\tincludeUpload\ttrue\tSkip the upload phase\tincludePing\ttrue\tSkip the latency sample\tonProgress\tnull\tCalled repeatedly during both phases\t\nProgress phases: SpeedTestPhase.download → SpeedTestPhase.upload →\nSpeedTestPhase.completed.进度阶段依次为 download → upload → completed。","fast-low-traffic-variant--轻量低流量变体#Fast, low-traffic variant / 轻量低流量变体":"final quick = await NetworkDiagnostic.runSpeedTest(\n includeUpload: false,\n includePing: false,\n maxDuration: const Duration(seconds: 5),\n);\nThe default endpoints point at Cloudflare's public speed service and move real\ntraffic (≈25 MB download by default). Ask for consent before running it on a\nmetered connection, and override downloadUrl / uploadUrl for production.\n默认端点指向 Cloudflare 公共服务并会产生真实流量(默认下载约 25 MB)。在按量计费\n网络上运行前请征得同意,并为生产环境替换 downloadUrl / uploadUrl。"}},"/Usage":{"title":"Usage / 用法","data":{"which-api-do-i-need--该用哪个-api#Which API do I need? / 该用哪个 API?":"I want to know…\tCall\tAm I online, and over what transport?\tNetworkDiagnostic.checkConnection()\tReact to Wi-Fi ⇄ cellular switches\tNetworkDiagnostic.onConnectivityChanged\tLatency, jitter, packet loss\tNetworkDiagnostic.ping()\tIs DNS slow or broken?\tNetworkDiagnostic.resolve()\tIs host:port reachable?\tNetworkDiagnostic.checkPort()\tWhich of these ports are open?\tNetworkDiagnostic.scanPorts()\tHow fast is down/up?\tNetworkDiagnostic.runSpeedTest()\tOne number for “good or bad”\tNetworkDiagnostic.evaluateQuality()\tEverything at once, as a report\tNetworkDiagnostic.diagnose()\tIs the diagnostics API itself expensive?\tNetworkBenchmark.runAll()\tNative version / SSID / gateway / MAC\tZeroNetworkKit.getPlatformVersion(), getNativeNetworkDetails()","global-configuration--全局配置#Global configuration / 全局配置":"NetworkDiagnosticConfig centralises every default. Override only what you\nneed; the rest keep the defaults below.NetworkDiagnosticConfig 集中了全部默认参数,只需覆盖你关心的字段。\nZeroNetworkKit.init(\n config: const NetworkDiagnosticConfig(\n pingHost: '1.1.1.1',\n pingPort: 443,\n pingCount: 5,\n dnsDomain: 'example.com',\n dnsServers: ['1.1.1.1', '8.8.8.8'],\n downloadUrl: 'https://my-cdn.example.com/speedtest.bin',\n uploadUrl: 'https://my-cdn.example.com/upload',\n ),\n);\nField\tDefault\tMeaning\tpingHost\t'1.1.1.1'\tDefault ping / port-scan target\tpingPort\t443\tPort used by the TCP ping\tpingCount\t4\tProbes per ping run\tpingTimeout\t3s\tTimeout of one probe\tpingInterval\t200ms\tDelay between probes\tdnsDomain\t'www.google.com'\tDefault domain for DNS tests\tdnsServers\t['1.1.1.1', '8.8.8.8', '114.114.114.114']\tServers queried by default\tdnsTimeout\t5s\tTimeout per DNS server\tdownloadUrl\tCloudflare __down?bytes=25000000\tDownload endpoint\tuploadUrl\tCloudflare __up\tUpload endpoint\tuploadPayloadBytes\t1048576 (1 MiB)\tUpload payload size\tspeedTestTimeout\t30s\tPer-request timeout\tspeedTestMaxDuration\t10s\tSampling window per phase\tportCheckTimeout\t3s\tTimeout of one port check\tprobePorts\t[80, 443]\tPorts used by scanPorts() by default\tqualityTargets\tconst QualityTargets()\tIdeal values for scoring\t\nThe default speed-test endpoints are Cloudflare's public service. Swap them for\nyour own before shipping production traffic.\n默认测速端点是 Cloudflare 的公共服务,正式项目请替换为自建端点。","quality-targets--质量评分理想值#Quality targets / 质量评分理想值":"const NetworkDiagnosticConfig(\n qualityTargets: QualityTargets(\n excellentLatency: 30, // ms\n acceptableLatency: 150, // ms\n excellentJitter: 5, // ms\n acceptableJitter: 40, // ms\n acceptablePacketLoss: 5, // %\n excellentDownload: 50, // Mbps\n acceptableDownload: 5, // Mbps\n excellentUpload: 20, // Mbps\n acceptableUpload: 2, // Mbps\n excellentDns: 30, // ms\n acceptableDns: 200, // ms\n ),\n);","json-serialisation--序列化#JSON serialisation / 序列化":"Every result object implements toMap() and is JSON encodable:每个结果对象都实现了 toMap(),可直接 JSON 序列化:\nimport 'dart:convert';\nfinal report = await NetworkDiagnostic.diagnose(includeSpeedTest: false);\nfinal json = jsonEncode(report.toMap());\nprint(json);\n// Round-trip a connection snapshot.\nfinal decoded = NetworkConnectionInfo.fromMap(jsonDecode(jsonEncode(\n report.connection.toMap(),\n)) as Map);\nType\tSerialisation\tNetworkConnectionInfo\ttoMap() + fromMap()\tPingResult\ttoMap()\tDnsTestResult\ttoMap()\tPortCheckResult\ttoMap()\tSpeedTestResult\ttoMap()\tNetworkQualityScore\ttoMap()\tNetworkDiagnosticReport\ttoMap()\tBenchmarkResult / BenchmarkSuiteResult\ttoMap()","dependency-injection--tests--注入与测试#Dependency injection & tests / 注入与测试":"Every service accepts its collaborators, so your integration points are\nunit-testable without touching the network.每个服务都支持注入协作对象,可以完全脱离网络做单测。\nclass FakeConnectivityAdapter implements ConnectivityAdapter {\n @override\n Future> checkConnectivity() async => ['wifi'];\n @override\n Stream> get onConnectivityChanged => const Stream.empty();\n}\nNetworkDiagnostic.configure(\n config: const NetworkDiagnosticConfig(pingHost: '127.0.0.1'),\n connectivity: ConnectivityService(adapter: FakeConnectivityAdapter()),\n ping: PingService(),\n dns: DnsService(),\n ports: PortService(),\n speedTest: SpeedTestService(client: fakeClient),\n);\n// Restore defaults afterwards.\nNetworkDiagnostic.reset();\nSwap individual services directly when you prefer:也可以直接替换单个服务:\nNetworkDiagnostic.pingService = MyFakePingService();\nNetworkDiagnostic.dnsService = MyFakeDnsService();\nFor advanced service classes, the DNS wire codec and low-level APIs, import\npackage:zero_network_kit/advanced.dart.\n进阶的服务类、DNS 报文编解码器等底层 API 请通过\npackage:zero_network_kit/advanced.dart 引入。"}},"/":{"title":"Zero Network Kit","data":{"":"A Flutter plugin for network diagnostics: connectivity inspection, latency\nprobing, DNS resolution, port checks, bandwidth measurement, quality scoring and\nmicro-benchmarks — on Android, iOS, macOS, Windows and Linux.一个 Flutter 插件,提供网络诊断能力:连通性检测、延迟探测、DNS 解析、端口\n检测、带宽测速、质量评分与微基准测试——覆盖 Android、iOS、macOS、Windows 与 Linux。","-features--功能特性#✨ Features / 功能特性":"Feature\tDescription\tZero setup\tWorks out of the box; init() only to override defaults / 开箱即用,仅需在想覆盖默认值时才 init()\tConnectivity\tTransport type, IPv4/IPv6, gateway, SSID, RSSI, MAC, VPN / 传输类型、IPv4/IPv6、网关、SSID、信号强度、MAC、VPN\tLatency\tTCP handshake RTT everywhere; system ICMP on desktop / TCP 握手 RTT 全平台可用,桌面额外支持系统 ICMP\tDNS\tSystem resolver + raw UDP against explicit servers / 系统解析器 + 针对指定服务器的原始 UDP 查询\tPorts\tBounded-concurrency TCP reachability / 有界并发的 TCP 可达性检测\tSpeed test\tDownload/upload throughput with progress callbacks / 上下行测速,带进度回调\tQuality\tWeighted 0–100 score + level + suggestions / 加权 0–100 分 + 等级 + 建议\tFull report\tOne-shot aggregate of every probe / 一次性汇总所有探测\tBenchmarks\tMeasures how fast the diagnostics API itself runs / 衡量诊断 API 自身开销\tCapabilities\tQuery-then-call; hide unsupported cards (e.g. SSID on desktop) / 先查询后调用,隐藏不支持的卡片\tGraceful degradation\tMissing permission or unreachable sub-service never throws / 缺权限或子服务不可达时只返回 null,绝不抛异常\tHermetic tests\tEvery service accepts injected collaborators / 每个服务都支持注入协作对象,便于单测","-table-of-contents--目录#📚 Table of Contents / 目录":"Page\tDescription\tGetting Started\tQuick start guide / 快速开始\tInstallation\tHow to install / 安装方式\tUsage\tGlobal config, serialisation, dependency injection / 全局配置、序列化、依赖注入\tConnectivity\tConnection snapshot & change stream / 连通性快照与变化监听\tLatency / Ping\tTCP & ICMP latency probing / 延迟探测\tDNS\tResolver comparison across servers / DNS 解析\tPorts\tSingle port & bulk scan / 端口检测\tSpeed Test\tDownload/upload throughput / 测速\tQuality Score\tWeighted scoring / 质量评分\tFull Report\tOne-shot aggregate / 汇总报告\tBenchmarks\tMicro-benchmarks / 微基准\tPlatform Support\tCapability matrix & native details / 能力矩阵与原生详情\tAPI Reference\tModel field reference & gotchas / 模型字段速查与陷阱\tFAQ\tFrequently asked questions / 常见问题","-links--链接#🔗 Links / 链接":"GitHub\nOfficial Website\npub.dev","-license--许可证#📄 License / 许可证":"This project is licensed under the MPL-2.0.本项目采用 MPL-2.0 许可证。This plugin is provided \"as is\", without warranty of any kind. The author assumes\nno responsibility or liability for the functionality, security, or any\nconsequences arising from the use of modified versions or derivative projects.本插件按\"原样\"提供,不提供任何担保。作者不对修改版或衍生项目的功能、安全性及\n任何使用后果承担责任。"}}} \ No newline at end of file +{"/API-Reference":{"title":"API Reference / 接口参考","data":{"":"A condensed field reference for every public model. For copy-paste examples of\neach method, see the capability pages.这里是每个公开模型的字段速查。每个方法的复制即用示例请见各能力页面。","networktype#NetworkType":"Member\tNotes\tvalues\tnone, wifi, mobile, ethernet, vpn, bluetooth, other\tlabel\tHuman readable: 'Wi-Fi', 'Mobile', …\tid\tStable English identifier (name), safe to persist\tisConnected\ttrue unless none\tNetworkType.fromRaw(Object?)\tParses a raw platform string","networkconnectioninfo#NetworkConnectionInfo":"isConnected, type, ssid, signalStrength (dBm), ipAddress,\nipv6Address, gateway, macAddress, isVpn, isReachable, timestamp,\nplus copyWith({bool? isReachable}).","pingresult#PingResult":"Fields host, port, mode, sent, received, times, timestamp;\nderived getters lost, packetLoss (%), minTime, maxTime, averageTime,\njitter, isSuccess.","dnstestresult#DnsTestResult":"Fields server, domain, isSuccess, responseTime, resolvedIps,\nerrorMessage, timestamp; derived responseTimeMs, primaryAddress.","portcheckresult#PortCheckResult":"Fields host, port, isOpen, responseTime, errorMessage, timestamp;\nderived responseTimeMs.","speedtestresult#SpeedTestResult":"Fields downloadSpeed, uploadSpeed (Mbps), ping (ms), jitter (ms),\npacketLoss (%), downloadedBytes, uploadedBytes, downloadDuration,\nuploadDuration, server, timestamp; derived duration; static helper\nSpeedTestResult.mbpsFromBytes(bytes, elapsed).","speedtestprogress--speedtestphase#SpeedTestProgress / SpeedTestPhase":"phase (download, upload, completed), bytes, elapsed, speedMbps.","networkqualityscore--networkqualitylevel#NetworkQualityScore / NetworkQualityLevel":"score (0–100), level, metrics (Map), suggestions,\ntimestamp; NetworkQualityLevel.fromScore(double), level.label.","networkdiagnosticreport#NetworkDiagnosticReport":"connection, ping, dnsResults, portResults, speedTest, quality,\ntimestamp.","benchmarkresult--benchmarksuiteresult#BenchmarkResult / BenchmarkSuiteResult":"BenchmarkResult: testName, iterations, totalDuration,\naverageDuration, minDuration, maxDuration, standardDeviation,\noperationsPerSecond, failures, timestamp.\nBenchmarkSuiteResult: suiteName, results, totalDuration, timestamp,\nand suite['name'].","gotchas--常见陷阱#Gotchas / 常见陷阱":"type.label, not displayName. NetworkType exposes label / id.\ncheckPort() returns PortCheckResult. Use isPortOpen() for a plain\nboolean, or scanPorts(..., ports: [p]).first for RTT / error message.\nincludeSystemResolver defaults to false. Pass true to add the\nsystem DNS row.\nA TCP ping needs a listening port. Probing host with port: 443 fails\nif that host does not accept TCP/443 — that is \"filtered\", not \"offline\". Use\nmode: PingMode.icmp on desktop to get closer to real ICMP.\nPingMode.icmp is desktop-only and silently degrades when the ping\nbinary is unavailable.\nThe speed test moves real traffic (≈25 MB download by default). Ask for\nconsent before running it on a metered connection.\nMissing permissions degrade, they never throw. A missing location\npermission yields ssid == null; the rest of the snapshot still arrives.\nincludePorts is false by default in diagnose().\ninit() is optional, but dispose() only closes the client the plugin\nowns — an httpClient you injected stays open, so close it yourself.\nFull source-level API docs live in the repo:\nAPI.md\n(English) and\nAPI_zh.md\n(简体中文).\n完整源码级 API 文档见仓库内的\nAPI.md\n与 API_zh.md。"}},"/Benchmark":{"title":"Benchmarks / 微基准测试","data":{"":"NetworkBenchmark measures how fast the diagnostics API itself runs — useful\nwhen deciding whether a diagnostic belongs on your startup path.NetworkBenchmark 衡量诊断 API 自身的开销——可用在判断某项诊断能否放在启动路径上。","all-at-once--一次性全跑#All at once / 一次性全跑":"final suite = await NetworkBenchmark.runAll(\n iterations: 20,\n warmupIterations: 3,\n host: '1.1.1.1',\n dnsDomain: 'example.com',\n port: 443,\n);\nfor (final result in suite.results) {\n print('${result.testName.padRight(12)} '\n 'avg ${(result.averageDuration.inMicroseconds / 1000).toStringAsFixed(2)} ms '\n '± ${(result.standardDeviation.inMicroseconds / 1000).toStringAsFixed(2)} ms '\n '${result.operationsPerSecond.toStringAsFixed(1)} ops/s '\n 'failures=${result.failures}');\n}\n// Look up one benchmark by name / 按名称查单个结果\nprint(suite['ping']?.averageDuration);\nprint(suite.totalDuration);","individual-suites--单个基准#Individual suites / 单个基准":"await NetworkBenchmark.benchmarkConnection(iterations: 20);\nawait NetworkBenchmark.benchmarkPing(iterations: 20, host: '1.1.1.1');\nawait NetworkBenchmark.benchmarkDns(iterations: 20, domain: 'example.com');\nawait NetworkBenchmark.benchmarkPortCheck(iterations: 20, port: 443);\nawait NetworkBenchmark.benchmarkPlatformChannel(iterations: 20);","result-fields--结果字段#Result fields / 结果字段":"BenchmarkResult: testName, iterations, totalDuration, averageDuration,\nminDuration, maxDuration, standardDeviation, operationsPerSecond,\nfailures, timestamp.BenchmarkSuiteResult: suiteName, results, totalDuration, timestamp, and\nsuite['name']."}},"/Connectivity":{"title":"Connectivity / 连通性","data":{"":"NetworkDiagnostic.checkConnection() captures a single snapshot of the current\nnetwork; onConnectivityChanged emits a fresh snapshot on every transport\nchange.NetworkDiagnostic.checkConnection() 捕获当前网络的一次快照;onConnectivityChanged\n在每次传输方式变化时推送新快照。","snapshot--快照#Snapshot / 快照":"final connection = await NetworkDiagnostic.checkConnection();\nprint('type : ${connection.type.label}'); // Wi-Fi / Mobile / Ethernet …\nprint('connected : ${connection.isConnected}');\nprint('ipv4 : ${connection.ipAddress}');\nprint('ipv6 : ${connection.ipv6Address}');\nprint('gateway : ${connection.gateway}');\nprint('ssid : ${connection.ssid}');\nprint('rssi : ${connection.signalStrength} dBm');\nprint('mac : ${connection.macAddress}');\nprint('vpn : ${connection.isVpn}');\nprint('timestamp : ${connection.timestamp}');\nField\tNotes\ttype\tNetworkType (none, wifi, mobile, ethernet, vpn, bluetooth, other)\tisConnected\ttrue unless type is none\tipAddress / ipv6Address\tLocal IPv4 / IPv6 (Dart NetworkInterface)\tgateway / macAddress\tNative; null on desktop except Windows\tssid / signalStrength\tNative; always null on desktop\tisVpn\tNative VPN detection\tisReachable\tOnly filled when probeReachability: true\ttimestamp\tWhen the snapshot was taken\t\nUse connection.type.label / connection.type.id. There is no\ndisplayName.\n请使用 connection.type.label / connection.type.id,没有 displayName。","parameters--参数#Parameters / 参数":"Parameter\tDefault\tMeaning\tincludeNativeDetails\ttrue\tAlso read SSID / gateway / MAC / VPN from the native side\tprobeReachability\tfalse\tMake a real request and fill isReachable\tprobeTimeout\t3s\tTimeout of that reachability probe\t\n// Skip the native channel (cheapest call — good on hot paths).\nfinal quick = await NetworkDiagnostic.checkConnection(includeNativeDetails: false);\n// Prove the internet is actually reachable, not just that a NIC is up.\nfinal verified = await NetworkDiagnostic.checkConnection(\n probeReachability: true,\n probeTimeout: const Duration(seconds: 5),\n);\nif (verified.isReachable == false) {\n print('Interface is up but the internet is unreachable.');\n}","change-stream--变化监听#Change stream / 变化监听":"final subscription = NetworkDiagnostic.onConnectivityChanged.listen(\n (info) => print('now on ${info.type.id} · ${info.ipAddress}'),\n);\n// Later:\nawait subscription.cancel();\nIn a widget:\nStreamBuilder(\n stream: NetworkDiagnostic.onConnectivityChanged,\n builder: (context, snapshot) {\n final info = snapshot.data;\n if (info == null) return const Text('Checking…');\n return Text('${info.type.label} · ${info.isConnected}');\n },\n)","connectivity-only-minimal-example--仅连通性最小示例#Connectivity-only: minimal example / 仅连通性:最小示例":"If all you need is \"am I online, on what transport, what IP, and react to\nchanges\", you only need this page — no init() required.如果只需要「在不在線、走什么網络、IP 是多少、切换时通知」,只看本页即可——\n无需 init()。\nclass ConnectivityScreen extends StatelessWidget {\n const ConnectivityScreen({super.key});\n @override\n Widget build(BuildContext context) {\n return StreamBuilder(\n stream: NetworkDiagnostic.onConnectivityChanged,\n builder: (context, snap) {\n final c = snap.data;\n if (c == null) {\n return const Center(child: CircularProgressIndicator());\n }\n return ListView(\n children: [\n ListTile(title: const Text('Type / 类型'), trailing: Text(c.type.label)),\n ListTile(title: const Text('Online / 在线'), trailing: Text('${c.isConnected}')),\n ListTile(title: const Text('IPv4'), trailing: Text(c.ipAddress ?? '—')),\n ListTile(title: const Text('IPv6'), trailing: Text(c.ipv6Address ?? '—')),\n ],\n );\n },\n );\n }\n}"}},"/DNS":{"title":"DNS / DNS 解析","data":{"":"NetworkDiagnostic.resolve() tests DNS resolution across multiple servers in\nparallel, so you can spot the fastest one. Each result is either the system\nresolver or a raw UDP query against an explicit server.NetworkDiagnostic.resolve() 并行测试多台 DNS 服务器的解析表现,从而挑出最快的一台。\n每条结果要么来自系统解析器,要么是对指定服务器的原始 UDP 查询。","basic--基础#Basic / 基础":"final results = await NetworkDiagnostic.resolve(\n domain: 'example.com',\n dnsServers: const ['1.1.1.1', '8.8.8.8', '114.114.114.114'],\n timeout: const Duration(seconds: 5),\n concurrent: true,\n includeSystemResolver: true,\n);\nfor (final r in results) {\n if (r.isSuccess) {\n print('${r.server.padRight(16)} → ${r.resolvedIps.join(\", \")} '\n '(${r.responseTimeMs.toStringAsFixed(1)} ms)');\n } else {\n print('${r.server.padRight(16)} ✗ ${r.errorMessage}');\n }\n}\nParameter\tDefault\tMeaning\tdomain\tconfig.dnsDomain\tDomain to resolve\tdnsServers\tconfig.dnsServers\tServers queried in parallel (or in series)\ttimeout\tconfig.dnsTimeout\tTimeout of one query\tconcurrent\ttrue\tQuery all servers at once\tincludeSystemResolver\tfalse\tAlso add a system row\t\nNotes / 说明:\nA row with server == 'system' comes from the OS resolver; the others are raw\nUDP queries against the listed IPs, encoded by the built-in DnsPacket wire\ncodec.\nserver == 'system' 的行来自系统解析器,其余是对指定 IP 的原始 UDP 查询,由内置\nDnsPacket 编解码。\nincludeSystemResolver defaults to false at the facade level — pass\ntrue to include it.\n门面层默认不包含系统解析器,需显式传 true。","pick-the-fastest--挑出最快的#Pick the fastest / 挑出最快的":"final fastest = results\n .where((r) => r.isSuccess)\n .reduce((a, b) => a.responseTimeMs <= b.responseTimeMs ? a : b);\nprint('fastest resolver: ${fastest.server}');"}},"/FAQ":{"title":"FAQ / 常见问题","data":{"do-i-need-to-call-init--需要调用-init-吗#Do I need to call init()? / 需要调用 init() 吗?":"No. Every API falls back to built-in defaults. Call ZeroNetworkKit.init() only\nwhen you want to override defaults (e.g. a custom reachability host or DNS\nservers). Connectivity alone works with zero setup.不需要。每个 API 都走内置默认值。只有在想覆盖默认参数(如自定义可达性主机或 DNS\n服务器)时才调用 ZeroNetworkKit.init()。单用连通性完全零配置。","which-platforms-are-supported--支持哪些平台#Which platforms are supported? / 支持哪些平台?":"Android, iOS, macOS, Windows, Linux and Web (partial — see\nPlatform Support).支持 Android、iOS、macOS、Windows、Linux 与 Web(部分支持)。详见\nPlatform Support。","why-is-ssid--signalstrength-null-on-desktop--为什么桌面上的-ssid信号强度是-null#Why is ssid / signalStrength null on desktop? / 为什么桌面上的 ssid/信号强度是 null?":"Desktop uses tier A: SSID and RSSI require system APIs that aren't exposed on\nmacOS/Linux/Windows the same way. They are always null on desktop; Windows\nadditionally provides gateway / MAC / DNS / VPN via GetAdaptersAddresses.桌面采用 A 档:SSID 与 RSSI 依赖系统 API,在桌面上不以同样方式暴露,因此恒为 null;\nWindows 额外通过 GetAdaptersAddresses 提供网关 / MAC / DNS / VPN。","why-does-getnativenetworkdetails-return-null--为什么-getnativenetworkdetails-返回-null#Why does getNativeNetworkDetails() return null? / 为什么 getNativeNetworkDetails 返回 null?":"Either the platform has no such data (e.g. desktop tier A), or the required\npermission is missing (e.g. location for Wi-Fi SSID on Android/iOS). The call\nnever throws — it degrades gracefully.要么是平台没有该数据(如桌面 A 档),要么是缺权限(如 Android/iOS 上读取 Wi-Fi SSID\n需定位权限)。该调用绝不抛异常,会优雅降级。","does-the-speed-test-use-my-bandwidth--测速会消耗我的流量吗#Does the speed test use my bandwidth? / 测速会消耗我的流量吗?":"Yes — the default endpoints are Cloudflare's public service and download ≈25 MB\nby default. Ask for consent on metered connections and override downloadUrl /\nuploadUrl for production.会——默认端点指向 Cloudflare 公共服务,默认下载约 25 MB。在按量计费网络上请征得同意,\n生产环境请替换 downloadUrl / uploadUrl。","how-do-i-test-my-integration-without-the-network--如何脱离网络测试我的集成#How do I test my integration without the network? / 如何脱离网络测试我的集成?":"Every service is injectable. Implement ConnectivityAdapter (or pass fake\nservice instances) and call NetworkDiagnostic.configure(...), then\nNetworkDiagnostic.reset() to restore defaults. See\nUsage → Dependency injection.每个服务都可注入。实现 ConnectivityAdapter(或直接传入假服务实例)后调用\nNetworkDiagnostic.configure(...),再用 NetworkDiagnostic.reset() 恢复默认。详见\n用法 → 依赖注入。","how-is-this-licensed--采用什么许可证#How is this licensed? / 采用什么许可证?":"MPL-2.0. See the repository LICENSE.采用 MPL-2.0。详见仓库 LICENSE。"}},"/Full-Report":{"title":"Full Report / 汇总报告","data":{"":"NetworkDiagnostic.diagnose() runs every probe you ask for and aggregates them\ninto one NetworkDiagnosticReport. A failing sub-test never aborts the run — its\nfield simply stays empty/null.NetworkDiagnostic.diagnose() 运行你指定的各项探测,并汇总为一份\nNetworkDiagnosticReport。任何子项失败都不会中断整体流程,对应字段保持空。","basic--基础#Basic / 基础":"final report = await NetworkDiagnostic.diagnose(\n includePing: true,\n includeDns: true,\n includePorts: true,\n includeSpeedTest: true,\n includeUpload: true,\n host: '1.1.1.1',\n dnsDomain: 'example.com',\n dnsServers: const ['1.1.1.1', '8.8.8.8'],\n ports: const [80, 443],\n);\nprint(report); // one-line summary\nprint(report.connection.type.label);\nprint(report.ping?.averageTime);\nprint(report.dnsResults.length);\nprint(report.portResults.where((p) => p.isOpen).length);\nprint(report.speedTest?.downloadSpeed);\nprint(report.quality.level.label);\nParameter\tDefault\tMeaning\tincludePing\ttrue\tSample latency / jitter / loss\tincludeDns\ttrue\tSample DNS latency\tincludePorts\tfalse\tScan ports (off by default)\tincludeSpeedTest\ttrue\tSample download / upload\tincludeUpload\ttrue\tInclude the upload metric\thost\tconfig.pingHost\tLatency / port target\tdnsDomain / dnsServers\tfrom config\tDNS target\tports\tconfig.probePorts\tPorts scanned when includePorts is true\t\nincludePorts defaults to false, so a default run does not scan ports.\nincludePorts 默认 false,默认运行不会扫描端口。\nThe report is JSON-encodable via report.toMap().\n报告可通过 report.toMap() 序列化为 JSON。"}},"/Getting-Started":{"title":"Getting Started / 快速开始","data":{"quick-start--快速开始#Quick Start / 快速开始":"Import the package and start diagnosing — no init() required:导入包即可开始诊断,无需 init():\nimport 'package:flutter/material.dart';\nimport 'package:zero_network_kit/zero_network_kit.dart';\nvoid main() {\n // Optional: apply your own global defaults once.\n // 可选:全局定制一次默认参数。\n ZeroNetworkKit.init(\n config: const NetworkDiagnosticConfig(pingHost: '1.1.1.1'),\n );\n runApp(const MyApp());\n}\nIf you only need connectivity, you don't even need init():如果只需要连通性,连 init() 都不需要:\nfinal connection = await NetworkDiagnostic.checkConnection();\nprint('${connection.type.label} · ${connection.ipAddress}');","what-you-get--你能得到什么#What you get / 你能得到什么":"Every method is a static, non-blocking call on the NetworkDiagnostic facade.\nThe plugin is pure Dart under the hood, so it is fully injectable and testable\nwithout touching the network.每个方法都是 NetworkDiagnostic 门面上的静态、非阻塞调用。插件内核是纯 Dart,\n因此完全可注入、可脱离网络做测试。\nNeed\tCall\tAm I online, on what transport?\tNetworkDiagnostic.checkConnection()\tReact to Wi-Fi ⇄ cellular switches\tNetworkDiagnostic.onConnectivityChanged\tLatency, jitter, packet loss\tNetworkDiagnostic.ping()\tIs DNS slow or broken?\tNetworkDiagnostic.resolve()\tIs host:port reachable?\tNetworkDiagnostic.checkPort() / isPortOpen()\tHow fast is down/up?\tNetworkDiagnostic.runSpeedTest()\tOne number for \"good or bad\"\tNetworkDiagnostic.evaluateQuality()\tEverything at once\tNetworkDiagnostic.diagnose()\tNative version / SSID / gateway / MAC\tZeroNetworkKit.getNativeNetworkDetails()\t\nSee Which API do I need? for the full map.","lifecycle--生命周期#Lifecycle / 生命周期":"ZeroNetworkKit.isInitialized; // false until init() runs\nZeroNetworkKit.config; // the effective NetworkDiagnosticConfig\nawait ZeroNetworkKit.dispose(); // releases the HTTP client the plugin owns\ndispose() only closes the HTTP client the plugin created itself. An\nhttp.Client you injected stays open — close it yourself.dispose() 只会关闭插件自己创建的 HTTP 客户端;你注入的 http.Client 不会被关闭。","next-steps--下一步#Next Steps / 下一步":"Installation — Detailed installation methods / 详细安装方式\nUsage — Global config & dependency injection / 全局配置与依赖注入\nPlatform Support — Capability matrix / 能力矩阵"}},"/Installation":{"title":"Installation / 安装","data":{"from-pubdev-recommended--从-pubdev-安装推荐#From pub.dev (Recommended) / 从 pub.dev 安装(推荐)":"Add the following to your pubspec.yaml:在 pubspec.yaml 中添加以下依赖:\ndependencies:\n zero_network_kit: ^1.0.1\nThen run:然后运行:\nflutter pub get","from-github--从-github-安装#From GitHub / 从 GitHub 安装":"Alternatively, install from GitHub:或者从 GitHub 安装:\ndependencies:\n zero_network_kit:\n git:\n url: https://github.com/zero-labsco/zero_network_kit.git\n ref: release/v1.0.1","platform-setup--平台配置#Platform Setup / 平台配置":"","android#Android":"The plugin manifest already declares INTERNET, ACCESS_NETWORK_STATE and\nACCESS_WIFI_STATE. Reading the Wi-Fi SSID additionally requires the\nlocation permission (ACCESS_FINE_LOCATION) on Android 8.1+, otherwise the\nsnapshot reports ssid: null.插件清单已声明 INTERNET、ACCESS_NETWORK_STATE 与 ACCESS_WIFI_STATE。读取 Wi-Fi\nSSID 还需在 Android 8.1+ 申请定位权限(ACCESS_FINE_LOCATION),否则快照中\nssid 为 null。","ios#iOS":"No additional configuration needed. Reading the Wi-Fi SSID additionally\nrequires the Access WiFi Information capability plus location authorisation.无需额外配置。读取 Wi-Fi SSID 还需开启 Access WiFi Information 能力并授权定位。","macos--windows--linux#macOS / Windows / Linux":"The plugin is declared on all three desktop platforms. On desktop, native\ndetails such as SSID / RSSI are always null (tier A). Windows additionally\nprovides gateway / MAC / DNS / VPN through GetAdaptersAddresses; macOS and\nLinux report only the Dart-side IP/IPv6. See\nPlatform Support for the full matrix.插件已在三个桌面平台声明。桌面上 SSID / 信号强度等原生详情恒为 null(A 档)。\nWindows 额外通过 GetAdaptersAddresses 提供网关 / MAC / DNS / VPN;macOS 与 Linux\n仅提供 Dart 侧的 IP/IPv6。完整矩阵见平台支持。","import--导入#Import / 导入":"import 'package:zero_network_kit/zero_network_kit.dart';","requirements--环境要求#Requirements / 环境要求":"Requirement\tVersion\tFlutter\t>= 3.3.0\tDart SDK\t>= 3.11.0 < 4.0.0","next-steps--下一步#Next Steps / 下一步":"Getting Started — Quick start guide / 快速开始\nUsage — Full usage guide / 完整使用指南"}},"/Ping":{"title":"Latency / Ping / 延迟探测","data":{"":"NetworkDiagnostic.ping() measures round-trip time towards a target host and\nreports sent / received counts, packet loss, min/avg/max and jitter.NetworkDiagnostic.ping() 测量到目标主机的往返时间,并给出发送/接收次数、丢包率、\n最小/平均/最大耗时与抖动。","basic--基础#Basic / 基础":"final ping = await NetworkDiagnostic.ping(\n host: '1.1.1.1',\n count: 5,\n timeout: const Duration(seconds: 2),\n interval: const Duration(milliseconds: 200),\n port: 443,\n);\nprint('received : ${ping.received}/${ping.sent}');\nprint('loss : ${ping.packetLoss.toStringAsFixed(1)} %');\nprint('min/avg/max: ${ping.minTime.toStringAsFixed(1)} / '\n '${ping.averageTime.toStringAsFixed(1)} / '\n '${ping.maxTime.toStringAsFixed(1)} ms');\nprint('jitter : ${ping.jitter.toStringAsFixed(2)} ms');\nprint('samples : ${ping.times}');\nParameter\tDefault\tMeaning\thost\tconfig.pingHost\tTarget host\tcount\tconfig.pingCount\tNumber of probes\ttimeout\tconfig.pingTimeout\tPer-probe timeout\tinterval\tconfig.pingInterval\tDelay between probes\tport\tconfig.pingPort\tTCP port probed in PingMode.tcp\tmode\tPingMode.tcp\tPingMode.tcp or PingMode.icmp","tcp-vs-icmp--tcp-与-icmp#TCP vs ICMP / TCP 与 ICMP":"PingMode.tcp performs a TCP handshake to host:port — the portable equivalent\nof ICMP and the only mode available on Android/iOS.PingMode.tcp 通过 TCP 握手到 host:port 测量往返,是移动端唯一可用的模式。\n// Desktop only — falls back gracefully if the `ping` binary is unavailable.\nawait NetworkDiagnostic.ping(host: '1.1.1.1', count: 4, mode: PingMode.icmp);\nping.isSuccess is true when at least one probe answered; check it before\ntrusting the averages.至少一次成功响应时 isSuccess 为 true,读平均值前建议先判断它。\nA TCP ping needs a listening port. Probing host with port: 443 fails if\nthat host does not accept TCP/443 — that is \"filtered\", not \"offline\". Use\nmode: PingMode.icmp on desktop to get closer to real ICMP.\nTCP 探测需要一个在监听的端口。对不接受 TCP/443 的主机探测 port: 443 会失败——\n那是“被过滤”,不是“离线”。在桌面上用 PingMode.icmp 更接近真实 ICMP。"}},"/Platform-Support":{"title":"Platform Support / 平台支持","data":{"":"zero_network_kit is declared on six plugin platforms: Android, iOS,\nmacOS, Windows, Linux and Web. Web support is partial: the services that\ndepend on dart:io are swapped for browser-safe equivalents, and the\ncapabilities the sandbox forbids degrade gracefully instead of failing.zero_network_kit 在 六 个插件平台上声明:Android、iOS、macOS、Windows、Linux\n与 Web。Web 为部分支持:依赖 dart:io 的服务已替换为浏览器安全的等价实现,\n浏览器沙箱禁止的能力会优雅降级而不会失败。","capability-matrix--能力矩阵#Capability matrix / 能力矩阵":"Capability\tAndroid / iOS\tDesktop (macOS / Windows / Linux)\tWeb\tConnectivity (connectivity_plus)\t✅\t✅\t✅\tLocal IP / IPv6 (NetworkInterface)\t✅\t✅\t❌\tNative details (SSID / gateway / MAC / VPN)\t✅\t⚠️ see below\t❌\tTCP ping\t✅\t✅\t⚠️ HTTPS round trip\tICMP ping (Process.run('ping'))\t❌\t✅\t❌\tHTTP ping\t✅\t✅\t✅\tDNS system resolver\t✅\t✅\t✅ DoH\tDNS raw UDP\t✅\t✅\t⚠️ DoH endpoint required\tPort check / scan\t✅\t✅\t❌\tSpeed test\t✅\t✅\t✅\tQuality score\t✅\t✅\t✅\tBenchmarks\t✅\t✅\t✅","networkcapabilities--能力查询#NetworkCapabilities / 能力查询":"Query the host platform before calling, so your UI can hide unsupported cards:在调用前查询当前平台能力,UI 即可据此隐藏不支持的卡片:\nfinal caps = NetworkDiagnostic.capabilities;\nprint(caps.platform); // 'android' | 'ios' | 'macos' | 'windows' | 'linux' | 'web'\nprint(caps.supports(NetworkCapability.nativeDetails)); // mobile: true, desktop: false\nprint(caps.supports(NetworkCapability.icmpPing)); // desktop: true, mobile: false\nRules baked into NetworkCapabilities.current():\nnativeDetails is mobile-only (SSID / gateway / MAC / VPN need system APIs).\nicmpPing is desktop-only (uses the system ping binary).\nOn web the supported set narrows to connectivity, tcpPing,\ndnsSystem, speedTest, quality and benchmark; every other capability is\nabsent.\nNetworkCapabilities.current() 内置规则:\nnativeDetails 仅移动端(SSID / 网关 / MAC / VPN 需要系统 API)。\nicmpPing 仅桌面(使用系统 ping 命令)。\nWeb 上的支持集合收缩为 connectivity、tcpPing、dnsSystem、speedTest、\nquality 与 benchmark,其余能力均不存在。","native-details-on-desktop--桌面原生详情#Native details on desktop / 桌面原生详情":"Desktop uses tier A by default: the native layer only reports the platform\nversion and an (often empty) details map. IP/IPv6 come from Dart\nNetworkInterface. As a result:桌面默认采用 A 档:原生层只报告平台版本与(通常为空的)详情 map,IP/IPv6 由 Dart\nNetworkInterface 兜底。因此:\nSSID / signal strength are always null on desktop.\n桌面上的 SSID / 信号强度恒为 null。\ngateway / macAddress / isVpn are null on macOS and Linux.\nmacOS 与 Linux 上 gateway / macAddress / isVpn 为 null。\nWindows additionally implements GetAdaptersAddresses, so it reports\ngateway / macAddress / DNS / isVpn (SSID still null). This is a bonus\ntier-B fragment kept as-is.\nWindows 额外实现了 GetAdaptersAddresses,因此上报 gateway / macAddress /\nDNS / isVpn(SSID 仍为 null)。这是保留的 B 档赠品。\nWhatever the platform, a missing permission or an unreachable native call never\nthrows — the field simply stays null and the rest of the result still arrives.无论在哪个平台,缺权限或原生调用不可达都不会抛异常——对应字段保持 null,其余\n结果照常返回。","web-support--web-支持#Web support / Web 支持":"The web build exposes the same static API. Capabilities that the browser sandbox\nforbids degrade gracefully — they return null or an \"unavailable\" result\ninstead of throwing:\nCapability\tWeb\tNotes\tConnectivity\t✅\tvia connectivity_plus\tPing (PingMode.tcp)\t⚠️\tmeasured as an HTTPS round trip; the target must send CORS headers\tPing (PingMode.icmp)\t❌\tthrows UnsupportedError\tDNS (system resolver)\t✅\tvia DNS-over-HTTPS\tDNS (explicit server)\t⚠️\tneeds a DoH endpoint, otherwise \"unsupported\"\tSpeed test\t✅\tHTTP download / upload\tQuality score\t✅\tpure function\tBenchmarks\t✅\tpure function\tPort check / scan\t❌\treturns \"unavailable\" results\tNative details (SSID, gateway, MAC, VPN)\t❌\tnull\t\nBrowsers expose no VPN API, so isVpn stays false on the web even when a\nsystem VPN or a local HTTP proxy is active.Web 构建提供同样的静态 API;浏览器沙箱禁止的能力会优雅降级(返回 null 或\"不可用\"\n结果,而不是抛异常):\n能力\tWeb\t说明\t连通性检测\t✅\t通过 connectivity_plus\tPing(PingMode.tcp)\t⚠️\t以 HTTPS 往返耗时度量,目标主机需下发 CORS 头\tPing(PingMode.icmp)\t❌\t抛出 UnsupportedError\tDNS(系统解析器)\t✅\t通过 DNS-over-HTTPS\tDNS(指定服务器)\t⚠️\t需要 DoH 端点,否则返回\"不支持\"\t带宽测速\t✅\tHTTP 下载 / 上传\t质量评分\t✅\t纯函数\t基准测试\t✅\t纯函数\t端口检测 / 扫描\t❌\t返回\"不可用\"结果\t原生详情(SSID、网关、MAC、VPN)\t❌\t返回 null\t\n浏览器不暴露 VPN 接口,因此即使系统开启了 VPN 或本地 HTTP 代理,Web 上的\nisVpn 仍为 false。","reading-native-data--读取原生数据#Reading native data / 读取原生数据":"final version = await ZeroNetworkKit.getPlatformVersion();\nprint(version); // e.g. 'Android 14' / 'iOS 18.0' / 'Web'\nfinal details = await ZeroNetworkKit.getNativeNetworkDetails();\nif (details != null) {\n print(details); // SSID, BSSID, gateway, MAC, VPN flag, RSSI …\n}\ndetails is always null on the web, and usually null on desktop too (see\nabove).Web 上 details 恒为 null,桌面端通常也为 null(见上文)。"}},"/Ports":{"title":"Ports / 端口检测","data":{"":"checkPort() returns a full PortCheckResult for one port; isPortOpen() is the\nplain boolean convenience; scanPorts() runs many ports concurrently with\nbounded in-flight connections.checkPort() 返回单个端口的完整 PortCheckResult;isPortOpen() 是便捷的布尔版;\nscanPorts() 以有界并发批量扫描多个端口。","single-port--单端口#Single port / 单端口":"// Boolean convenience / 便捷布尔版\nfinal open = await NetworkDiagnostic.isPortOpen(\n host: 'example.com',\n port: 443,\n timeout: const Duration(seconds: 3),\n);\nprint(open ? 'HTTPS reachable' : 'HTTPS unreachable');\n// Full result with RTT and error message / 含 RTT 与错误信息的完整结果\nfinal result = await NetworkDiagnostic.checkPort(host: 'example.com', port: 443);\nprint('open=${result.isOpen} rtt=${result.responseTimeMs} ms '\n 'err=${result.errorMessage}');","bulk-scan--批量扫描#Bulk scan / 批量扫描":"final scan = await NetworkDiagnostic.scanPorts(\n host: 'example.com',\n ports: const [22, 80, 443, 8080, 8443],\n concurrency: 8,\n);\nfor (final r in scan) {\n print('${r.host}:${r.port} '\n '${r.isOpen ? \"open\" : \"closed\"} '\n '${r.responseTimeMs.toStringAsFixed(1)} ms '\n '${r.errorMessage ?? \"\"}');\n}\nParameter\tDefault\tMeaning\tports (scanPorts)\tconfig.probePorts ([80, 443])\tPorts to probe\tconcurrency\t12\tMax in-flight connections\ttimeout\tconfig.portCheckTimeout\tTimeout per port\t\ncheckPort() returns a PortCheckResult (with isOpen, responseTimeMs\nand errorMessage); use isPortOpen() for a plain boolean. When you need the\nround-trip time or the failure reason for a single port, call checkPort()\ndirectly or pass a one-element list to scanPorts():\nscanPorts(host: 'example.com', ports: [443]).first.\ncheckPort() 返回 PortCheckResult(含 isOpen、responseTimeMs、\nerrorMessage);单端口布尔诉求请用 isPortOpen()。需要 RTT 或失败原因时可直接\n调用 checkPort(),或给 scanPorts(..., ports: [443]) 取单条结果。"}},"/Quality":{"title":"Quality Score / 质量评分","data":{"":"NetworkDiagnostic.evaluateQuality() returns a weighted 0–100 score plus a\nlevel and human-readable suggestions, computed over whatever metrics are\navailable.NetworkDiagnostic.evaluateQuality() 返回一个加权 0–100 分,附带等级与可读建议,\n它基于当前可用的各项指标计算得出。","basic--基础#Basic / 基础":"final quality = await NetworkDiagnostic.evaluateQuality(\n includePing: true,\n includeDns: true,\n includeSpeedTest: true,\n includeUpload: true,\n);\nprint('${quality.score.toStringAsFixed(1)}/100 — ${quality.level.label}');\nquality.metrics.forEach((metric, value) {\n print(' $metric = ${value.toStringAsFixed(2)}');\n});\nfor (final suggestion in quality.suggestions) {\n print('• $suggestion');\n}\nParameter\tDefault\tMeaning\tincludePing\ttrue\tSample latency / jitter / loss\tincludeDns\ttrue\tSample DNS latency\tincludeSpeedTest\ttrue\tSample download / upload (heavy)\tincludeUpload\ttrue\tInclude the upload metric\tpingHost / pingCount\tfrom config\tLatency target\tdnsDomain / dnsServers\tfrom config\tDNS target\tdownloadUrl / uploadUrl\tfrom config\tBandwidth endpoints","lightweight-variant--轻量变体#Lightweight variant / 轻量变体":"final quality = await NetworkDiagnostic.evaluateQuality(includeSpeedTest: false);","level-thresholds--等级阈值#Level thresholds / 等级阈值":"≥90 excellent · ≥75 good · ≥60 fair · ≥40 poor · otherwise bad\n(NetworkQualityLevel.fromScore).≥90 极佳 · ≥75 良好 · ≥60 一般 · ≥40 较差 · 其余为极差。","weights--权重#Weights / 权重":"Metric\tWeight\tSource\tlatency\t0.25\tPingResult.averageTime\tjitter\t0.10\tPingResult.jitter\tpacketLoss\t0.15\tPingResult.packetLoss\tdownload\t0.25\tSpeedTestResult.downloadSpeed\tupload\t0.15\tSpeedTestResult.uploadSpeed\tdns\t0.10\tmean of successful DnsTestResult.responseTimeMs\tsignalStrength\t0.10\tNetworkConnectionInfo.signalStrength","pure-function--纯函数#Pure function / 纯函数":"If you already have the metrics, skip the network entirely:如果你已有指标,可完全跳过网络:\nfinal score = NetworkQualityEvaluator.evaluate(\n latency: 42, jitter: 6, packetLoss: 0,\n download: 88.4, upload: 12.1, dns: 25, signalStrength: -55,\n targets: const QualityTargets(),\n);\nprint('${score.score.toStringAsFixed(1)} → ${score.level.label}');\nTune the ideal values globally through NetworkDiagnosticConfig(qualityTargets: ...).\n调整理想值请通过 NetworkDiagnosticConfig(qualityTargets: ...) 全局设置。"}},"/Speed-Test":{"title":"Speed Test / 测速","data":{"":"NetworkDiagnostic.runSpeedTest() measures download and upload throughput and\nsamples latency during the run, reporting progress through onProgress.NetworkDiagnostic.runSpeedTest() 测量下载与上传吞吐量,并在过程中采样延迟,通过\nonProgress 汇报进度。","basic--基础#Basic / 基础":"final speed = await NetworkDiagnostic.runSpeedTest(\n includeUpload: true,\n includePing: true,\n onProgress: (progress) {\n print('${progress.phase.name}: '\n '${progress.speedMbps.toStringAsFixed(1)} Mbps '\n '(${progress.bytes} bytes, ${progress.elapsed.inMilliseconds} ms)');\n },\n);\nprint('download : ${speed.downloadSpeed.toStringAsFixed(2)} Mbps');\nprint('upload : ${speed.uploadSpeed.toStringAsFixed(2)} Mbps');\nprint('ping : ${speed.ping.toStringAsFixed(1)} ms');\nprint('jitter : ${speed.jitter.toStringAsFixed(2)} ms');\nprint('loss : ${speed.packetLoss.toStringAsFixed(1)} %');\nprint('server : ${speed.server}');\nprint('duration : ${speed.duration.inMilliseconds} ms');\nParameter\tDefault\tMeaning\tdownloadUrl / uploadUrl\tfrom config\tEndpoints used\ttimeout\tconfig.speedTestTimeout\tPer-request timeout\tmaxDuration\tconfig.speedTestMaxDuration\tSampling window per phase\tuploadPayloadBytes\tconfig.uploadPayloadBytes\tUpload size\tpingHost / pingCount\tfrom config\tLatency sampled during the test\tincludeUpload\ttrue\tSkip the upload phase\tincludePing\ttrue\tSkip the latency sample\tonProgress\tnull\tCalled repeatedly during both phases\t\nProgress phases: SpeedTestPhase.download → SpeedTestPhase.upload →\nSpeedTestPhase.completed.进度阶段依次为 download → upload → completed。","fast-low-traffic-variant--轻量低流量变体#Fast, low-traffic variant / 轻量低流量变体":"final quick = await NetworkDiagnostic.runSpeedTest(\n includeUpload: false,\n includePing: false,\n maxDuration: const Duration(seconds: 5),\n);\nThe default endpoints point at Cloudflare's public speed service and move real\ntraffic (≈25 MB download by default). Ask for consent before running it on a\nmetered connection, and override downloadUrl / uploadUrl for production.\n默认端点指向 Cloudflare 公共服务并会产生真实流量(默认下载约 25 MB)。在按量计费\n网络上运行前请征得同意,并为生产环境替换 downloadUrl / uploadUrl。"}},"/Usage":{"title":"Usage / 用法","data":{"which-api-do-i-need--该用哪个-api#Which API do I need? / 该用哪个 API?":"I want to know…\tCall\tAm I online, and over what transport?\tNetworkDiagnostic.checkConnection()\tReact to Wi-Fi ⇄ cellular switches\tNetworkDiagnostic.onConnectivityChanged\tLatency, jitter, packet loss\tNetworkDiagnostic.ping()\tIs DNS slow or broken?\tNetworkDiagnostic.resolve()\tIs host:port reachable?\tNetworkDiagnostic.checkPort()\tWhich of these ports are open?\tNetworkDiagnostic.scanPorts()\tHow fast is down/up?\tNetworkDiagnostic.runSpeedTest()\tOne number for “good or bad”\tNetworkDiagnostic.evaluateQuality()\tEverything at once, as a report\tNetworkDiagnostic.diagnose()\tIs the diagnostics API itself expensive?\tNetworkBenchmark.runAll()\tNative version / SSID / gateway / MAC\tZeroNetworkKit.getPlatformVersion(), getNativeNetworkDetails()","global-configuration--全局配置#Global configuration / 全局配置":"NetworkDiagnosticConfig centralises every default. Override only what you\nneed; the rest keep the defaults below.NetworkDiagnosticConfig 集中了全部默认参数,只需覆盖你关心的字段。\nZeroNetworkKit.init(\n config: const NetworkDiagnosticConfig(\n pingHost: '1.1.1.1',\n pingPort: 443,\n pingCount: 5,\n dnsDomain: 'example.com',\n dnsServers: ['1.1.1.1', '8.8.8.8'],\n downloadUrl: 'https://my-cdn.example.com/speedtest.bin',\n uploadUrl: 'https://my-cdn.example.com/upload',\n ),\n);\nField\tDefault\tMeaning\tpingHost\t'1.1.1.1'\tDefault ping / port-scan target\tpingPort\t443\tPort used by the TCP ping\tpingCount\t4\tProbes per ping run\tpingTimeout\t3s\tTimeout of one probe\tpingInterval\t200ms\tDelay between probes\tdnsDomain\t'www.google.com'\tDefault domain for DNS tests\tdnsServers\t['1.1.1.1', '8.8.8.8', '114.114.114.114']\tServers queried by default\tdnsTimeout\t5s\tTimeout per DNS server\tdownloadUrl\tCloudflare __down?bytes=25000000\tDownload endpoint\tuploadUrl\tCloudflare __up\tUpload endpoint\tuploadPayloadBytes\t1048576 (1 MiB)\tUpload payload size\tspeedTestTimeout\t30s\tPer-request timeout\tspeedTestMaxDuration\t10s\tSampling window per phase\tportCheckTimeout\t3s\tTimeout of one port check\tprobePorts\t[80, 443]\tPorts used by scanPorts() by default\tqualityTargets\tconst QualityTargets()\tIdeal values for scoring\t\nThe default speed-test endpoints are Cloudflare's public service. Swap them for\nyour own before shipping production traffic.\n默认测速端点是 Cloudflare 的公共服务,正式项目请替换为自建端点。","quality-targets--质量评分理想值#Quality targets / 质量评分理想值":"const NetworkDiagnosticConfig(\n qualityTargets: QualityTargets(\n excellentLatency: 30, // ms\n acceptableLatency: 150, // ms\n excellentJitter: 5, // ms\n acceptableJitter: 40, // ms\n acceptablePacketLoss: 5, // %\n excellentDownload: 50, // Mbps\n acceptableDownload: 5, // Mbps\n excellentUpload: 20, // Mbps\n acceptableUpload: 2, // Mbps\n excellentDns: 30, // ms\n acceptableDns: 200, // ms\n ),\n);","json-serialisation--序列化#JSON serialisation / 序列化":"Every result object implements toMap() and is JSON encodable:每个结果对象都实现了 toMap(),可直接 JSON 序列化:\nimport 'dart:convert';\nfinal report = await NetworkDiagnostic.diagnose(includeSpeedTest: false);\nfinal json = jsonEncode(report.toMap());\nprint(json);\n// Round-trip a connection snapshot.\nfinal decoded = NetworkConnectionInfo.fromMap(jsonDecode(jsonEncode(\n report.connection.toMap(),\n)) as Map);\nType\tSerialisation\tNetworkConnectionInfo\ttoMap() + fromMap()\tPingResult\ttoMap()\tDnsTestResult\ttoMap()\tPortCheckResult\ttoMap()\tSpeedTestResult\ttoMap()\tNetworkQualityScore\ttoMap()\tNetworkDiagnosticReport\ttoMap()\tBenchmarkResult / BenchmarkSuiteResult\ttoMap()","dependency-injection--tests--注入与测试#Dependency injection & tests / 注入与测试":"Every service accepts its collaborators, so your integration points are\nunit-testable without touching the network.每个服务都支持注入协作对象,可以完全脱离网络做单测。\nclass FakeConnectivityAdapter implements ConnectivityAdapter {\n @override\n Future> checkConnectivity() async => ['wifi'];\n @override\n Stream> get onConnectivityChanged => const Stream.empty();\n}\nNetworkDiagnostic.configure(\n config: const NetworkDiagnosticConfig(pingHost: '127.0.0.1'),\n connectivity: ConnectivityService(adapter: FakeConnectivityAdapter()),\n ping: PingService(),\n dns: DnsService(),\n ports: PortService(),\n speedTest: SpeedTestService(client: fakeClient),\n);\n// Restore defaults afterwards.\nNetworkDiagnostic.reset();\nSwap individual services directly when you prefer:也可以直接替换单个服务:\nNetworkDiagnostic.pingService = MyFakePingService();\nNetworkDiagnostic.dnsService = MyFakeDnsService();\nFor advanced service classes, the DNS wire codec and low-level APIs, import\npackage:zero_network_kit/advanced.dart.\n进阶的服务类、DNS 报文编解码器等底层 API 请通过\npackage:zero_network_kit/advanced.dart 引入。"}},"/":{"title":"Zero Network Kit","data":{"":"A Flutter plugin for network diagnostics: connectivity inspection, latency\nprobing, DNS resolution, port checks, bandwidth measurement, quality scoring and\nmicro-benchmarks — on Android, iOS, macOS, Windows and Linux.一个 Flutter 插件,提供网络诊断能力:连通性检测、延迟探测、DNS 解析、端口\n检测、带宽测速、质量评分与微基准测试——覆盖 Android、iOS、macOS、Windows 与 Linux。","-features--功能特性#✨ Features / 功能特性":"Feature\tDescription\tZero setup\tWorks out of the box; init() only to override defaults / 开箱即用,仅需在想覆盖默认值时才 init()\tConnectivity\tTransport type, IPv4/IPv6, gateway, SSID, RSSI, MAC, VPN / 传输类型、IPv4/IPv6、网关、SSID、信号强度、MAC、VPN\tLatency\tTCP handshake RTT everywhere; system ICMP on desktop / TCP 握手 RTT 全平台可用,桌面额外支持系统 ICMP\tDNS\tSystem resolver + raw UDP against explicit servers / 系统解析器 + 针对指定服务器的原始 UDP 查询\tPorts\tBounded-concurrency TCP reachability / 有界并发的 TCP 可达性检测\tSpeed test\tDownload/upload throughput with progress callbacks / 上下行测速,带进度回调\tQuality\tWeighted 0–100 score + level + suggestions / 加权 0–100 分 + 等级 + 建议\tFull report\tOne-shot aggregate of every probe / 一次性汇总所有探测\tBenchmarks\tMeasures how fast the diagnostics API itself runs / 衡量诊断 API 自身开销\tCapabilities\tQuery-then-call; hide unsupported cards (e.g. SSID on desktop) / 先查询后调用,隐藏不支持的卡片\tGraceful degradation\tMissing permission or unreachable sub-service never throws / 缺权限或子服务不可达时只返回 null,绝不抛异常\tHermetic tests\tEvery service accepts injected collaborators / 每个服务都支持注入协作对象,便于单测","-table-of-contents--目录#📚 Table of Contents / 目录":"Page\tDescription\tGetting Started\tQuick start guide / 快速开始\tInstallation\tHow to install / 安装方式\tUsage\tGlobal config, serialisation, dependency injection / 全局配置、序列化、依赖注入\tConnectivity\tConnection snapshot & change stream / 连通性快照与变化监听\tLatency / Ping\tTCP & ICMP latency probing / 延迟探测\tDNS\tResolver comparison across servers / DNS 解析\tPorts\tSingle port & bulk scan / 端口检测\tSpeed Test\tDownload/upload throughput / 测速\tQuality Score\tWeighted scoring / 质量评分\tFull Report\tOne-shot aggregate / 汇总报告\tBenchmarks\tMicro-benchmarks / 微基准\tPlatform Support\tCapability matrix & native details / 能力矩阵与原生详情\tAPI Reference\tModel field reference & gotchas / 模型字段速查与陷阱\tFAQ\tFrequently asked questions / 常见问题","-links--链接#🔗 Links / 链接":"GitHub\nOfficial Website\npub.dev","-license--许可证#📄 License / 许可证":"This project is licensed under the MPL-2.0.本项目采用 MPL-2.0 许可证。This plugin is provided \"as is\", without warranty of any kind. The author assumes\nno responsibility or liability for the functionality, security, or any\nconsequences arising from the use of modified versions or derivative projects.本插件按\"原样\"提供,不提供任何担保。作者不对修改版或衍生项目的功能、安全性及\n任何使用后果承担责任。"}}} \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/FAQ-bccbbb52a0b53bb8.js b/docs/_next/static/chunks/pages/FAQ-bccbbb52a0b53bb8.js new file mode 100644 index 0000000..1eceb4a --- /dev/null +++ b/docs/_next/static/chunks/pages/FAQ-bccbbb52a0b53bb8.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[210],{9238:function(e,t,n){(window.__NEXT_P=window.__NEXT_P||[]).push(["/FAQ",function(){return n(5797)}])},5797:function(e,t,n){"use strict";n.r(t),n.d(t,{useTOC:function(){return d}});var i=n(5893),r=n(7812),o=n(7080),s=n(8925);function d(e){let t={code:"code",...(0,s.a)()};return[{value:(0,i.jsxs)(i.Fragment,{children:["Do I need to call ",(0,i.jsx)(t.code,{children:"init()"}),"? / 需要调用 ",(0,i.jsx)(t.code,{children:"init()"})," 吗?"]}),id:"do-i-need-to-call-init--需要调用-init-吗",depth:3},{value:"Which platforms are supported? / 支持哪些平台?",id:"which-platforms-are-supported--支持哪些平台",depth:3},{value:(0,i.jsxs)(i.Fragment,{children:["Why is ",(0,i.jsx)(t.code,{children:"ssid"})," / ",(0,i.jsx)(t.code,{children:"signalStrength"})," ",(0,i.jsx)(t.code,{children:"null"})," on desktop? / 为什么桌面上的 ssid/信号强度是 null?"]}),id:"why-is-ssid--signalstrength-null-on-desktop--为什么桌面上的-ssid信号强度是-null",depth:3},{value:(0,i.jsxs)(i.Fragment,{children:["Why does ",(0,i.jsx)(t.code,{children:"getNativeNetworkDetails()"})," return ",(0,i.jsx)(t.code,{children:"null"}),"? / 为什么 getNativeNetworkDetails 返回 null?"]}),id:"why-does-getnativenetworkdetails-return-null--为什么-getnativenetworkdetails-返回-null",depth:3},{value:"Does the speed test use my bandwidth? / 测速会消耗我的流量吗?",id:"does-the-speed-test-use-my-bandwidth--测速会消耗我的流量吗",depth:3},{value:"How do I test my integration without the network? / 如何脱离网络测试我的集成?",id:"how-do-i-test-my-integration-without-the-network--如何脱离网络测试我的集成",depth:3},{value:"How is this licensed? / 采用什么许可证?",id:"how-is-this-licensed--采用什么许可证",depth:3}]}t.default=(0,r.c)(function(e){let{toc:t=d(e)}=e,n={a:"a",code:"code",h1:"h1",h3:"h3",p:"p",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{children:"FAQ / 常见问题"}),"\n",(0,i.jsx)(n.h3,{id:t[0].id,children:t[0].value}),"\n",(0,i.jsxs)(n.p,{children:["No. Every API falls back to built-in defaults. Call ",(0,i.jsx)(n.code,{children:"ZeroNetworkKit.init()"})," only\nwhen you want to override defaults (e.g. a custom reachability host or DNS\nservers). Connectivity alone works with zero setup."]}),"\n",(0,i.jsxs)(n.p,{children:["不需要。每个 API 都走内置默认值。只有在想覆盖默认参数(如自定义可达性主机或 DNS\n服务器)时才调用 ",(0,i.jsx)(n.code,{children:"ZeroNetworkKit.init()"}),"。单用连通性完全零配置。"]}),"\n",(0,i.jsx)(n.h3,{id:t[1].id,children:t[1].value}),"\n",(0,i.jsxs)(n.p,{children:["Android, iOS, macOS, Windows, Linux and Web (partial — see\n",(0,i.jsx)(n.a,{href:"Platform-Support",children:"Platform Support"}),")."]}),"\n",(0,i.jsxs)(n.p,{children:["支持 Android、iOS、macOS、Windows、Linux 与 Web(部分支持)。详见\n",(0,i.jsx)(n.a,{href:"Platform-Support",children:"Platform Support"}),"。"]}),"\n",(0,i.jsx)(n.h3,{id:t[2].id,children:t[2].value}),"\n",(0,i.jsxs)(n.p,{children:["Desktop uses tier A: SSID and RSSI require system APIs that aren’t exposed on\nmacOS/Linux/Windows the same way. They are always ",(0,i.jsx)(n.code,{children:"null"})," on desktop; Windows\nadditionally provides gateway / MAC / DNS / VPN via ",(0,i.jsx)(n.code,{children:"GetAdaptersAddresses"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["桌面采用 A 档:SSID 与 RSSI 依赖系统 API,在桌面上不以同样方式暴露,因此恒为 ",(0,i.jsx)(n.code,{children:"null"}),";\nWindows 额外通过 ",(0,i.jsx)(n.code,{children:"GetAdaptersAddresses"})," 提供网关 / MAC / DNS / VPN。"]}),"\n",(0,i.jsx)(n.h3,{id:t[3].id,children:t[3].value}),"\n",(0,i.jsx)(n.p,{children:"Either the platform has no such data (e.g. desktop tier A), or the required\npermission is missing (e.g. location for Wi-Fi SSID on Android/iOS). The call\nnever throws — it degrades gracefully."}),"\n",(0,i.jsx)(n.p,{children:"要么是平台没有该数据(如桌面 A 档),要么是缺权限(如 Android/iOS 上读取 Wi-Fi SSID\n需定位权限)。该调用绝不抛异常,会优雅降级。"}),"\n",(0,i.jsx)(n.h3,{id:t[4].id,children:t[4].value}),"\n",(0,i.jsxs)(n.p,{children:["Yes — the default endpoints are Cloudflare’s public service and download ≈25 MB\nby default. Ask for consent on metered connections and override ",(0,i.jsx)(n.code,{children:"downloadUrl"})," /\n",(0,i.jsx)(n.code,{children:"uploadUrl"})," for production."]}),"\n",(0,i.jsxs)(n.p,{children:["会——默认端点指向 Cloudflare 公共服务,默认下载约 25 MB。在按量计费网络上请征得同意,\n生产环境请替换 ",(0,i.jsx)(n.code,{children:"downloadUrl"})," / ",(0,i.jsx)(n.code,{children:"uploadUrl"}),"。"]}),"\n",(0,i.jsx)(n.h3,{id:t[5].id,children:t[5].value}),"\n",(0,i.jsxs)(n.p,{children:["Every service is injectable. Implement ",(0,i.jsx)(n.code,{children:"ConnectivityAdapter"})," (or pass fake\nservice instances) and call ",(0,i.jsx)(n.code,{children:"NetworkDiagnostic.configure(...)"}),", then\n",(0,i.jsx)(n.code,{children:"NetworkDiagnostic.reset()"})," to restore defaults. See\n",(0,i.jsx)(n.a,{href:"Usage#dependency-injection--tests",children:"Usage → Dependency injection"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["每个服务都可注入。实现 ",(0,i.jsx)(n.code,{children:"ConnectivityAdapter"}),"(或直接传入假服务实例)后调用\n",(0,i.jsx)(n.code,{children:"NetworkDiagnostic.configure(...)"}),",再用 ",(0,i.jsx)(n.code,{children:"NetworkDiagnostic.reset()"})," 恢复默认。详见\n",(0,i.jsx)(n.a,{href:"Usage#dependency-injection--tests",children:"用法 → 依赖注入"}),"。"]}),"\n",(0,i.jsx)(n.h3,{id:t[6].id,children:t[6].value}),"\n",(0,i.jsxs)(n.p,{children:["MPL-2.0. See the repository ",(0,i.jsx)(n.a,{href:"https://github.com/zero-labsco/zero_network_kit/blob/main/LICENSE",children:"LICENSE"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["采用 MPL-2.0。详见仓库 ",(0,i.jsx)(n.a,{href:"https://github.com/zero-labsco/zero_network_kit/blob/main/LICENSE",children:"LICENSE"}),"。"]})]})},"/FAQ",{filePath:"pages/FAQ.md",timestamp:1789334081e3,pageMap:o.v,frontMatter:{},title:"FAQ / 常见问题"},"undefined"==typeof RemoteContent?d:RemoteContent.useTOC)},7080:function(e,t,n){"use strict";n.d(t,{v:function(){return i}});let i=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=9238)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/FAQ-c14e0ebd2147b3f8.js b/docs/_next/static/chunks/pages/FAQ-c14e0ebd2147b3f8.js deleted file mode 100644 index 528a020..0000000 --- a/docs/_next/static/chunks/pages/FAQ-c14e0ebd2147b3f8.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[210],{9238:function(e,t,n){(window.__NEXT_P=window.__NEXT_P||[]).push(["/FAQ",function(){return n(5797)}])},5797:function(e,t,n){"use strict";n.r(t),n.d(t,{useTOC:function(){return d}});var i=n(5893),r=n(7812),o=n(7080),s=n(8925);function d(e){let t={code:"code",...(0,s.a)()};return[{value:(0,i.jsxs)(i.Fragment,{children:["Do I need to call ",(0,i.jsx)(t.code,{children:"init()"}),"? / 需要调用 ",(0,i.jsx)(t.code,{children:"init()"})," 吗?"]}),id:"do-i-need-to-call-init--需要调用-init-吗",depth:3},{value:"Which platforms are supported? / 支持哪些平台?",id:"which-platforms-are-supported--支持哪些平台",depth:3},{value:(0,i.jsxs)(i.Fragment,{children:["Why is ",(0,i.jsx)(t.code,{children:"ssid"})," / ",(0,i.jsx)(t.code,{children:"signalStrength"})," ",(0,i.jsx)(t.code,{children:"null"})," on desktop? / 为什么桌面上的 ssid/信号强度是 null?"]}),id:"why-is-ssid--signalstrength-null-on-desktop--为什么桌面上的-ssid信号强度是-null",depth:3},{value:(0,i.jsxs)(i.Fragment,{children:["Why does ",(0,i.jsx)(t.code,{children:"getNativeNetworkDetails()"})," return ",(0,i.jsx)(t.code,{children:"null"}),"? / 为什么 getNativeNetworkDetails 返回 null?"]}),id:"why-does-getnativenetworkdetails-return-null--为什么-getnativenetworkdetails-返回-null",depth:3},{value:"Does the speed test use my bandwidth? / 测速会消耗我的流量吗?",id:"does-the-speed-test-use-my-bandwidth--测速会消耗我的流量吗",depth:3},{value:"How do I test my integration without the network? / 如何脱离网络测试我的集成?",id:"how-do-i-test-my-integration-without-the-network--如何脱离网络测试我的集成",depth:3},{value:"How is this licensed? / 采用什么许可证?",id:"how-is-this-licensed--采用什么许可证",depth:3}]}t.default=(0,r.c)(function(e){let{toc:t=d(e)}=e,n={a:"a",code:"code",h1:"h1",h3:"h3",p:"p",strong:"strong",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{children:"FAQ / 常见问题"}),"\n",(0,i.jsx)(n.h3,{id:t[0].id,children:t[0].value}),"\n",(0,i.jsxs)(n.p,{children:["No. Every API falls back to built-in defaults. Call ",(0,i.jsx)(n.code,{children:"ZeroNetworkKit.init()"})," only\nwhen you want to override defaults (e.g. a custom reachability host or DNS\nservers). Connectivity alone works with zero setup."]}),"\n",(0,i.jsxs)(n.p,{children:["不需要。每个 API 都走内置默认值。只有在想覆盖默认参数(如自定义可达性主机或 DNS\n服务器)时才调用 ",(0,i.jsx)(n.code,{children:"ZeroNetworkKit.init()"}),"。单用连通性完全零配置。"]}),"\n",(0,i.jsx)(n.h3,{id:t[1].id,children:t[1].value}),"\n",(0,i.jsxs)(n.p,{children:["Android, iOS, macOS, Windows and Linux. Web is ",(0,i.jsx)(n.strong,{children:"not"})," supported."]}),"\n",(0,i.jsxs)(n.p,{children:["支持 Android、iOS、macOS、Windows 与 Linux。Web ",(0,i.jsx)(n.strong,{children:"不支持"}),"。详见\n",(0,i.jsx)(n.a,{href:"Platform-Support",children:"Platform Support"}),"。"]}),"\n",(0,i.jsx)(n.h3,{id:t[2].id,children:t[2].value}),"\n",(0,i.jsxs)(n.p,{children:["Desktop uses tier A: SSID and RSSI require system APIs that aren’t exposed on\nmacOS/Linux/Windows the same way. They are always ",(0,i.jsx)(n.code,{children:"null"})," on desktop; Windows\nadditionally provides gateway / MAC / DNS / VPN via ",(0,i.jsx)(n.code,{children:"GetAdaptersAddresses"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["桌面采用 A 档:SSID 与 RSSI 依赖系统 API,在桌面上不以同样方式暴露,因此恒为 ",(0,i.jsx)(n.code,{children:"null"}),";\nWindows 额外通过 ",(0,i.jsx)(n.code,{children:"GetAdaptersAddresses"})," 提供网关 / MAC / DNS / VPN。"]}),"\n",(0,i.jsx)(n.h3,{id:t[3].id,children:t[3].value}),"\n",(0,i.jsx)(n.p,{children:"Either the platform has no such data (e.g. desktop tier A), or the required\npermission is missing (e.g. location for Wi-Fi SSID on Android/iOS). The call\nnever throws — it degrades gracefully."}),"\n",(0,i.jsx)(n.p,{children:"要么是平台没有该数据(如桌面 A 档),要么是缺权限(如 Android/iOS 上读取 Wi-Fi SSID\n需定位权限)。该调用绝不抛异常,会优雅降级。"}),"\n",(0,i.jsx)(n.h3,{id:t[4].id,children:t[4].value}),"\n",(0,i.jsxs)(n.p,{children:["Yes — the default endpoints are Cloudflare’s public service and download ≈25 MB\nby default. Ask for consent on metered connections and override ",(0,i.jsx)(n.code,{children:"downloadUrl"})," /\n",(0,i.jsx)(n.code,{children:"uploadUrl"})," for production."]}),"\n",(0,i.jsxs)(n.p,{children:["会——默认端点指向 Cloudflare 公共服务,默认下载约 25 MB。在按量计费网络上请征得同意,\n生产环境请替换 ",(0,i.jsx)(n.code,{children:"downloadUrl"})," / ",(0,i.jsx)(n.code,{children:"uploadUrl"}),"。"]}),"\n",(0,i.jsx)(n.h3,{id:t[5].id,children:t[5].value}),"\n",(0,i.jsxs)(n.p,{children:["Every service is injectable. Implement ",(0,i.jsx)(n.code,{children:"ConnectivityAdapter"})," (or pass fake\nservice instances) and call ",(0,i.jsx)(n.code,{children:"NetworkDiagnostic.configure(...)"}),", then\n",(0,i.jsx)(n.code,{children:"NetworkDiagnostic.reset()"})," to restore defaults. See\n",(0,i.jsx)(n.a,{href:"Usage#dependency-injection--tests",children:"Usage → Dependency injection"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["每个服务都可注入。实现 ",(0,i.jsx)(n.code,{children:"ConnectivityAdapter"}),"(或直接传入假服务实例)后调用\n",(0,i.jsx)(n.code,{children:"NetworkDiagnostic.configure(...)"}),",再用 ",(0,i.jsx)(n.code,{children:"NetworkDiagnostic.reset()"})," 恢复默认。详见\n",(0,i.jsx)(n.a,{href:"Usage#dependency-injection--tests",children:"用法 → 依赖注入"}),"。"]}),"\n",(0,i.jsx)(n.h3,{id:t[6].id,children:t[6].value}),"\n",(0,i.jsxs)(n.p,{children:["MPL-2.0. See the repository ",(0,i.jsx)(n.a,{href:"https://github.com/zero-labsco/zero_network_kit/blob/main/LICENSE",children:"LICENSE"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["采用 MPL-2.0。详见仓库 ",(0,i.jsx)(n.a,{href:"https://github.com/zero-labsco/zero_network_kit/blob/main/LICENSE",children:"LICENSE"}),"。"]})]})},"/FAQ",{filePath:"pages/FAQ.md",timestamp:1789334081e3,pageMap:o.v,frontMatter:{},title:"FAQ / 常见问题"},"undefined"==typeof RemoteContent?d:RemoteContent.useTOC)},7080:function(e,t,n){"use strict";n.d(t,{v:function(){return i}});let i=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(e){e.O(0,[812,888,774,179],function(){return e(e.s=9238)}),_N_E=e.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Platform-Support-3994cdd8603e191b.js b/docs/_next/static/chunks/pages/Platform-Support-3994cdd8603e191b.js new file mode 100644 index 0000000..bec793f --- /dev/null +++ b/docs/_next/static/chunks/pages/Platform-Support-3994cdd8603e191b.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[397],{9502:function(n,e,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Platform-Support",function(){return s(622)}])},622:function(n,e,s){"use strict";s.r(e),s.d(e,{useTOC:function(){return l}});var i=s(5893),d=s(7812),r=s(7080),t=s(8925);function l(n){let e={code:"code",...(0,t.a)()};return[{value:"Capability matrix / 能力矩阵",id:"capability-matrix--能力矩阵",depth:2},{value:(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.code,{children:"NetworkCapabilities"})," / 能力查询"]}),id:"networkcapabilities--能力查询",depth:2},{value:"Native details on desktop / 桌面原生详情",id:"native-details-on-desktop--桌面原生详情",depth:2},{value:"Web support / Web 支持",id:"web-support--web-支持",depth:2},{value:"Reading native data / 读取原生数据",id:"reading-native-data--读取原生数据",depth:2}]}e.default=(0,d.c)(function(n){let{toc:e=l(n)}=n,s={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,t.a)(),...n.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(s.h1,{children:"Platform Support / 平台支持"}),"\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.code,{children:"zero_network_kit"})," is declared on ",(0,i.jsx)(s.strong,{children:"six"})," plugin platforms: Android, iOS,\nmacOS, Windows, Linux and ",(0,i.jsx)(s.strong,{children:"Web"}),". Web support is ",(0,i.jsx)(s.strong,{children:"partial"}),": the services that\ndepend on ",(0,i.jsx)(s.code,{children:"dart:io"})," are swapped for browser-safe equivalents, and the\ncapabilities the sandbox forbids degrade gracefully instead of failing."]}),"\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.code,{children:"zero_network_kit"})," 在 ",(0,i.jsx)(s.strong,{children:"六"})," 个插件平台上声明:Android、iOS、macOS、Windows、Linux\n与 ",(0,i.jsx)(s.strong,{children:"Web"}),"。Web 为",(0,i.jsx)(s.strong,{children:"部分支持"}),":依赖 ",(0,i.jsx)(s.code,{children:"dart:io"})," 的服务已替换为浏览器安全的等价实现,\n浏览器沙箱禁止的能力会优雅降级而不会失败。"]}),"\n",(0,i.jsx)(s.h2,{id:e[0].id,children:e[0].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Capability"}),(0,i.jsx)(s.th,{children:"Android / iOS"}),(0,i.jsx)(s.th,{children:"Desktop (macOS / Windows / Linux)"}),(0,i.jsx)(s.th,{children:"Web"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:["Connectivity (",(0,i.jsx)(s.code,{children:"connectivity_plus"}),")"]}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"✅"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:["Local IP / IPv6 (",(0,i.jsx)(s.code,{children:"NetworkInterface"}),")"]}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"❌"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Native details (SSID / gateway / MAC / VPN)"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"⚠️ see below"}),(0,i.jsx)(s.td,{children:"❌"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"TCP ping"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"⚠️ HTTPS round trip"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:["ICMP ping (",(0,i.jsx)(s.code,{children:"Process.run('ping')"}),")"]}),(0,i.jsx)(s.td,{children:"❌"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"❌"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"HTTP ping"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"✅"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"DNS system resolver"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"✅ DoH"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"DNS raw UDP"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"⚠️ DoH endpoint required"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Port check / scan"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"❌"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Speed test"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"✅"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Quality score"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"✅"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Benchmarks"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"✅"})]})]})]}),"\n",(0,i.jsx)(s.h2,{id:e[1].id,children:e[1].value}),"\n",(0,i.jsx)(s.p,{children:"Query the host platform before calling, so your UI can hide unsupported cards:"}),"\n",(0,i.jsx)(s.p,{children:"在调用前查询当前平台能力,UI 即可据此隐藏不支持的卡片:"}),"\n",(0,i.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,i.jsxs)(s.code,{children:[(0,i.jsxs)(s.span,{children:[(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" caps "}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".capabilities;"})]}),"\n",(0,i.jsxs)(s.span,{children:[(0,i.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(caps.platform); "}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 'android' | 'ios' | 'macos' | 'windows' | 'linux' | 'web'"})]}),"\n",(0,i.jsxs)(s.span,{children:[(0,i.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(caps."}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"supports"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkCapability"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".nativeDetails)); "}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// mobile: true, desktop: false"})]}),"\n",(0,i.jsxs)(s.span,{children:[(0,i.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(caps."}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"supports"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkCapability"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".icmpPing)); "}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// desktop: true, mobile: false"})]})]})}),"\n",(0,i.jsxs)(s.p,{children:["Rules baked into ",(0,i.jsx)(s.code,{children:"NetworkCapabilities.current()"}),":"]}),"\n",(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.code,{children:"nativeDetails"})," is ",(0,i.jsx)(s.strong,{children:"mobile-only"})," (SSID / gateway / MAC / VPN need system APIs)."]}),"\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.code,{children:"icmpPing"})," is ",(0,i.jsx)(s.strong,{children:"desktop-only"})," (uses the system ",(0,i.jsx)(s.code,{children:"ping"})," binary)."]}),"\n",(0,i.jsxs)(s.li,{children:["On ",(0,i.jsx)(s.strong,{children:"web"})," the supported set narrows to ",(0,i.jsx)(s.code,{children:"connectivity"}),", ",(0,i.jsx)(s.code,{children:"tcpPing"}),",\n",(0,i.jsx)(s.code,{children:"dnsSystem"}),", ",(0,i.jsx)(s.code,{children:"speedTest"}),", ",(0,i.jsx)(s.code,{children:"quality"})," and ",(0,i.jsx)(s.code,{children:"benchmark"}),"; every other capability is\nabsent."]}),"\n"]}),"\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.code,{children:"NetworkCapabilities.current()"})," 内置规则:"]}),"\n",(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.code,{children:"nativeDetails"})," ",(0,i.jsx)(s.strong,{children:"仅移动端"}),"(SSID / 网关 / MAC / VPN 需要系统 API)。"]}),"\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.code,{children:"icmpPing"})," ",(0,i.jsx)(s.strong,{children:"仅桌面"}),"(使用系统 ",(0,i.jsx)(s.code,{children:"ping"})," 命令)。"]}),"\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.strong,{children:"Web"})," 上的支持集合收缩为 ",(0,i.jsx)(s.code,{children:"connectivity"}),"、",(0,i.jsx)(s.code,{children:"tcpPing"}),"、",(0,i.jsx)(s.code,{children:"dnsSystem"}),"、",(0,i.jsx)(s.code,{children:"speedTest"}),"、\n",(0,i.jsx)(s.code,{children:"quality"})," 与 ",(0,i.jsx)(s.code,{children:"benchmark"}),",其余能力均不存在。"]}),"\n"]}),"\n",(0,i.jsx)(s.h2,{id:e[2].id,children:e[2].value}),"\n",(0,i.jsxs)(s.p,{children:["Desktop uses ",(0,i.jsx)(s.strong,{children:"tier A"})," by default: the native layer only reports the platform\nversion and an (often empty) details map. IP/IPv6 come from Dart\n",(0,i.jsx)(s.code,{children:"NetworkInterface"}),". As a result:"]}),"\n",(0,i.jsxs)(s.p,{children:["桌面默认采用 ",(0,i.jsx)(s.strong,{children:"A 档"}),":原生层只报告平台版本与(通常为空的)详情 map,IP/IPv6 由 Dart\n",(0,i.jsx)(s.code,{children:"NetworkInterface"})," 兜底。因此:"]}),"\n",(0,i.jsxs)(s.ul,{children:["\n",(0,i.jsxs)(s.li,{children:[(0,i.jsxs)(s.strong,{children:["SSID / signal strength are always ",(0,i.jsx)(s.code,{children:"null"})," on desktop."]}),"\n",(0,i.jsxs)(s.strong,{children:["桌面上的 SSID / 信号强度恒为 ",(0,i.jsx)(s.code,{children:"null"}),"。"]})]}),"\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.code,{children:"gateway"})," / ",(0,i.jsx)(s.code,{children:"macAddress"})," / ",(0,i.jsx)(s.code,{children:"isVpn"})," are ",(0,i.jsx)(s.code,{children:"null"})," on macOS and Linux.\nmacOS 与 Linux 上 ",(0,i.jsx)(s.code,{children:"gateway"})," / ",(0,i.jsx)(s.code,{children:"macAddress"})," / ",(0,i.jsx)(s.code,{children:"isVpn"})," 为 ",(0,i.jsx)(s.code,{children:"null"}),"。"]}),"\n",(0,i.jsxs)(s.li,{children:[(0,i.jsx)(s.strong,{children:"Windows"})," additionally implements ",(0,i.jsx)(s.code,{children:"GetAdaptersAddresses"}),", so it reports\n",(0,i.jsx)(s.code,{children:"gateway"})," / ",(0,i.jsx)(s.code,{children:"macAddress"})," / DNS / ",(0,i.jsx)(s.code,{children:"isVpn"})," (SSID still ",(0,i.jsx)(s.code,{children:"null"}),"). This is a bonus\ntier-B fragment kept as-is.\n",(0,i.jsx)(s.strong,{children:"Windows"})," 额外实现了 ",(0,i.jsx)(s.code,{children:"GetAdaptersAddresses"}),",因此上报 ",(0,i.jsx)(s.code,{children:"gateway"})," / ",(0,i.jsx)(s.code,{children:"macAddress"})," /\nDNS / ",(0,i.jsx)(s.code,{children:"isVpn"}),"(SSID 仍为 ",(0,i.jsx)(s.code,{children:"null"}),")。这是保留的 B 档赠品。"]}),"\n"]}),"\n",(0,i.jsxs)(s.p,{children:["Whatever the platform, a missing permission or an unreachable native call never\nthrows — the field simply stays ",(0,i.jsx)(s.code,{children:"null"})," and the rest of the result still arrives."]}),"\n",(0,i.jsxs)(s.p,{children:["无论在哪个平台,缺权限或原生调用不可达都",(0,i.jsx)(s.strong,{children:"不会抛异常"}),"——对应字段保持 ",(0,i.jsx)(s.code,{children:"null"}),",其余\n结果照常返回。"]}),"\n",(0,i.jsx)(s.h2,{id:e[3].id,children:e[3].value}),"\n",(0,i.jsxs)(s.p,{children:["The web build exposes the same static API. Capabilities that the browser sandbox\nforbids degrade gracefully — they return ",(0,i.jsx)(s.code,{children:"null"})," or an “unavailable” result\ninstead of throwing:"]}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"Capability"}),(0,i.jsx)(s.th,{children:"Web"}),(0,i.jsx)(s.th,{children:"Notes"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Connectivity"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsxs)(s.td,{children:["via ",(0,i.jsx)(s.code,{children:"connectivity_plus"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:["Ping (",(0,i.jsx)(s.code,{children:"PingMode.tcp"}),")"]}),(0,i.jsx)(s.td,{children:"⚠️"}),(0,i.jsx)(s.td,{children:"measured as an HTTPS round trip; the target must send CORS headers"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:["Ping (",(0,i.jsx)(s.code,{children:"PingMode.icmp"}),")"]}),(0,i.jsx)(s.td,{children:"❌"}),(0,i.jsxs)(s.td,{children:["throws ",(0,i.jsx)(s.code,{children:"UnsupportedError"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"DNS (system resolver)"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"via DNS-over-HTTPS"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"DNS (explicit server)"}),(0,i.jsx)(s.td,{children:"⚠️"}),(0,i.jsx)(s.td,{children:"needs a DoH endpoint, otherwise “unsupported”"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Speed test"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"HTTP download / upload"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Quality score"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"pure function"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Benchmarks"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"pure function"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Port check / scan"}),(0,i.jsx)(s.td,{children:"❌"}),(0,i.jsx)(s.td,{children:"returns “unavailable” results"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"Native details (SSID, gateway, MAC, VPN)"}),(0,i.jsx)(s.td,{children:"❌"}),(0,i.jsx)(s.td,{children:(0,i.jsx)(s.code,{children:"null"})})]})]})]}),"\n",(0,i.jsxs)(s.p,{children:["Browsers expose ",(0,i.jsx)(s.strong,{children:"no VPN API"}),", so ",(0,i.jsx)(s.code,{children:"isVpn"})," stays ",(0,i.jsx)(s.code,{children:"false"})," on the web even when a\nsystem VPN or a local HTTP proxy is active."]}),"\n",(0,i.jsxs)(s.p,{children:["Web 构建提供同样的静态 API;浏览器沙箱禁止的能力会优雅降级(返回 ",(0,i.jsx)(s.code,{children:"null"})," 或”不可用”\n结果,而不是抛异常):"]}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,i.jsxs)(s.table,{children:[(0,i.jsx)(s.thead,{children:(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.th,{children:"能力"}),(0,i.jsx)(s.th,{children:"Web"}),(0,i.jsx)(s.th,{children:"说明"})]})}),(0,i.jsxs)(s.tbody,{children:[(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"连通性检测"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsxs)(s.td,{children:["通过 ",(0,i.jsx)(s.code,{children:"connectivity_plus"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:["Ping(",(0,i.jsx)(s.code,{children:"PingMode.tcp"}),")"]}),(0,i.jsx)(s.td,{children:"⚠️"}),(0,i.jsx)(s.td,{children:"以 HTTPS 往返耗时度量,目标主机需下发 CORS 头"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsxs)(s.td,{children:["Ping(",(0,i.jsx)(s.code,{children:"PingMode.icmp"}),")"]}),(0,i.jsx)(s.td,{children:"❌"}),(0,i.jsxs)(s.td,{children:["抛出 ",(0,i.jsx)(s.code,{children:"UnsupportedError"})]})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"DNS(系统解析器)"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"通过 DNS-over-HTTPS"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"DNS(指定服务器)"}),(0,i.jsx)(s.td,{children:"⚠️"}),(0,i.jsx)(s.td,{children:"需要 DoH 端点,否则返回”不支持”"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"带宽测速"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"HTTP 下载 / 上传"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"质量评分"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"纯函数"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"基准测试"}),(0,i.jsx)(s.td,{children:"✅"}),(0,i.jsx)(s.td,{children:"纯函数"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"端口检测 / 扫描"}),(0,i.jsx)(s.td,{children:"❌"}),(0,i.jsx)(s.td,{children:"返回”不可用”结果"})]}),(0,i.jsxs)(s.tr,{children:[(0,i.jsx)(s.td,{children:"原生详情(SSID、网关、MAC、VPN)"}),(0,i.jsx)(s.td,{children:"❌"}),(0,i.jsxs)(s.td,{children:["返回 ",(0,i.jsx)(s.code,{children:"null"})]})]})]})]}),"\n",(0,i.jsxs)(s.p,{children:["浏览器",(0,i.jsx)(s.strong,{children:"不暴露 VPN 接口"}),",因此即使系统开启了 VPN 或本地 HTTP 代理,Web 上的\n",(0,i.jsx)(s.code,{children:"isVpn"})," 仍为 ",(0,i.jsx)(s.code,{children:"false"}),"。"]}),"\n",(0,i.jsx)(s.h2,{id:e[4].id,children:e[4].value}),"\n",(0,i.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,i.jsxs)(s.code,{children:[(0,i.jsxs)(s.span,{children:[(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" version "}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ZeroNetworkKit"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"getPlatformVersion"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,i.jsxs)(s.span,{children:[(0,i.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(version); "}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// e.g. 'Android 14' / 'iOS 18.0' / 'Web'"})]}),"\n",(0,i.jsx)(s.span,{children:" "}),"\n",(0,i.jsxs)(s.span,{children:[(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" details "}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ZeroNetworkKit"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"getNativeNetworkDetails"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,i.jsxs)(s.span,{children:[(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"if"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (details "}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"!="}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" null"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:") {"})]}),"\n",(0,i.jsxs)(s.span,{children:[(0,i.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(details); "}),(0,i.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// SSID, BSSID, gateway, MAC, VPN flag, RSSI …"})]}),"\n",(0,i.jsx)(s.span,{children:(0,i.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,i.jsxs)(s.p,{children:[(0,i.jsx)(s.code,{children:"details"})," is always ",(0,i.jsx)(s.code,{children:"null"})," on the web, and usually ",(0,i.jsx)(s.code,{children:"null"})," on desktop too (see\nabove)."]}),"\n",(0,i.jsxs)(s.p,{children:["Web 上 ",(0,i.jsx)(s.code,{children:"details"})," 恒为 ",(0,i.jsx)(s.code,{children:"null"}),",桌面端通常也为 ",(0,i.jsx)(s.code,{children:"null"}),"(见上文)。"]})]})},"/Platform-Support",{filePath:"pages/Platform-Support.md",timestamp:1789334081e3,pageMap:r.v,frontMatter:{},title:"Platform Support / 平台支持"},"undefined"==typeof RemoteContent?l:RemoteContent.useTOC)},7080:function(n,e,s){"use strict";s.d(e,{v:function(){return i}});let i=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(n){n.O(0,[812,888,774,179],function(){return n(n.s=9502)}),_N_E=n.O()}]); \ No newline at end of file diff --git a/docs/_next/static/chunks/pages/Platform-Support-45a009c029992240.js b/docs/_next/static/chunks/pages/Platform-Support-45a009c029992240.js deleted file mode 100644 index 5b2944c..0000000 --- a/docs/_next/static/chunks/pages/Platform-Support-45a009c029992240.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[397],{9502:function(i,e,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/Platform-Support",function(){return s(622)}])},622:function(i,e,s){"use strict";s.r(e),s.d(e,{useTOC:function(){return d}});var n=s(5893),t=s(7812),r=s(7080),l=s(8925);function d(i){let e={code:"code",...(0,l.a)()};return[{value:"Capability matrix / 能力矩阵",id:"capability-matrix--能力矩阵",depth:2},{value:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.code,{children:"NetworkCapabilities"})," / 能力查询"]}),id:"networkcapabilities--能力查询",depth:2},{value:"Native details on desktop / 桌面原生详情",id:"native-details-on-desktop--桌面原生详情",depth:2},{value:"Reading native data / 读取原生数据",id:"reading-native-data--读取原生数据",depth:2}]}e.default=(0,t.c)(function(i){let{toc:e=d(i)}=i,s={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,l.a)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.h1,{children:"Platform Support / 平台支持"}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"zero_network_kit"})," is declared on ",(0,n.jsx)(s.strong,{children:"five"})," plugin platforms: Android, iOS,\nmacOS, Windows and Linux. ",(0,n.jsx)(s.strong,{children:"Web is not supported"})," — the Dart services rely on\n",(0,n.jsx)(s.code,{children:"dart:io"}),", which does not compile for the web, and browsers have no raw\nTCP/UDP sockets."]}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"zero_network_kit"})," 在 ",(0,n.jsx)(s.strong,{children:"五"})," 个插件平台上声明:Android、iOS、macOS、Windows 与\nLinux。",(0,n.jsx)(s.strong,{children:"不支持 Web"}),"——Dart 服务依赖 ",(0,n.jsx)(s.code,{children:"dart:io"}),"(无法在 Web 上编译),且浏览器没有\n原生 TCP/UDP 套接字。"]}),"\n",(0,n.jsx)(s.h2,{id:e[0].id,children:e[0].value}),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",(0,n.jsxs)(s.table,{children:[(0,n.jsx)(s.thead,{children:(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.th,{children:"Capability"}),(0,n.jsx)(s.th,{children:"Android / iOS"}),(0,n.jsx)(s.th,{children:"Desktop (macOS / Windows / Linux)"})]})}),(0,n.jsxs)(s.tbody,{children:[(0,n.jsxs)(s.tr,{children:[(0,n.jsxs)(s.td,{children:["Connectivity (",(0,n.jsx)(s.code,{children:"connectivity_plus"}),")"]}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsxs)(s.td,{children:["Local IP / IPv6 (",(0,n.jsx)(s.code,{children:"NetworkInterface"}),")"]}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Native details (SSID / gateway / MAC / VPN)"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"⚠️ see below"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"TCP ping"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsxs)(s.td,{children:["ICMP ping (",(0,n.jsx)(s.code,{children:"Process.run('ping')"}),")"]}),(0,n.jsx)(s.td,{children:"❌"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"HTTP ping"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"DNS system resolver"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"DNS raw UDP"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Port check / scan"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Speed test"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Quality score"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]}),(0,n.jsxs)(s.tr,{children:[(0,n.jsx)(s.td,{children:"Benchmarks"}),(0,n.jsx)(s.td,{children:"✅"}),(0,n.jsx)(s.td,{children:"✅"})]})]})]}),"\n",(0,n.jsx)(s.h2,{id:e[1].id,children:e[1].value}),"\n",(0,n.jsx)(s.p,{children:"Query the host platform before calling, so your UI can hide unsupported cards:"}),"\n",(0,n.jsx)(s.p,{children:"在调用前查询当前平台能力,UI 即可据此隐藏不支持的卡片:"}),"\n",(0,n.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" caps "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" NetworkDiagnostic"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".capabilities;"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(caps.platform); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// 'android' | 'ios' | 'macos' | 'windows' | 'linux'"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(caps."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"supports"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkCapability"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".nativeDetails)); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// mobile: true, desktop: false"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(caps."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"supports"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"NetworkCapability"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:".icmpPing)); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// desktop: true, mobile: false"})]})]})}),"\n",(0,n.jsxs)(s.p,{children:["Rules baked into ",(0,n.jsx)(s.code,{children:"NetworkCapabilities.current()"}),":"]}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"nativeDetails"})," is ",(0,n.jsx)(s.strong,{children:"mobile-only"})," (SSID / gateway / MAC / VPN need system APIs)."]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"icmpPing"})," is ",(0,n.jsx)(s.strong,{children:"desktop-only"})," (uses the system ",(0,n.jsx)(s.code,{children:"ping"})," binary)."]}),"\n"]}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"NetworkCapabilities.current()"})," 内置规则:"]}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"nativeDetails"})," ",(0,n.jsx)(s.strong,{children:"仅移动端"}),"(SSID / 网关 / MAC / VPN 需要系统 API)。"]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"icmpPing"})," ",(0,n.jsx)(s.strong,{children:"仅桌面"}),"(使用系统 ",(0,n.jsx)(s.code,{children:"ping"})," 命令)。"]}),"\n"]}),"\n",(0,n.jsx)(s.h2,{id:e[2].id,children:e[2].value}),"\n",(0,n.jsxs)(s.p,{children:["Desktop uses ",(0,n.jsx)(s.strong,{children:"tier A"})," by default: the native layer only reports the platform\nversion and an (often empty) details map. IP/IPv6 come from Dart\n",(0,n.jsx)(s.code,{children:"NetworkInterface"}),". As a result:"]}),"\n",(0,n.jsxs)(s.p,{children:["桌面默认采用 ",(0,n.jsx)(s.strong,{children:"A 档"}),":原生层只报告平台版本与(通常为空的)详情 map,IP/IPv6 由 Dart\n",(0,n.jsx)(s.code,{children:"NetworkInterface"})," 兜底。因此:"]}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsxs)(s.strong,{children:["SSID / signal strength are always ",(0,n.jsx)(s.code,{children:"null"})," on desktop."]}),"\n",(0,n.jsxs)(s.strong,{children:["桌面上的 SSID / 信号强度恒为 ",(0,n.jsx)(s.code,{children:"null"}),"。"]})]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"gateway"})," / ",(0,n.jsx)(s.code,{children:"macAddress"})," / ",(0,n.jsx)(s.code,{children:"isVpn"})," are ",(0,n.jsx)(s.code,{children:"null"})," on macOS and Linux.\nmacOS 与 Linux 上 ",(0,n.jsx)(s.code,{children:"gateway"})," / ",(0,n.jsx)(s.code,{children:"macAddress"})," / ",(0,n.jsx)(s.code,{children:"isVpn"})," 为 ",(0,n.jsx)(s.code,{children:"null"}),"。"]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.strong,{children:"Windows"})," additionally implements ",(0,n.jsx)(s.code,{children:"GetAdaptersAddresses"}),", so it reports\n",(0,n.jsx)(s.code,{children:"gateway"})," / ",(0,n.jsx)(s.code,{children:"macAddress"})," / DNS / ",(0,n.jsx)(s.code,{children:"isVpn"})," (SSID still ",(0,n.jsx)(s.code,{children:"null"}),"). This is a bonus\ntier-B fragment kept as-is.\n",(0,n.jsx)(s.strong,{children:"Windows"})," 额外实现了 ",(0,n.jsx)(s.code,{children:"GetAdaptersAddresses"}),",因此上报 ",(0,n.jsx)(s.code,{children:"gateway"})," / ",(0,n.jsx)(s.code,{children:"macAddress"})," /\nDNS / ",(0,n.jsx)(s.code,{children:"isVpn"}),"(SSID 仍为 ",(0,n.jsx)(s.code,{children:"null"}),")。这是保留的 B 档赠品。"]}),"\n"]}),"\n",(0,n.jsxs)(s.p,{children:["Whatever the platform, a missing permission or an unreachable native call never\nthrows — the field simply stays ",(0,n.jsx)(s.code,{children:"null"})," and the rest of the result still arrives."]}),"\n",(0,n.jsxs)(s.p,{children:["无论在哪个平台,缺权限或原生调用不可达都",(0,n.jsx)(s.strong,{children:"不会抛异常"}),"——对应字段保持 ",(0,n.jsx)(s.code,{children:"null"}),",其余\n结果照常返回。"]}),"\n",(0,n.jsx)(s.h2,{id:e[3].id,children:e[3].value}),"\n",(0,n.jsx)(s.pre,{tabIndex:"0","data-language":"dart","data-word-wrap":"","data-copy":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" version "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ZeroNetworkKit"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"getPlatformVersion"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(version); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// e.g. 'Android 14' / 'iOS 18.0'"})]}),"\n",(0,n.jsx)(s.span,{children:" "}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"final"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" details "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" ZeroNetworkKit"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:"getNativeNetworkDetails"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"if"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" (details "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"!="}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" null"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:") {"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" print"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"(details); "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6A737D","--shiki-dark":"#6A737D"},children:"// SSID, BSSID, gateway, MAC, VPN flag, RSSI …"})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})})]})},"/Platform-Support",{filePath:"pages/Platform-Support.md",timestamp:1789334081e3,pageMap:r.v,frontMatter:{},title:"Platform Support / 平台支持"},"undefined"==typeof RemoteContent?d:RemoteContent.useTOC)},7080:function(i,e,s){"use strict";s.d(e,{v:function(){return n}});let n=[{data:{index:"\uD83C\uDFE0 Home","Getting-Started":"\uD83D\uDE80 Getting Started",Installation:"\uD83D\uDCE6 Installation",Usage:"\uD83D\uDCD6 Usage","--capabilities":{type:"separator",title:"\uD83D\uDD27 Capabilities"},Connectivity:"\uD83D\uDCE1 Connectivity",Ping:"⏱ Latency / Ping",DNS:"\uD83C\uDF0D DNS",Ports:"\uD83D\uDD0C Ports","Speed-Test":"\uD83D\uDE80 Speed Test",Quality:"⭐ Quality Score","Full-Report":"\uD83D\uDCCB Full Report",Benchmark:"\uD83D\uDCCA Benchmarks","--advanced":{type:"separator",title:"\uD83D\uDEE0 Advanced"},"Platform-Support":"\uD83D\uDDA5 Platform Support","API-Reference":"\uD83D\uDCDA API Reference","--info":{type:"separator",title:"ℹ️ Info"},FAQ:"❓ FAQ"}},{name:"API-Reference",route:"/API-Reference",frontMatter:{sidebarTitle:"API Reference"}},{name:"Benchmark",route:"/Benchmark",frontMatter:{sidebarTitle:"Benchmark"}},{name:"Connectivity",route:"/Connectivity",frontMatter:{sidebarTitle:"Connectivity"}},{name:"DNS",route:"/DNS",frontMatter:{sidebarTitle:"DNS"}},{name:"FAQ",route:"/FAQ",frontMatter:{sidebarTitle:"Faq"}},{name:"Full-Report",route:"/Full-Report",frontMatter:{sidebarTitle:"Full Report"}},{name:"Getting-Started",route:"/Getting-Started",frontMatter:{sidebarTitle:"Getting Started"}},{name:"index",route:"/",frontMatter:{sidebarTitle:"Index"}},{name:"Installation",route:"/Installation",frontMatter:{sidebarTitle:"Installation"}},{name:"Ping",route:"/Ping",frontMatter:{sidebarTitle:"Ping"}},{name:"Platform-Support",route:"/Platform-Support",frontMatter:{sidebarTitle:"Platform Support"}},{name:"Ports",route:"/Ports",frontMatter:{sidebarTitle:"Ports"}},{name:"Quality",route:"/Quality",frontMatter:{sidebarTitle:"Quality"}},{name:"Speed-Test",route:"/Speed-Test",frontMatter:{sidebarTitle:"Speed Test"}},{name:"Usage",route:"/Usage",frontMatter:{sidebarTitle:"Usage"}}]}},function(i){i.O(0,[812,888,774,179],function(){return i(i.s=9502)}),_N_E=i.O()}]); \ No newline at end of file diff --git a/docs/_next/static/dF_UuZS4SBtufIwTYLshU/_buildManifest.js b/docs/_next/static/x-nTvOiGfo930-2DM2DH8/_buildManifest.js similarity index 91% rename from docs/_next/static/dF_UuZS4SBtufIwTYLshU/_buildManifest.js rename to docs/_next/static/x-nTvOiGfo930-2DM2DH8/_buildManifest.js index 11b3f26..f0dc45e 100644 --- a/docs/_next/static/dF_UuZS4SBtufIwTYLshU/_buildManifest.js +++ b/docs/_next/static/x-nTvOiGfo930-2DM2DH8/_buildManifest.js @@ -1 +1 @@ -self.__BUILD_MANIFEST=function(e){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":[e,"static/chunks/pages/index-2a81fce2c8fa4aa7.js"],"/API-Reference":[e,"static/chunks/pages/API-Reference-e13a2917d7546319.js"],"/Benchmark":[e,"static/chunks/pages/Benchmark-a292e8cb0a504f00.js"],"/Connectivity":[e,"static/chunks/pages/Connectivity-f9b385023ad97f07.js"],"/DNS":[e,"static/chunks/pages/DNS-93340032eaa9ffdd.js"],"/FAQ":[e,"static/chunks/pages/FAQ-c14e0ebd2147b3f8.js"],"/Full-Report":[e,"static/chunks/pages/Full-Report-8fdda01136483e9e.js"],"/Getting-Started":[e,"static/chunks/pages/Getting-Started-0b9a79d0ebc87cdf.js"],"/Installation":[e,"static/chunks/pages/Installation-43ade467e1e7ca4a.js"],"/Ping":[e,"static/chunks/pages/Ping-e7614d3667bef7af.js"],"/Platform-Support":[e,"static/chunks/pages/Platform-Support-45a009c029992240.js"],"/Ports":[e,"static/chunks/pages/Ports-743ec1523389b840.js"],"/Quality":[e,"static/chunks/pages/Quality-ac653fb19750eaeb.js"],"/Speed-Test":[e,"static/chunks/pages/Speed-Test-03d333b534600839.js"],"/Usage":[e,"static/chunks/pages/Usage-668e8555c3b8432b.js"],"/_error":["static/chunks/pages/_error-7a92967bea80186d.js"],"/_meta":["static/chunks/pages/_meta-b47e7a01bb6b7929.js"],sortedPages:["/","/API-Reference","/Benchmark","/Connectivity","/DNS","/FAQ","/Full-Report","/Getting-Started","/Installation","/Ping","/Platform-Support","/Ports","/Quality","/Speed-Test","/Usage","/_app","/_error","/_meta"]}}("static/chunks/812-02e96d01ac591260.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB(); \ No newline at end of file +self.__BUILD_MANIFEST=function(e){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":[e,"static/chunks/pages/index-2a81fce2c8fa4aa7.js"],"/API-Reference":[e,"static/chunks/pages/API-Reference-e13a2917d7546319.js"],"/Benchmark":[e,"static/chunks/pages/Benchmark-a292e8cb0a504f00.js"],"/Connectivity":[e,"static/chunks/pages/Connectivity-f9b385023ad97f07.js"],"/DNS":[e,"static/chunks/pages/DNS-93340032eaa9ffdd.js"],"/FAQ":[e,"static/chunks/pages/FAQ-bccbbb52a0b53bb8.js"],"/Full-Report":[e,"static/chunks/pages/Full-Report-8fdda01136483e9e.js"],"/Getting-Started":[e,"static/chunks/pages/Getting-Started-0b9a79d0ebc87cdf.js"],"/Installation":[e,"static/chunks/pages/Installation-43ade467e1e7ca4a.js"],"/Ping":[e,"static/chunks/pages/Ping-e7614d3667bef7af.js"],"/Platform-Support":[e,"static/chunks/pages/Platform-Support-3994cdd8603e191b.js"],"/Ports":[e,"static/chunks/pages/Ports-743ec1523389b840.js"],"/Quality":[e,"static/chunks/pages/Quality-ac653fb19750eaeb.js"],"/Speed-Test":[e,"static/chunks/pages/Speed-Test-03d333b534600839.js"],"/Usage":[e,"static/chunks/pages/Usage-668e8555c3b8432b.js"],"/_error":["static/chunks/pages/_error-7a92967bea80186d.js"],"/_meta":["static/chunks/pages/_meta-b47e7a01bb6b7929.js"],sortedPages:["/","/API-Reference","/Benchmark","/Connectivity","/DNS","/FAQ","/Full-Report","/Getting-Started","/Installation","/Ping","/Platform-Support","/Ports","/Quality","/Speed-Test","/Usage","/_app","/_error","/_meta"]}}("static/chunks/812-02e96d01ac591260.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB(); \ No newline at end of file diff --git a/docs/_next/static/dF_UuZS4SBtufIwTYLshU/_ssgManifest.js b/docs/_next/static/x-nTvOiGfo930-2DM2DH8/_ssgManifest.js similarity index 100% rename from docs/_next/static/dF_UuZS4SBtufIwTYLshU/_ssgManifest.js rename to docs/_next/static/x-nTvOiGfo930-2DM2DH8/_ssgManifest.js diff --git a/docs/index.html b/docs/index.html index f8d17ae..0dc976a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,4 +1,4 @@ -
    🏠 Home

    Zero Network Kit

    +
    🏠 Home

    Zero Network Kit

    A Flutter plugin for network diagnostics: connectivity inspection, latency probing, DNS resolution, port checks, bandwidth measurement, quality scoring and micro-benchmarks — on Android, iOS, macOS, Windows and Linux.

    @@ -143,4 +143,4 @@

    本插件按”原样”提供,不提供任何担保。作者不对修改版或衍生项目的功能、安全性及 -任何使用后果承担责任。


    Zero Network Kit · MPL-2.0
    \ No newline at end of file +任何使用后果承担责任。


    Zero Network Kit · MPL-2.0
    \ No newline at end of file diff --git a/website/pages/FAQ.md b/website/pages/FAQ.md index 16c361b..5d211fc 100644 --- a/website/pages/FAQ.md +++ b/website/pages/FAQ.md @@ -11,9 +11,10 @@ servers). Connectivity alone works with zero setup. ### Which platforms are supported? / 支持哪些平台? -Android, iOS, macOS, Windows and Linux. Web is **not** supported. +Android, iOS, macOS, Windows, Linux and Web (partial — see +[Platform Support](Platform-Support)). -支持 Android、iOS、macOS、Windows 与 Linux。Web **不支持**。详见 +支持 Android、iOS、macOS、Windows、Linux 与 Web(部分支持)。详见 [Platform Support](Platform-Support)。 ### Why is `ssid` / `signalStrength` `null` on desktop? / 为什么桌面上的 ssid/信号强度是 null? diff --git a/website/pages/Platform-Support.md b/website/pages/Platform-Support.md index f74ed22..6fb2ec4 100644 --- a/website/pages/Platform-Support.md +++ b/website/pages/Platform-Support.md @@ -1,30 +1,30 @@ # Platform Support / 平台支持 -`zero_network_kit` is declared on **five** plugin platforms: Android, iOS, -macOS, Windows and Linux. **Web is not supported** — the Dart services rely on -`dart:io`, which does not compile for the web, and browsers have no raw -TCP/UDP sockets. +`zero_network_kit` is declared on **six** plugin platforms: Android, iOS, +macOS, Windows, Linux and **Web**. Web support is **partial**: the services that +depend on `dart:io` are swapped for browser-safe equivalents, and the +capabilities the sandbox forbids degrade gracefully instead of failing. -`zero_network_kit` 在 **五** 个插件平台上声明:Android、iOS、macOS、Windows 与 -Linux。**不支持 Web**——Dart 服务依赖 `dart:io`(无法在 Web 上编译),且浏览器没有 -原生 TCP/UDP 套接字。 +`zero_network_kit` 在 **六** 个插件平台上声明:Android、iOS、macOS、Windows、Linux +与 **Web**。Web 为**部分支持**:依赖 `dart:io` 的服务已替换为浏览器安全的等价实现, +浏览器沙箱禁止的能力会优雅降级而不会失败。 ## Capability matrix / 能力矩阵 -| Capability | Android / iOS | Desktop (macOS / Windows / Linux) | -| --- | --- | --- | -| Connectivity (`connectivity_plus`) | ✅ | ✅ | -| Local IP / IPv6 (`NetworkInterface`) | ✅ | ✅ | -| Native details (SSID / gateway / MAC / VPN) | ✅ | ⚠️ see below | -| TCP ping | ✅ | ✅ | -| ICMP ping (`Process.run('ping')`) | ❌ | ✅ | -| HTTP ping | ✅ | ✅ | -| DNS system resolver | ✅ | ✅ | -| DNS raw UDP | ✅ | ✅ | -| Port check / scan | ✅ | ✅ | -| Speed test | ✅ | ✅ | -| Quality score | ✅ | ✅ | -| Benchmarks | ✅ | ✅ | +| Capability | Android / iOS | Desktop (macOS / Windows / Linux) | Web | +| --- | --- | --- | --- | +| Connectivity (`connectivity_plus`) | ✅ | ✅ | ✅ | +| Local IP / IPv6 (`NetworkInterface`) | ✅ | ✅ | ❌ | +| Native details (SSID / gateway / MAC / VPN) | ✅ | ⚠️ see below | ❌ | +| TCP ping | ✅ | ✅ | ⚠️ HTTPS round trip | +| ICMP ping (`Process.run('ping')`) | ❌ | ✅ | ❌ | +| HTTP ping | ✅ | ✅ | ✅ | +| DNS system resolver | ✅ | ✅ | ✅ DoH | +| DNS raw UDP | ✅ | ✅ | ⚠️ DoH endpoint required | +| Port check / scan | ✅ | ✅ | ❌ | +| Speed test | ✅ | ✅ | ✅ | +| Quality score | ✅ | ✅ | ✅ | +| Benchmarks | ✅ | ✅ | ✅ | ## `NetworkCapabilities` / 能力查询 @@ -34,7 +34,7 @@ Query the host platform before calling, so your UI can hide unsupported cards: ```dart final caps = NetworkDiagnostic.capabilities; -print(caps.platform); // 'android' | 'ios' | 'macos' | 'windows' | 'linux' +print(caps.platform); // 'android' | 'ios' | 'macos' | 'windows' | 'linux' | 'web' print(caps.supports(NetworkCapability.nativeDetails)); // mobile: true, desktop: false print(caps.supports(NetworkCapability.icmpPing)); // desktop: true, mobile: false ``` @@ -43,11 +43,16 @@ Rules baked into `NetworkCapabilities.current()`: - `nativeDetails` is **mobile-only** (SSID / gateway / MAC / VPN need system APIs). - `icmpPing` is **desktop-only** (uses the system `ping` binary). +- On **web** the supported set narrows to `connectivity`, `tcpPing`, + `dnsSystem`, `speedTest`, `quality` and `benchmark`; every other capability is + absent. `NetworkCapabilities.current()` 内置规则: - `nativeDetails` **仅移动端**(SSID / 网关 / MAC / VPN 需要系统 API)。 - `icmpPing` **仅桌面**(使用系统 `ping` 命令)。 +- **Web** 上的支持集合收缩为 `connectivity`、`tcpPing`、`dnsSystem`、`speedTest`、 + `quality` 与 `benchmark`,其余能力均不存在。 ## Native details on desktop / 桌面原生详情 @@ -74,14 +79,60 @@ throws — the field simply stays `null` and the rest of the result still arrive 无论在哪个平台,缺权限或原生调用不可达都**不会抛异常**——对应字段保持 `null`,其余 结果照常返回。 +## Web support / Web 支持 + +The web build exposes the same static API. Capabilities that the browser sandbox +forbids degrade gracefully — they return `null` or an "unavailable" result +instead of throwing: + +| Capability | Web | Notes | +| --- | --- | --- | +| Connectivity | ✅ | via `connectivity_plus` | +| Ping (`PingMode.tcp`) | ⚠️ | measured as an HTTPS round trip; the target must send CORS headers | +| Ping (`PingMode.icmp`) | ❌ | throws `UnsupportedError` | +| DNS (system resolver) | ✅ | via DNS-over-HTTPS | +| DNS (explicit server) | ⚠️ | needs a DoH endpoint, otherwise "unsupported" | +| Speed test | ✅ | HTTP download / upload | +| Quality score | ✅ | pure function | +| Benchmarks | ✅ | pure function | +| Port check / scan | ❌ | returns "unavailable" results | +| Native details (SSID, gateway, MAC, VPN) | ❌ | `null` | + +Browsers expose **no VPN API**, so `isVpn` stays `false` on the web even when a +system VPN or a local HTTP proxy is active. + +Web 构建提供同样的静态 API;浏览器沙箱禁止的能力会优雅降级(返回 `null` 或"不可用" +结果,而不是抛异常): + +| 能力 | Web | 说明 | +| --- | --- | --- | +| 连通性检测 | ✅ | 通过 `connectivity_plus` | +| Ping(`PingMode.tcp`) | ⚠️ | 以 HTTPS 往返耗时度量,目标主机需下发 CORS 头 | +| Ping(`PingMode.icmp`) | ❌ | 抛出 `UnsupportedError` | +| DNS(系统解析器) | ✅ | 通过 DNS-over-HTTPS | +| DNS(指定服务器) | ⚠️ | 需要 DoH 端点,否则返回"不支持" | +| 带宽测速 | ✅ | HTTP 下载 / 上传 | +| 质量评分 | ✅ | 纯函数 | +| 基准测试 | ✅ | 纯函数 | +| 端口检测 / 扫描 | ❌ | 返回"不可用"结果 | +| 原生详情(SSID、网关、MAC、VPN) | ❌ | 返回 `null` | + +浏览器**不暴露 VPN 接口**,因此即使系统开启了 VPN 或本地 HTTP 代理,Web 上的 +`isVpn` 仍为 `false`。 + ## Reading native data / 读取原生数据 ```dart final version = await ZeroNetworkKit.getPlatformVersion(); -print(version); // e.g. 'Android 14' / 'iOS 18.0' +print(version); // e.g. 'Android 14' / 'iOS 18.0' / 'Web' final details = await ZeroNetworkKit.getNativeNetworkDetails(); if (details != null) { print(details); // SSID, BSSID, gateway, MAC, VPN flag, RSSI … } ``` + +`details` is always `null` on the web, and usually `null` on desktop too (see +above). + +Web 上 `details` 恒为 `null`,桌面端通常也为 `null`(见上文)。