Android自动从WiFi断开连接,没有互联网低于Android 10

eh57zj3b  于 2022-12-31  发布在  Android
关注(0)|答案(3)|浏览(402)

工作中的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
        }
    }

使用的权限:

<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" />

上面的代码在提供互联网连接的网络上运行良好,但在大多数情况下,在没有互联网连接的网络上运行失败。
当尝试连接到无法访问互联网的WiFi配置时,我们需要将应用的进程绑定到该网络,或将HTTP客户端配置为使用该网络的套接字工厂,否则系统将与该WiFi网络断开连接。
根据this guideline,bindProcessToNetwork已经被应用。但是无论是否使用bindToProcess()/通过套接字工厂路由流量,系统都与网络断开连接。它不允许与没有互联网的WiFi保持连接。这真的很令人惊讶,Android在限制网络连接之前从未考虑过物联网设备的用例。
当尝试连接到我的应用程序或系统设置应用程序或任何其他应用程序添加的WiFi网络时,系统日志显示:
第一个月
当应用程序尝试连接具有互联网的设备时,即使该网络是由其他应用程序添加的,也不会发生相同的错误。
因此,应用程序可以连接到之前的配置,尽管"权限不足",流量暂时通过这个网络路由。但几秒钟后,网络断开,系统尝试重新连接到其他支持互联网的网络。
在Moto G5 Plus,Android 8. 1. 0上测试,但我相信这是一个平台bug,而不是设备特定的。而且这个bug大多是从Android 7或其他东西引入的,因为它以前工作过。
我也报告了问题here。也提供了示例应用程序在这个问题。
这个问题有没有解决方案?安卓有没有付费支持的选项?
先谢了。

cuxqih21

cuxqih211#

你提到的问题可能不是因为你在Issuetracker上提供的代码。一旦我在我的设备(Android 9)中修复了这个问题,即使在完全撤销后,我也无法复制错误。我甚至尝试了设备重新启动,应用程序重新安装,甚至工厂重置。试试这个。
1.在设置--〉应用程序和权限中,测试应用程序请求一个位置权限。给予它一个权限。

  1. 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;
}
fdx2calv

fdx2calv2#

如果您的目标是在特定网络中使用您的代码,那么您可以转到您的接入点界面,只需将 * DHCP * 设置设置为静态,并为设备提供适当的IP。
更多信息请参见here
现在,如果您的目标网络是这样做,您无法访问他们的 * DHCP * 设置,根据link,您可以告诉您的设备保持连接到网络,无论它是否有互联网连接。

NetworkRequest.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    builder = new NetworkRequest.Builder();
    //set the transport type do WIFI
    builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
    connectivityManager.requestNetwork(builder.build(), new
                                 ConnectivityManager.NetworkCallback() {
        @Override
        public void onAvailable(Network network) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (Build.VERSION.RELEASE.equalsIgnoreCase("6.0")) {
                    if (!Settings.System.canWrite(mActivity)) {
                        Intent goToSettings = new  Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
                        goToSettings.setData(Uri.parse("package:" + 
                        mActivity.getPackageName()));
                        mActivity.startActivity(goToSettings);
                    }
                }
                connectivityManager.bindProcessToNetwork(null);
                if (mSsid.contains("my_iot_device-xxxxxxxxx"))
                    connectivityManager.bindProcessToNetwork(network);
                else {
                    //This method was deprecated in API level 23
                    ConnectivityManager.setProcessDefaultNetwork(null);
                    if (mSsid.contains("my_iot_device-xxxxxxxxx"))
                        ConnectivityManager.setProcessDefaultNetwork(network);
                }
                connectivityManager.unregisterNetworkCallback(this);
            }
        }
    });
}

此外,有时它是好的,让您的WiFi收音机唤醒,所以您需要举行它使用WiFiLock

//Create a wifi manager instance first
WifiManager mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
//and then create your wifiLock
WifiManager.WifiLock mWifiLock = mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "wifiLock");
if(!mWifiLock.isHeld())
        mWifiLock.acquire();

以后如果你想实现它

if(mWifiLock.isHeld())
        mWifiLock.release();

此代码帮助我保持连接到我的网络,即使它没有互联网接入。

vfhzx4xs

vfhzx4xs3#

替换:

  • connectivityManager.registerNetworkCallback链路

  • connectivityManager.requestNetwork链路

来自上述链接的requestNetwork相关文档:
只要此请求未完成,平台将尝试****维护匹配此请求的最佳网络,同时始终尝试将请求匹配到更好的网络(如果可能)。

    • 请注意,registerNetworkCallback不包括上述文档。**

Android连接堆栈将拆除未使用的网络。这通过requestNetwork对网络的请求数进行跟踪。作为registerNetworkCallback的一部分提交的请求不计入,因此就连接堆栈而言,您请求的Wi-Fi网络未被 * 请求 *,因此可以拆除。
这不适用于 * 默认 * 网络,但是只有具有互联网功能的网络才有资格成为默认网络,这不适用于您的情况。

相关问题