跳过主要内容

How to Detect the Network Status in a Capacitor App

在 Capacitor 应用程序中检测网络状态:读取在线/离线状态,监听变化,验证真实的互联网访问,并处理计量网络。

文章来源

马丁·多纳迪厄

作者

瓦莱里娅

审阅者

乔丹

编辑

在 Capacitor 应用程序中检测网络状态

要检测 Capacitor 应用程序的网络状态,请安装 @capacitor/network调用 Network.getStatus() 获取当前状态,并订阅 networkStatusChange 为了获取更新。它告诉你设备是否有连接,并且是否是Wi-Fi还是蜂窝网络。要知道互联网是否实际工作,还是连接是计量的,需要添加可达性检查或 @capgo/capacitor-network-diagnostics本指南涵盖了所有三个层次,包括Capacitor 8 code。

“用户是否在线?”背后的三个问题

问题 API 注意
是否有活动的网络接口? Network.getStatus().connected 快速、事件驱动的,但没有说到互联网访问
是什么类型的连接? connectionType wifi, cellular, none, unknown 在官方插件中
互联网是否实际工作? HTTP检查或 internetReachable 需要请求或操作系统验证
是否应该避免大型下载? expensive, constrained 带有计量的网络和 iOS 低数据模式

大多数离线错误来自于将第一行视为第三行。一个需要登录的酒店 Wi-Fi 网络会报告 connected: true 每次 API 调用都会超时。

安装网络插件

bun add @capacitor/network
bunx cap sync

不需要任何配置。 在 Android 上,插件会添加 ACCESS_NETWORK_STATE 到合并的清单中,一个正常的权限在安装时被授予。 iOS 不需要任何配置。

读取当前状态

import { Network } from '@capacitor/network';

const status = await Network.getStatus();
console.log(status.connected);      // true or false
console.log(status.connectionType); // 'wifi' | 'cellular' | 'none' | 'unknown'

在应用启动时调用它,决定是否从缓存或网络加载。它在几毫秒内返回,因为它读取操作系统状态,而不发送流量。

监听网络变化

import { Network, type ConnectionStatus } from '@capacitor/network';
import type { PluginListenerHandle } from '@capacitor/core';

let handle: PluginListenerHandle | undefined;

export async function watchNetwork(onChange: (s: ConnectionStatus) => void) {
  onChange(await Network.getStatus());
  handle = await Network.addListener('networkStatusChange', onChange);
}

export async function stopWatchingNetwork() {
  await handle?.remove();
}

两个实用细节:

  • 延迟事件。 切换到蜂窝网络时,两种平台可能会在新连接建立之前短暂地报告网络状态。为了避免闪烁,延迟1到2秒后再显示“离线”提示 banner。 none 移除监听器
  • 当组件卸载时,移除监听器,否则在热重载和导航后会多次调用回调函数。 React hook

React hook

import { useEffect, useState } from 'react';
import { Network, type ConnectionStatus } from '@capacitor/network';

export function useNetworkStatus() {
  const [status, setStatus] = useState<ConnectionStatus>({ connected: true, connectionType: 'unknown' });

  useEffect(() => {
    let timer: ReturnType<typeof setTimeout>;
    const listener = Network.addListener('networkStatusChange', (s) => {
      clearTimeout(timer);
      timer = setTimeout(() => setStatus(s), s.connected ? 0 : 1500);
    });
    Network.getStatus().then(setStatus);
    return () => {
      clearTimeout(timer);
      listener.then((l) => l.remove());
    };
  }, []);

  return status;
}

为什么“已连接”不等同于在线 BehaviorSubject.

源于操作系统网络堆栈。它保持真实状态的情况包括:

connected: true Wi-Fi网络有一个捕获门户(机场、酒店、火车)

  • 路由器没有上游连接
  • DNS已被破坏或过滤
  • 原因是操作系统网络堆栈。它保持真实状态的情况包括:
  • 公司防火墙或 VPN 阻止了您的 API 域名
  • 您的后端服务不可用

修复方法是对您控制的内容进行可达性检查:

export async function canReachApi(timeoutMs = 4000): Promise<boolean> {
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeoutMs);
  try {
    const res = await fetch('https://api.example.com/health', {
      method: 'HEAD',
      cache: 'no-store',
      signal: controller.signal,
    });
    return res.ok;
  } catch {
    return false;
  } finally {
    clearTimeout(timer);
  }
}

