Langsung ke konten utama

Cara Mendeteksi Status Jaringan di Aplikasi Capacitor

Deteksi status jaringan di aplikasi Capacitor: baca status online/offline, pantau perubahan, verifikasi akses internet sebenarnya, dan tangani jaringan metered.

Mendeteksi status jaringan online dan offline di aplikasi mobile Capacitor

Untuk mendeteksi status jaringan di aplikasi Capacitor, instal @capacitor/network, panggil Network.getStatus() untuk status saat ini, dan subscribe ke networkStatusChange untuk update. Ini memberi tahu apakah perangkat punya koneksi dan apakah itu Wi-Fi atau seluler. Untuk tahu apakah internet benar-benar berfungsi, atau apakah koneksinya berkuota, tambahkan pengecekan reachability atau @capgo/capacitor-network-diagnostics. Panduan ini membahas ketiga lapisan tersebut dengan Capacitor 8 code.

Tiga pertanyaan di balik “apakah user sedang online?”

Pertanyaan API Catatan
Apakah ada interface jaringan yang aktif? Network.getStatus().connected Cepat, event-driven, tapi tidak memberi info soal akses internet
Jenis koneksi apa yang digunakan? connectionType wifi, cellular, none, unknown in the official plugin
Apakah internet benar-benar berfungsi? Cek HTTP atau internetReachable Butuh request atau validasi OS
Haruskah saya menghindari download besar? expensive, constrained Jaringan berkuota dan iOS Low Data Mode

Kebanyakan bug offline muncul karena menganggap baris pertama sebagai baris ketiga. Wi-Fi hotel dengan halaman login melaporkan connected: true sementara setiap panggilan API mengalami timeout.

Pasang plugin Network

bun add @capacitor/network
bunx cap sync

Tidak perlu konfigurasi. Di Android, plugin ini menambahkan ACCESS_NETWORK_STATE ke merged manifest, izin normal yang diberikan saat instalasi. iOS tidak butuh apa-apa.

Baca status saat ini

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'

Panggil saat app start sebelum memutuskan mau load dari cache atau network. Hasilnya kembali dalam beberapa milidetik karena hanya membaca state OS, tidak mengirim traffic.

Pantau perubahan jaringan

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();
}

Dua detail praktis:

  • Debounce event-nya. Saat beralih dari Wi-Fi ke seluler, kedua platform bisa saja melaporkan none sebelum link baru aktif. Debounce 1–2 detik sebelum menampilkan banner “offline” menghindari flicker.
  • Hapus listeners saat komponen unmount, atau callback akan berjalan beberapa kali setelah hot reload dan navigasi.

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;
}

Status online diterapkan segera, status offline menunggu 1,5 detik. Pola yang sama berfungsi sebagai composable Vue atau service Angular dengan BehaviorSubject.

Mengapa “connected” tidak berarti online

connected: true berasal dari stack jaringan OS. Nilai ini tetap true ketika:

  • jaringan Wi-Fi memiliki captive portal (bandara, hotel, kereta)
  • router tidak memiliki koneksi upstream
  • DNS rusak atau difilter
  • firewall perusahaan atau VPN memblokir domain API Anda
  • backend Anda sendiri sedang down

Solusinya adalah pengecekan reachability ke sesuatu yang Anda kontrol:

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);
  }
}

Jalankan saat app start, ketika networkStatusChange laporan connected: true, dan setelah request gagal. Jangan poll setiap beberapa detik, itu menguras baterai dan data. Pastikan health endpoint mengizinkan origin app Anda di CORS (capacitor://localhost di iOS, https://localhost di Android secara default), atau gunakan CapacitorHttp untuk mengirimnya dari native code.

Dapatkan status lebih lengkap dengan diagnostik jaringan

@capgo/capacitor-network-diagnostics membaca lebih banyak informasi yang diketahui OS dan dapat menjalankan pemeriksaan native yang melewati CORS WebView:

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: { ... }
// }

Bagaimana field-field ini dipetakan ke OS:

Kolom Android iOS
internetReachable NET_CAPABILITY_VALIDATED (Android memeriksa internet) Mencerminkan NWPathMonitor status path
expensive isActiveNetworkMetered() NWPath.isExpensive
constrained Selalu false NWPath.isConstrained (Mode Data Rendah)
captivePortal NET_CAPABILITY_CAPTIVE_PORTAL Tidak dilaporkan
vpn tipe Ya Ya

Di Android, internetReachable adalah sinyal yang kuat karena OS sudah menguji koneksinya. Pada iOS, ini lebih mendekati connected, jadi tetap gunakan pengecekan HTTP untuk alur kritis.

Pengecekan reachability native

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 });

