ユーザーのデバイスがインターネットに接続されているかどうかを監視・判定する方法を解説します。
簡単な UI 表示の切り替えであれば JavaScript の標準機能で十分ですが、実際に通信可能かどうかを厳密に判定するには Rust 側でのチェックが有効です。
方法 1: JavaScript 標準 API (簡易チェック)
Web 標準の navigator.onLine プロパティと online/offline イベントを使用します。
これは最も手軽な方法ですが、「ルーターに繋がっているが、インターネットには繋がっていない」場合でも true (Online) を返す という特性があります。
* 用途: UI の表示切り替え(「オフラインモードです」の表示など)
* 信頼性: 低(LANケーブルが刺さっているかどうかの判定に近い)
実装例
// ネットワーク状態の変化を監視する
function initConnectivityListener() {
const updateStatus = () => {
const isOnline = navigator.onLine;
console.log(isOnline ? '接続されました' : '切断されました');
};
window.addEventListener('online', updateStatus);
window.addEventListener('offline', updateStatus);
// 初期状態の反映
updateStatus();
}
// アプリ起動時などに呼び出す
// initConnectivityListener();
---
方法 2: Rust による疎通確認 (厳密なチェック)
「本当にインターネット上のサーバーにアクセスできるか」を知るためには、実際にパケットを飛ばしてみるのが確実です。
Rust 側で定期的に信頼できるエンドポイント(Google DNS 8.8.8.8 や Cloudflare 1.1.1.1、または自社サーバー)に対して接続試行を行います。
1. 依存関係 (src-tauri/Cargo.toml)
[dependencies]
# 特別な追加依存関係は不要ですが、HTTPでチェックしたい場合は reqwest が便利です
# ここでは標準ライブラリの TcpStream を使い軽量に実装します
2. Rust 実装 (src-tauri/src/lib.rs)
TcpStream::connect を使って、特定の IP アドレスのポート 53 (DNS) や 80 (HTTP) に接続できるかを確認するコマンドを作成します。
use tauri::command;
use std::net::TcpStream;
use std::time::Duration;
#[command]
async fn check_internet_connectivity() -> bool {
// Cloudflare Public DNS (1.1.1.1) のポート 53 に接続を試みる
// タイムアウトを短く設定 (例: 1500ms)
// ※ TCP接続を確立するだけで、実際のデータは送らない
let addr = "1.1.1.1:53";
let timeout = Duration::from_millis(1500);
// std::net::TcpStream を使う場合はブロッキングするため、
// 厳密には spawn_blocking するか、非同期版 (tokio::net::TcpStream) を使うのがベターです。
// ここでは Tokio 環境下でも動作しやすいよう、tokio::net::TcpStream を使う例にします
match tokio::net::TcpStream::connect(addr).await {
Ok(_) => true,
Err(_) => false,
}
}
// 登録関数
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![
check_internet_connectivity
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
3. JavaScript 実装
重要な操作(課金処理や同期処理など)の直前にこのコマンドを呼び出して確認します。
import { invoke } from '@tauri-apps/api/core';
async function performSensitiveAction(): Promise<void> {
// まずブラウザの判定でフィルタ
if (!navigator.onLine) {
alert('オフラインです。ネットワークを確認してください。');
return;
}
// 念のため実際に繋がるか確認
const hasInternet = await invoke<boolean>('check_internet_connectivity');
if (!hasInternet) {
alert('インターネット接続が確認できません。ファイアウォール等の設定を確認してください。');
return;
}
// 処理実行...
console.log('Action executed!');
}
---
方法 3: バックグラウンドでの定期監視
Rust 側で定期的にチェックを行い、状態が変化したタイミングでイベントを発行する実装です。
常に最新の接続状態を UI に反映させたい場合に有効です。
Rust 側 (src-tauri/src/lib.rs)
use tauri::{AppHandle, Emitter, Manager};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tokio::time::{sleep, Duration};
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.setup(|app| {
let app_handle = app.handle().clone();
// 現在の状態を保持
let is_online = Arc::new(AtomicBool::new(true)); // 初期値
tauri::async_runtime::spawn(async move {
loop {
// 5秒ごとにチェック
sleep(Duration::from_secs(5)).await;
// 接続確認 (非同期)
let current_status = tokio::net::TcpStream::connect("8.8.8.8:53").await.is_ok();
// 前回の状態と比較
let prev_status = is_online.load(Ordering::Relaxed);
if current_status != prev_status {
is_online.store(current_status, Ordering::Relaxed);
println!("Internet status changed: {}", current_status);
// イベント送信
let _ = app_handle.emit("network-status-changed", current_status);
}
}
});
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
JavaScript 側 (イベント受信)
import { listen } from '@tauri-apps/api/event';
async function startNetworkMonitor() {
console.log("ネットワーク監視を開始します...");
// イベントリスナーの登録
const unlisten = await listen<boolean>('network-status-changed', (event) => {
const isOnline = event.payload;
console.log(`詳細な接続状態が変更されました: ${isOnline ? 'Online' : 'Offline'}`);
if (!isOnline) {
console.warn("インターネット接続が失われました (Rust側判定)");
// ここでトースト通知などを表示する
} else {
console.info("インターネット接続が復帰しました");
}
});
// 監視を停止したい場合は unlisten() を呼び出します
// unlisten();
}
// 起動時に監視を開始
// startNetworkMonitor();