在应用启动时 networkStatusChange 报告 connected: true, 并在请求失败后。不要每几秒钟轮询一次,否则会耗尽电池和数据。确保健康端点允许您的应用的源站在 CORS 中 (capacitor://localhost 在 iOS 上 https://localhost 在 Android 上默认情况下),或使用 CapacitorHttp 从本机 code 发送它

通过网络诊断获得更丰富的状态

@capgo/capacitor-network-diagnostics 读取操作系统知道的更多内容,并可以在 WebView CORS 中绕过的本机检查:

bun add @capgo/capacitor-network-diagnostics
bunx cap sync
import { NetworkDiagnostics } from '@capgo/capacitor-network-diagnostics';

const status = await NetworkDiagnostics.getNetworkStatus();
// {
//   connected: true,
//   connectionType: 'wifi' | 'cellular' | 'ethernet' | 'vpn' | 'other' | 'unknown' | 'none',
//   internetReachable: true,
//   expensive: false,      // metered / cellular
//   constrained: false,    // iOS Low Data Mode
//   captivePortal: false,  // Android only
//   details: { ... }
// }

这些字段如何映射到操作系统:

Field Android iOS
internetReachable NET_CAPABILITY_VALIDATED (Android 检测到网络) 镜像 NWPathMonitor 路径状态
expensive isActiveNetworkMetered() NWPath.isExpensive
constrained 始终 false NWPath.isConstrained (低数据模式)
captivePortal NET_CAPABILITY_CAPTIVE_PORTAL 未报告
vpn 类型 是 是

在 Android 上 internetReachable 是因为 Android 系统已经测试了连接,所以信号很强。 connected在 iOS 上,它更接近于

所以对于关键流程,仍然需要 HTTP 检查。

const api = await NetworkDiagnostics.testUrl({
  url: 'https://api.example.com/health',
  method: 'HEAD',
  timeoutMs: 4000,
});
// api.reachable, api.statusCode, api.durationMs, api.errorCode

const socket = await NetworkDiagnostics.testWebSocket({ url: 'wss://realtime.example.com' });
const port = await NetworkDiagnostics.testPort({ host: 'mqtt.example.com', port: 8883 });

原生可达性检查

原生请求不受 CORS 影响,所以可以测试第三方主机。

一个支持“网络报告”屏幕

const report = await NetworkDiagnostics.runDiagnostics({
  urls: [{ url: 'https://api.example.com/health' }, { url: 'https://cdn.example.com/ping' }],
  websockets: [{ url: 'wss://realtime.example.com' }],
  download: { url: 'https://cdn.example.com/1mb.bin', maxBytes: 1_048_576 },
  packetLoss: { url: 'https://api.example.com/health', count: 5 },
});

console.log(report.issues);        // human-readable list of problems
console.log(report.download?.mbps);
console.log(report.packetLoss?.lossPercent);

当用户说“应用程序不工作”,一个一键诊断报告可以节省数小时的往返时间:

将 JSON 附加到支持票中。您会立即看到问题是否出在 DNS、阻塞的 WebSocket、捕获门户或慢速连接上。

适应计量和低数据模式连接

export async function shouldPrefetchMedia() {
  const s = await NetworkDiagnostics.getNetworkStatus();
  if (!s.connected) return false;
  if (s.constrained) return false; // user asked iOS to save data
  if (s.expensive) return false;   // cellular or metered Wi-Fi
  return true;
}

尊严数据限制是快速获得市场上昂贵移动数据的好评:

使用它来决定视频自动播放、图像质量、背景同步和大型下载。Android 上,用户可以标记一个 Wi-Fi 网络为计量网络,所以不要假设 Wi-Fi 是免费的。

一个小的横幅比失败的请求更清晰。使用上面的钩子:

export function OfflineBanner() {
  const { connected } = useNetworkStatus();
  if (connected) return null;
  return (
    <div role="status" aria-live="polite" className="offline-banner">
      You are offline. Changes will sync when you reconnect.
    </div>
  );
}

role="status" with aria-live="polite" 使屏幕阅读器宣布更改。对于框架特定的UI,请参见我们的指南到 在Vue、Angular和React中构建一个离线屏幕.

在离线时进行队列工作

检测仅是离线支持的一半。当状态变为离线时:

  1. Serve从本地存储读取。一个SQLite数据库,如 @capgo/capacitor-fast-sql 比 localStorage.
  2. 将用户操作写入一个带有时间戳和幂等性键的出箱表中。
  3. 在 networkStatusChange 连接时运行 canReachApi(),然后按照顺序清空出箱。
  4. 使用指数退避重试失败的请求,最大时间限制几分钟。

对于必须在应用程序关闭时存活的上传,应将它们交给一个本机上传器,而不是 fetch.

网络回退

@capacitor/network 也在浏览器中运行,基于 navigator.onLine 和 online 在 offline 事件。因此您的code在 bun run dev 和 connectionType 中有效,但 unknown 通常会 navigator.connection 在web上。Chrome的 effectiveType 在 saveData,Safari 不支持,所以将它们视为可选提示。

故障排除

iOS Simulator 上的监听器永远不会触发:模拟器共享 Mac 的网络。将 Mac 的 Wi-Fi 打开或在飞行模式下测试设备。

connectionType 在 VPN 上 unknown :官方插件仅报告和 wifi, cellular, none and unknown切换网络时应用会在一秒钟内显示离线状态 vpn and ethernet.

:请像上面所示那样延迟离线过渡。故障排除

设备上健康检查失败,但在浏览器中正常工作: CORS 允许 capacitor://localhost 并且 https://localhost, 或使用 NetworkDiagnostics.testUrl,它可以在本机运行

navigator.onLine 是 true,而插件显示离线: 信任插件。一些 Android WebViews 不可靠地更新 navigator.onLine 通过空中将离线修复

离线处理主要是 JavaScript:阈值、横幅、重试逻辑、缓存规则。使用

__CAPGO_KEEP_0__ Capgo 实时更新,您可以为每个用户在同一天调整这些设置。Capgo 在后台下载更新包并在下载失败时保留当前版本,因此,连接不佳的情况下,用户不会因为下载失败而留下半装的更新。 网络诊断文档 列出所有选项。

Live updates for Capacitor apps

When a web-layer bug is live, ship the fix through Capgo instead of waiting days for app store approval. Users get the update in the background while native changes stay in the normal review path.

最新博客

Capgo 为您提供创建真正专业的移动应用所需的最佳见解。