Skip to content

[Bug]: checkConnectivity() returns [ConnectivityResult.none] on Android when only VPN is active #3810

@rxvivek

Description

@rxvivek

Platform

android

Plugin

connectivity_plus

Version

6.1.5

Flutter SDK

3.14.0

Steps to reproduce

Bug Report: checkConnectivity() returns [ConnectivityResult.none] on Android when only VPN is active

Plugin

connectivity_plus

Version

6.1.5 (locked), constraint ^6.1.4

Platform

Android

Device

Samsung Galaxy A05s (SM-A057G/DSN), MediaTek Helio G85 chipset, One UI

Flutter SDK

3.24.0


Description

On Samsung Galaxy A05s, when the device is connected to the internet exclusively through a VPN (e.g., corporate VPN without a separate Wi-Fi/mobile data indicator), Connectivity().checkConnectivity() returns [ConnectivityResult.none] instead of [ConnectivityResult.vpn] or a list containing ConnectivityResult.vpn.

This causes the app to incorrectly determine that there is no network connectivity, even though the device has full internet access through the VPN tunnel.


Steps to Reproduce

  1. Use a Samsung Galaxy A05s (SM-A057G/DSN) running Android with One UI
  2. Connect to a VPN (corporate or third-party VPN app)
  3. Ensure internet is accessible through the VPN (verify by opening a browser)
  4. Call Connectivity().checkConnectivity()
  5. Observe the returned result

Expected Behavior

checkConnectivity() should return a list containing ConnectivityResult.vpn (and possibly the underlying transport like ConnectivityResult.wifi or ConnectivityResult.mobile).

For example:

[ConnectivityResult.vpn]
// or
[ConnectivityResult.vpn, ConnectivityResult.wifi]

Actual Behavior

checkConnectivity() returns:

[ConnectivityResult.none]

This happens despite the device having full internet access through the VPN.


Root Cause Analysis

The issue is in the Android native implementation of connectivity_plus. The plugin uses Android's ConnectivityManager.getNetworkCapabilities() on the activeNetwork to determine transport types. It checks for:

  • NetworkCapabilities.TRANSPORT_WIFIConnectivityResult.wifi
  • NetworkCapabilities.TRANSPORT_CELLULARConnectivityResult.mobile
  • NetworkCapabilities.TRANSPORT_VPNConnectivityResult.vpn
  • NetworkCapabilities.TRANSPORT_ETHERNETConnectivityResult.ethernet

However, on certain Android devices (particularly Samsung budget devices with MediaTek chipsets like the Galaxy A05s), the ConnectivityManager behaves differently when a VPN is active:

  1. activeNetwork may return null: Some Samsung devices with custom network stacks don't properly expose the VPN network as the active network, causing getNetworkCapabilities() to return null, which the plugin maps to ConnectivityResult.none.

  2. VPN transport not reported: On some devices, when a VPN is the sole active connection, getNetworkCapabilities() on the active network does not include TRANSPORT_VPN in the capabilities. This is a known Android platform behavior documented in multiple StackOverflow threads:

  3. Samsung One UI network stack quirks: Samsung's custom Android implementation on budget chipsets (MediaTek Helio G85 in the A05s) has known inconsistencies in how NetworkCapabilities are reported for VPN connections compared to stock Android or Qualcomm-based Samsung devices.


Impact

This is a critical issue for enterprise apps that rely on connectivity_plus to gate API calls. When the plugin incorrectly reports ConnectivityResult.none, the app:

  • Blocks all API calls thinking there is no internet
  • Shows "no internet" error dialogs to the user
  • Prevents data synchronization
  • Breaks first-time app setup flows that require server data

The plugin's own README states: "Connection type availability does not guarantee that there is an Internet access." However, the inverse is also problematic — the plugin reports NO connection when there IS internet access via VPN.


Workaround

We are currently working around this by performing an actual reachability check (using internet_connection_checker package) when connectivity_plus returns ConnectivityResult.none:

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';

class NetworkCheck {
  Future<bool> check() async {
    final List<ConnectivityResult> connectivityResult =
        await (Connectivity().checkConnectivity());
    if (connectivityResult.contains(ConnectivityResult.mobile)) {
      return true;
    } else if (connectivityResult.contains(ConnectivityResult.wifi)) {
      return true;
    } else if (connectivityResult.contains(ConnectivityResult.vpn)) {
      return true;
    } else if (connectivityResult.contains(ConnectivityResult.other)) {
      return true;
    } else if (connectivityResult.contains(ConnectivityResult.ethernet)) {
      return true;
    } else if (connectivityResult.contains(ConnectivityResult.none)) {
      // Fallback: actual reachability check for devices where VPN
      // is not properly reported by ConnectivityManager
      try {
        final hasConnection =
            await InternetConnectionChecker.createInstance(
              checkTimeout: const Duration(seconds: 5),
            ).hasConnection;
        return hasConnection;
      } catch (_) {
        return false;
      }
    }
    return false;
  }
}

Suggested Fix

The Android native implementation should consider iterating over all networks (not just activeNetwork) when activeNetwork returns null capabilities, or when the capabilities don't include any known transport type. Android's ConnectivityManager.getAllNetworks() can be used as a fallback:

// Pseudocode for suggested fix in the Android plugin
val activeNetwork = connectivityManager.activeNetwork
val capabilities = connectivityManager.getNetworkCapabilities(activeNetwork)

if (capabilities == null) {
    // Fallback: check all available networks
    val allNetworks = connectivityManager.allNetworks
    for (network in allNetworks) {
        val caps = connectivityManager.getNetworkCapabilities(network)
        if (caps != null && caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
            return listOf("vpn")
        }
    }
}

Alternatively, the plugin could check NET_CAPABILITY_INTERNET or NET_CAPABILITY_VALIDATED on available networks as a secondary signal.


Related Issues


Environment

Flutter 3.24.0
connectivity_plus: 6.1.5
Device: Samsung Galaxy A05s (SM-A057G/DSN)
Chipset: MediaTek Helio G85
Android Version: [fill in your exact Android version]
One UI Version: [fill in your One UI version]
VPN App Used: [fill in the VPN app name]

Checklist

  • I searched existing issues and couldn't find a duplicate for this specific Android VPN scenario
  • I read the README.md file of the plugin
  • I'm using the latest version of the plugin (6.1.5)
  • All dependencies are up to date
  • I did a flutter clean
  • I confirmed the device has internet access via browser while the bug occurs

Code Sample

Logs

.

Flutter Doctor

.

Checklist before submitting a bug

  • I searched issues in this repository and couldn't find such bug/problem
  • I Google'd a solution and I couldn't find it
  • I searched on StackOverflow for a solution and I couldn't find it
  • I read the README.md file of the plugin
  • I'm using the latest version of the plugin
  • All dependencies are up to date with flutter pub upgrade
  • I did a flutter clean
  • I tried running the example project

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingtriage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions