omni_connectivity
Lightweight, platform-aware reachability / probe checker for Flutter (native + web). Check whether your app can reach the network or a specific service (TCP, TLS, HTTP/GraphQL/SOAP, Web fetch, or a custom native handshake ) with a tiny API and minimal dependencies.
Table of contents
- Why
omni_connectivity - Features
- Install
- Quick start
- Public API
- Probe examples (copy-paste)
- Web considerations & CORS
- Best practices
- Troubleshooting
- Contributing
- License
Why omni_connectivity
Many apps need more than a simple "is there any network" boolean. They need to know whether a specific service or protocol is reachable (TCP/TLS endpoint, HTTP/GraphQL endpoint, gRPC service, SOAP Endpoint, WebSocket, or custom native handshake). omni_connectivity is a tiny package designed to:
- Be platform-aware (native vs web).
- Keep dependencies minimal.
- Let you plug custom probes (FFI/MethodChannel/native code) for protocol-specific checks.
- Provide an ergonomic, static API that’s easy for developers to call anywhere.
Features
- Static API:
OmniConnectivity.*— easy to call from app code. - Flexible:
InternetCheckOption.customProbeaccepts anyFuture<bool>probe. strictmode: require all probes to succeed (or default: first success = connected).onStatusChangestream triggered byconnectivity_plusevents (used only as triggers; actual status relies on probes).
Install
Add to your plugin/app pubspec.yaml:
dependencies:
omni_connectivity: ^0.0.2
When packaging your plugin, add your omni_connectivity package and export lib/omni_connectivity.dart.
Quick start
import 'package:flutter/widgets.dart';
import 'package:omni_connectivity/omni_connectivity.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await OmniConnectivity.init(
options: [
// native-friendly TCP probe (Cloudflare)
InternetCheckOption.fromHostPort('1.1.1.1', 443),
// custom probe (native/FFI/MethodChannel)
InternetCheckOption(
uri: Uri.parse('custom://custom-service'),
customProbe: () => myCustomProbe(),
),
],
checkInterval: Duration(seconds: 8),
strict: false,
);
final ok = await OmniConnectivity.hasInternetAccess();
print('Has internet access: $ok');
OmniConnectivity.onStatusChange.listen((status) {
print('Connectivity changed: $status');
});
}
Public API
OmniConnectivity.init({ options, checkInterval, strict })
Initialize/override configuration. Optional; if not called, reasonable defaults are used.
options—List<InternetCheckOption>(probes to run).checkInterval—Durationbetween periodic checks.strict—bool(defaultfalse).
OmniConnectivity.hasInternetAccess() -> Future<bool>
Convenience one-liner returning true when at least one probe succeeded (or all succeeded if strict).
OmniConnectivity.checkOnce() -> Future<InternetStatus>
Runs the configured probes once and returns InternetStatus.connected or InternetStatus.disconnected.
OmniConnectivity.onStatusChange -> Stream<InternetStatus>
Subscribe to connectivity state changes.
OmniConnectivity.setIntervalAndResetTimer(Duration d)
Change polling interval and reset the timer.
OmniConnectivity.lastTryResults -> InternetStatus?
Last known status (or null if no checks have been run).
InternetCheckOption
Represents one probe:
class InternetCheckOption {
final Uri? uri;
final Duration timeout;
final Future<bool> Function()? customProbe;
const InternetCheckOption({ this.uri, this.timeout = const Duration(seconds: 3), this.customProbe });
factory InternetCheckOption.fromHostPort(String host, int port, { Duration timeout = const Duration(seconds: 3) }) => ...;
}
fromHostPort(host, port)is a convenience factory for native TCP probes.customProbeaccepts any async function returningbool— ideal for FFI/MethodChannel native handshakes , gRPC health RPCs, or application-layer checks.
Probe examples (copy-paste)
TCP probe (native)
import 'dart:io';
Future<bool> tcpProbe(String host, int port, { Duration timeout = const Duration(seconds: 2) }) async {
try {
final socket = await Socket.connect(host, port, timeout: timeout);
socket.destroy();
return true;
} catch (_) {
return false;
}
}
TLS probe (native)
import 'dart:io';
Future<bool> tlsProbe(String host, int port, { Duration timeout = const Duration(seconds: 3) }) async {
try {
final socket = await SecureSocket.connect(host, port, timeout: timeout, onBadCertificate: (_) => true);
socket.destroy();
return true;
} catch (_) {
return false;
}
}
HTTP HEAD probe (native, no http package)
import 'dart:io';
import 'dart:convert';
Future<bool> httpHeadProbe(Uri uri, { Duration timeout = const Duration(seconds: 3) }) async {
final client = HttpClient();
try {
client.connectionTimeout = timeout;
final req = await client.openUrl('HEAD', uri);
final resp = await req.close().timeout(timeout);
return resp.statusCode >= 200 && resp.statusCode < 400;
} catch (_) {
return false;
} finally {
client.close(force: true);
}
}
Fetch HEAD probe (web; CORS required)
// implemented inside web impl using package:web + dart:js_interop
Future<bool> fetchHeadProbe(String url, { Duration timeout = const Duration(seconds: 3) });
gRPC probe (when you already depend on grpc)
import 'package:grpc/grpc.dart';
Future<bool> grpcProbe(String host, int port, { Duration timeout = const Duration(seconds: 3) }) async {
final channel = ClientChannel(host, port: port, options: const ChannelOptions(credentials: ChannelCredentials.insecure()));
try {
await channel.getConnection().isReady.timeout(timeout);
await channel.shutdown();
return true;
} catch (_) {
try { await channel.shutdown(); } catch (_) {}
return false;
}
}
Other native handshakes (recommended: MethodChannel or FFI)
Future<bool> otherProbe() async {
// define any function that returns bool
}
Web considerations & CORS
- Browser probes use
fetchand are subject to CORS. The server must allow cross-origin HEAD/GET requests for probes to succeed from web builds. dart:iosockets are unavailable on web — web builds must usefetchor a custom web-friendly probe.- Prefer to probe endpoints you control (CORS-enabled) for reliable web behavior.
Best practices
- Keep probe timeouts short (1–3s) to avoid blocking UI.
- Use TCP/TLS probes for fast reachability checks (native).
- Use
customProbefor app-layer validation or protocol-specific handshakes. - Use
strict = trueonly when all endpoints are under your control. - Allow consumers of your plugin to override default endpoints (don’t hardcode public IPs as single source of truth).
Troubleshooting
- Web probes fail with CORS errors — ensure the endpoint returns
Access-Control-Allow-Origin: *(or your origin) and allows HEAD/GET. - Probe flaky on some networks — corporate or captive networks may block public DNS or certain IPs. Make endpoints configurable and prefer application-layer health endpoints you control.
Contributing
Contributions welcome!
Please open issues or PRs. Follow the existing style and add tests for new behaviors.
If you liked the package, then please give it a Like 👍🏼 and Star ⭐ on GitHub.
A final note
omni_connectivity is meant to be a small, focused plugin: a developer-friendly, cross-platform probe abstraction. It keeps the core dependency-free for protocol-specific checks and lets apps plug in the exact probe they need (TCP, HTTP, gRPC, any binary protocol you made).
