vpn_connection_detector 2.0.1
vpn_connection_detector: ^2.0.1 copied to clipboard
VPN connection detection for Flutter with native iOS & Android support. Includes real-time status stream & one-time checks.
VPN Connection Detector #
The most accurate VPN detection package for Flutter — with native iOS & Android implementations that detect both system-configured VPNs and third-party VPN apps like NordVPN, ExpressVPN, ProtonVPN, and more.
Why This Package? #
Most VPN detection solutions only check for system-configured VPNs, missing the majority of users who use third-party VPN apps. This package uses platform-native APIs to detect VPNs with ~95% accuracy:
- 🔍 Detects third-party VPN apps (NordVPN, ExpressVPN, Surfshark, ProtonVPN, etc.)
- 🔍 Detects system-configured VPNs (IKEv2, IPSec, WireGuard profiles)
- 🔍 Detects corporate VPNs (Cisco AnyConnect, OpenVPN, etc.)
- ⚡ Real-time monitoring with stream-based updates
- 🎯 No false positives from system network interfaces
Features #
- ✅ Native iOS detection using
NEVPNManagerandNWPathMonitor - ✅ Native Android detection using
NetworkCapabilities.TRANSPORT_VPN - ✅ Dart fallback for desktop platforms (macOS, Windows, Linux)
- ✅ Real-time streaming of VPN connection status changes
- ✅ One-time checks via static method
- ✅ Detailed VPN info including interface name and protocol
- ✅ Singleton pattern for efficient resource management
Platform Support #
| Platform | Native | Accuracy | Notes |
|---|---|---|---|
| iOS | ✅ | ~95% | Uses NEVPNManager & NWPathMonitor |
| Android | ✅ | ~95% | Uses NetworkCapabilities API |
| macOS | ❌ | ~70-80% | Dart fallback (interface name matching) |
| Windows | ❌ | ~70-80% | Dart fallback |
| Linux | ❌ | ~70-80% | Dart fallback |
Getting Started #
Installation #
Add vpn_connection_detector to your pubspec.yaml:
dependencies:
vpn_connection_detector: ^2.0.1
Android Setup #
Add the following permission to your AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
iOS Setup #
No additional setup required. The plugin uses system frameworks that are available by default.
Usage #
Import the package #
import 'package:vpn_connection_detector/vpn_connection_detector.dart';
One-time VPN Check #
// Check if VPN is currently active
bool isVpnConnected = await VpnConnectionDetector.isVpnActive();
if (isVpnConnected) {
print('VPN is connected');
} else {
print('VPN is not connected');
}
Real-time VPN Status Stream #
final vpnDetector = VpnConnectionDetector();
// Listen to VPN status changes
vpnDetector.vpnConnectionStream.listen((state) {
switch (state) {
case VpnConnectionState.connected:
print('VPN connected');
break;
case VpnConnectionState.disconnected:
print('VPN disconnected');
break;
}
});
// Don't forget to dispose when done
vpnDetector.dispose();
Get Detailed VPN Information #
final info = await VpnConnectionDetector.getVpnInfo();
if (info != null && info.isConnected) {
print('VPN Connected');
print('Interface: ${info.interfaceName}'); // e.g., 'utun3', 'tun0'
print('Protocol: ${info.vpnProtocol}'); // e.g., 'WireGuard', 'IKEv2'
}
Access Current Cached State #
final vpnDetector = VpnConnectionDetector();
// Get the last known state (may be null if not yet determined)
final currentState = vpnDetector.currentState;
print('Current state: ${currentState?.name ?? "unknown"}');
API Reference #
VpnConnectionDetector #
| Method/Property | Type | Description |
|---|---|---|
isVpnActive() |
static Future<bool> |
One-time check if VPN is active |
getVpnInfo() |
static Future<VpnInfo?> |
Get detailed VPN information |
vpnConnectionStream |
Stream<VpnConnectionState> |
Real-time status stream |
currentState |
VpnConnectionState? |
Last known VPN state |
dispose() |
void |
Clean up resources |
VpnConnectionState #
enum VpnConnectionState {
connected, // VPN is currently connected
disconnected, // VPN is currently disconnected
}
VpnInfo #
class VpnInfo {
final bool isConnected; // Whether VPN is connected
final String? interfaceName; // Network interface name (e.g., 'utun3')
final String? vpnProtocol; // Detected VPN protocol (e.g., 'WireGuard')
}
Example #
See the example directory for a complete sample app.
import 'package:flutter/material.dart';
import 'package:vpn_connection_detector/vpn_connection_detector.dart';
class VpnStatusWidget extends StatelessWidget {
final _vpnDetector = VpnConnectionDetector();
@override
Widget build(BuildContext context) {
return StreamBuilder<VpnConnectionState>(
stream: _vpnDetector.vpnConnectionStream,
builder: (context, snapshot) {
final isConnected = snapshot.data == VpnConnectionState.connected;
return Icon(
isConnected ? Icons.vpn_lock : Icons.vpn_lock_outlined,
color: isConnected ? Colors.green : Colors.grey,
);
},
);
}
}
Migration from v1.x #
Version 2.0 introduces native platform support with a cleaner API:
// v1.x (still works)
final isActive = await VpnConnectionDetector.isVpnActive();
final detector = VpnConnectionDetector();
detector.vpnConnectionStream.listen((state) { ... });
// v2.0 (new features)
final info = await VpnConnectionDetector.getVpnInfo();
print('Protocol: ${info?.vpnProtocol}');
Breaking changes:
- Minimum iOS version: 12.0
- Minimum Android SDK: 21
- Removed web platform support (not possible to detect VPN in browsers)
How It Works #
iOS #
- System VPNs: Uses
NEVPNManagerto check for active system-configured VPN profiles (IKEv2, IPSec, etc.) - Third-party VPN apps: Uses
CFNetworkCopySystemProxySettingsto inspect the__SCOPED__dictionary, which only contains active VPN network interfaces — this reliably detects apps like NordVPN, ExpressVPN, ProtonVPN, Surfshark, etc. - Real-time monitoring: Uses
NWPathMonitorto detect network changes and re-evaluate VPN status
Android #
Uses ConnectivityManager with NetworkCapabilities.TRANSPORT_VPN for accurate VPN detection on API 23+. This detects all VPN connections regardless of the VPN app used.
Desktop (Fallback) #
Inspects network interface names for common VPN patterns (tun, tap, ppp, wireguard, etc.).
Contributing #
Contributions are welcome! Please feel free to submit issues, feature requests, or pull requests.
License #
This project is licensed under the MIT License - see the LICENSE file for details.