在 Android 10 以下没有互联网的情况下,Android 会自动与 WiFi 断开连接

Khu*_*hah 12 android wifi wifimanager android-wifi android-8.0-oreo

正在开发一个 android 应用程序,我需要在其中以编程方式连接没有互联网的 WiFi 设备。这是一个代码:

    private void connectToWiFi(final String ssid, String password) {

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {

            WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
            final ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

            NetworkRequest.Builder request = new NetworkRequest.Builder();
            request.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
            request.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); // Internet not required

            ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {

                @Override
                public void onAvailable(Network network) {

                    String networkSSID = getNetworkSsid();

                    if (networkSSID.equals(ssid)) {
                        connectivityManager.bindProcessToNetwork(network);
                    }
                }

                @Override
                public void onUnavailable() {
                    super.onUnavailable();
                }

                @Override
                public void onLost(@NonNull Network network) {
                    super.onLost(network);
                }
            };
            connectivityManager.registerNetworkCallback(request.build(), networkCallback);

            WifiConfiguration config = new WifiConfiguration();
            config.SSID = String.format("\"%s\"", ssid);

            int netId = -1;
            List<WifiConfiguration> apList = wifiManager.getConfiguredNetworks();

            for (WifiConfiguration i : apList) {

                if (i.SSID != null && i.SSID.equals("\"" + ssid + "\"")) {
                    netId = i.networkId;
                }
            }

            // Add network in Saves network list if it is not available in list
            if (netId == -1) {

                if (TextUtils.isEmpty(password)) {
                    Log.d(TAG, "====== Connect to open network");
                    config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
                } else {
                    Log.d(TAG, "====== Connect to secure network");
                    config.preSharedKey = String.format("\"%s\"", password);
                }

                netId = wifiManager.addNetwork(config);
            }

            Log.d(TAG, "Connect to Network : " + netId);
            wifiManager.enableNetwork(netId, true);

        } else {

            // For Android 10 and above
            // WifiNetworkSpecifier code
        }
    }
Run Code Online (Sandbox Code Playgroud)

使用的权限:

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Run Code Online (Sandbox Code Playgroud)

以上代码适用于提供互联网连接的网络。但是对于没有互联网连接的网络,它在大多数情况下都会失败。

当尝试连接到没有互联网访问权限的 WiFi 配置时,我们需要将应用程序的进程绑定到该网络,或者将我们的 HTTP 客户端配置为使用该网络的套接字工厂,否则系统将与该 WiFi 网络断开连接。

根据本指南,bindProcessToNetwork 已被应用。但是,无论使用 bindToProcess() 还是通过套接字工厂路由流量,系统都会断开网络连接。它不允许与没有互联网的 WiFi 保持连接。真是令人惊讶,在限制网络连接之前,Android 从未考虑过物联网设备用例。

当尝试连接到由我的应用程序或系统设置应用程序或任何其他应用程序添加的 WiFi 网络时,系统日志显示:

UID xxxxx does not have permission to update configuration

当应用程序尝试连接具有互联网的设备时,即使该网络是由其他应用程序添加的,也不会发生相同的错误。

因此,该应用程序可以连接到先前的配置,尽管“权限不足”,并且流量会暂时通过该网络进行路由。但几秒钟后,网络断开连接,系统尝试与其他启用 Internet 的网络重新关联。

在 Moto G5 Plus、Android 8.1.0 上测试,但我相信这是一个平台错误,而不是特定于设备。大多数情况下,这个错误是从 Android 7 或其他东西引入的,因为它以前可以工作。

我也在这里报告了问题。本期还提供了示例应用程序。

是否有针对此问题的解决方案?Android 是否有任何付费支持选项?

提前致谢。

Nil*_*ari 0

您提到的问题可能不是因为您在 Issuetracker 上提供的代码造成的。一旦我修复了我的设备(Android 9)中的问题,即使在完全撤消之后,我也无法复制该错误。我什至尝试过设备重启、应用程序重新安装甚至恢复出厂设置。尝试这个。

  1. 在设置 --> 应用程序和权限中,测试应用程序请求位置权限。给它许可。

  2. Java代码可以是

    private void connectToWiFi(final String ssid, String password) {
    
    if (connectivityManager != null) {
    
        try {
            connectivityManager.bindProcessToNetwork(null);
            connectivityManager.unregisterNetworkCallback(networkCallback);
        } catch (Exception e) {
            Log.d(TAG, "Connectivity Manager is already unregistered");
        }
    }
    
    NetworkRequest.Builder request = new NetworkRequest.Builder();
    request.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
    if(isOnline()==false){
        request.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
    }
    
    networkCallback = new ConnectivityManager.NetworkCallback() {
    
        @Override
        public void onAvailable(Network network) {
    
            String networkSSID = getNetworkSsid();
            Log.e(TAG, "Network is available - " + networkSSID);
    
            if (networkSSID.equals(ssid)) {
                if(isOnline()==false){
                    Log.e(TAG, "bindProcessToNetwork");
                    connectivityManager.bindProcessToNetwork(network);
                }
            }
        }
    
        @Override
        public void onUnavailable() {
            super.onUnavailable();
            Log.e(TAG, "Network is Unavailable");
        }
    
        @Override
        public void onLost(@NonNull Network network) {
            super.onLost(network);
            Log.e(TAG, "Lost Network Connection");
        }
    };
    
    connectivityManager.registerNetworkCallback(request.build(), networkCallback);
    
    if (!wifiManager.isWifiEnabled()) {
        wifiManager.setWifiEnabled(true);
    }
    
    WifiConfiguration config = new WifiConfiguration();
    config.SSID = String.format("\"%s\"", ssid);
    config.status = WifiConfiguration.Status.ENABLED;
    
    int netId = -1;
    List<WifiConfiguration> apList = wifiManager.getConfiguredNetworks();
    Log.d(TAG, "List Size : " + apList.size());
    
    for (WifiConfiguration i : apList) {
    
        if (i.SSID != null && i.SSID.equals("\"" + ssid + "\"")) {
            netId = i.networkId;
        }
    }
    
    // Add network in Saves network list if it is not available in list
    if (netId == -1) {
    
        if (TextUtils.isEmpty(password)) {
            Log.e(TAG, "====== Connect to open network");
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
        } else {
            Log.e(TAG, "====== Connect to secure network");
            config.preSharedKey = String.format("\"%s\"", password);
        }
    
        netId = wifiManager.addNetwork(config);
    }
    
    Log.d(TAG, "Connect to network : " + netId);
    wifiManager.enableNetwork(netId, true);
    
    }
    
    public boolean isOnline() {
    Runtime runtime = Runtime.getRuntime();
    try {
        Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8");
        int     exitValue = ipProcess.waitFor();
        return (exitValue == 0);
    }
    catch (IOException e)          { e.printStackTrace(); }
    catch (InterruptedException e) { e.printStackTrace(); }
    
    return false;
    }
    
    Run Code Online (Sandbox Code Playgroud)