Request native tidak terkena CORS, jadi Anda juga bisa menguji host pihak ketiga.

Layar “network report” untuk support

Saat user bilang “aplikasinya tidak jalan”, laporan diagnostik sekali tap bisa menghemat berjam-jam komunikasi bolak-balik:

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);

Lampirkan JSON ke tiket support. Anda akan langsung tahu apakah masalahnya ada di DNS, WebSocket yang diblokir, captive portal, atau koneksi lambat.

Beradaptasi dengan koneksi metered dan Low Data Mode

Menghormati limit data adalah cara cepat mendapat review bagus di pasar dengan kuota mahal:

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;
}

Gunakan ini untuk menentukan autoplay video, kualitas gambar, background sync, dan download besar. Di Android, user bisa menandai Wi-Fi sebagai metered, jadi jangan berasumsi Wi-Fi selalu gratis.

Buat banner offline

Banner kecil lebih jelas daripada request yang gagal. Dengan hook di atas:

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" dengan aria-live="polite" membuat screen reader mengumumkan perubahan. Untuk UI spesifik framework, lihat panduan kami tentang membangun layar offline di Vue, Angular, dan React.

Antrekan pekerjaan saat offline

Deteksi hanyalah separuh dari dukungan offline. Saat status berubah menjadi offline:

  1. Serve bacaan dari local storage. Database SQLite seperti @capgo/capacitor-fast-sql menangani dataset besar lebih baik daripada localStorage.
  2. Tulis aksi pengguna ke tabel outbox dengan timestamp dan idempotency key.
  3. Di networkStatusChange ke connected, jalankan canReachApi(), lalu flush outbox secara berurutan.
  4. Ulangi permintaan yang gagal dengan exponential backoff, dibatasi beberapa menit.

Untuk upload yang harus tetap berjalan saat aplikasi ditutup, serahkan prosesnya ke native uploader alih-alih fetch.

Fallback web

@capacitor/network juga berjalan di browser, di mana ia berbasis pada navigator.onLine dan online dan offline events. Artinya code Anda berfungsi di bun run dev dan di PWA tanpa perubahan, tetapi connectionType sering kali akan unknown di web. Chrome memiliki navigator.connection menyediakan effectiveType dan saveData, Safari tidak, jadi perlakukan sebagai petunjuk opsional.

Pemecahan Masalah

Listener tidak pernah memicu di iOS Simulator: simulator berbagi jaringan Mac. Aktifkan/nonaktifkan Wi-Fi di Mac atau uji di perangkat dengan mode pesawat.

connectionType adalah unknown di VPN: plugin resmi hanya melaporkan wifi, cellular, none dan unknown. Gunakan plugin diagnostik, yang mengembalikan vpn dan ethernet.

Aplikasi menampilkan status offline selama satu detik saat beralih jaringan: debounce transisi offline seperti yang ditunjukkan di atas.

Health check gagal di perangkat tetapi berfungsi di browser: CORS. Izinkan capacitor://localhost dan https://localhost, atau gunakan NetworkDiagnostics.testUrl, yang berjalan secara native.

navigator.onLine bernilai true saat plugin menyatakan offline: percaya pada plugin. Beberapa Android WebView tidak memperbarui navigator.onLine secara andal.

Kirim perbaikan offline over the air

Penanganan offline sebagian besar adalah JavaScript: ambang batas, banner, logika retry, aturan cache. Dengan Live updates Capgo, Anda dapat menyesuaikan semuanya untuk setiap pengguna pada hari yang sama. Capgo mengunduh bundle update di latar belakang dan mempertahankan versi saat ini jika unduhan gagal, sehingga koneksi buruk tidak pernah meninggalkan pengguna dengan update yang setengah terpasang. dokumen diagnostik jaringan menampilkan semua opsi.

Live updates untuk aplikasi Capacitor

Saat bug web-layer sudah live, kirim perbaikannya lewat Capgo alih-alih menunggu berhari-hari untuk persetujuan app store. Pengguna mendapat update di background, sementara perubahan native tetap mengikuti jalur review normal.

Terbaru dari Blog kami

Capgo memberikan insight terbaik yang Anda butuhkan untuk membuat aplikasi mobile yang benar-benar profesional.