以编程方式连接到 Android Q 中的 Wifi

Eup*_*r08 15 android wifi android-wifi android-10.0

我有这个功能可以在 Wifi 网络中连接,在 Android 10 以下它工作正常,但是当我在 Android 10 上尝试时,我成功连接但没有互联网,我知道这是Android 10 中一个错误,但我发现这个应用程序可以连接从 Android 10 连接到 wifi 没有问题。我被屏蔽了好几天。

我的功能:

private void connectToWifi(String ssid, String password)
    {
        WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            try {
                Log.e(TAG,"connection wifi pre Q");
                WifiConfiguration wifiConfig = new WifiConfiguration();
                wifiConfig.SSID = "\"" + ssid + "\"";
                wifiConfig.preSharedKey = "\"" + password + "\"";
                int netId = wifiManager.addNetwork(wifiConfig);
                wifiManager.disconnect();
                wifiManager.enableNetwork(netId, true);
                wifiManager.reconnect();

            } catch ( Exception e) {
                e.printStackTrace();
            }
        } else {
            Log.e(TAG,"connection wifi  Q");

            WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier.Builder()
                .setSsid( ssid )
                .setWpa2Passphrase(password)
                    .build();

            NetworkRequest networkRequest = new NetworkRequest.Builder()
                    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                    .setNetworkSpecifier(wifiNetworkSpecifier)
                    .build();

             connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);


                 networkCallback = new ConnectivityManager.NetworkCallback() {
                @Override
                public void onAvailable(Network network) {
                    super.onAvailable(network);

                     connectivityManager.bindProcessToNetwork(network);
                    Log.e(TAG,"onAvailable");
                }

                  @Override
                  public void onLosing(@NonNull Network network, int maxMsToLive) {
                      super.onLosing(network, maxMsToLive);
                      Log.e(TAG,"onLosing");
                  }

                  @Override
                public void onLost(Network network) {
                    super.onLost(network);
                    Log.e(TAG, "losing active connection");
                }

                @Override
                public void onUnavailable() {
                    super.onUnavailable();
                    Log.e(TAG,"onUnavailable");
                }
            };
            connectivityManager.requestNetwork(networkRequest,networkCallback);


        }
    }
Run Code Online (Sandbox Code Playgroud)

Let*_*aus 10

到目前为止,在我测试过的大多数设备上,什么对我有用,有一个回退选项,至少可以停止可怕的“循环请求”并允许成功的手动连接

下面的代码是用 Kotlin 编写的,如果需要,请谷歌如何转换到 Java。

创建API >= 29 所需的NetworkCallback(之前不需要但可以使用)

val networkCallback = object : ConnectivityManager.NetworkCallback() {
    override fun onAvailable(network: Network) {
        super.onAvailable(network)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // To make sure that requests don't go over mobile data
            connectivityManager.bindProcessToNetwork(network)
        } else {
            connectivityManager.setProcessDefaultNetwork(network)
        }
    }

    override fun onLost(network: Network) {
        super.onLost(network)
        // This is to stop the looping request for OnePlus & Xiaomi models
        connectivityManager.bindProcessToNetwork(null)
        connectivityManager.unregisterNetworkCallback(networkCallback)
        // Here you can have a fallback option to show a 'Please connect manually' page with an Intent to the Wifi settings
    }
}
Run Code Online (Sandbox Code Playgroud)

连接到网络如下:

val wifiNetworkSpecifier = WifiNetworkSpecifier.Builder()
    .setSsid(ssid)
    .setWpa2Passphrase(pass)
    .build()

val networkRequest = NetworkRequest.Builder()
    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
// Add the below 2 lines if the network should have internet capabilities.
// Adding/removing other capabilities has made no known difference so far
//    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
//    .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
    .setNetworkSpecifier(wifiNetworkSpecifier)
    .build()

connectivityManager.requestNetwork(networkRequest, networkCallback)
Run Code Online (Sandbox Code Playgroud)

正如谷歌在此处所述,一些 OEM Roms 没有“坚持请求”,因此连接立即断开。OnePlus 在其后期的一些型号中解决了这个问题,但不是全部。对于某些 Android 版本上的某些手机型号,此错误将持续存在,因此需要成功回退(即没有网络中断的手动连接)。没有已知的解决方法可用,但如果找到,我会在这里更新它作为一个选项。

要删除网络,请执行以下操作:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    //This is required for Xiaomi models for disconnecting
    connectivityManager.bindProcessToNetwork(null)
} else {
    connectivityManager.setProcessDefaultNetwork(null)
}
connectivityManager.unregisterNetworkCallback(it)
Run Code Online (Sandbox Code Playgroud)

请记住,自动连接允许自动和手动断开连接。手动连接(例如建议的 OnePlus 设备后备)不允许自动断开连接。当涉及到物联网设备时,这也需要在应用程序中处理以获得更好的用户体验设计。

一些额外的小提示和信息:

  • 现在系统对话框打开,应用程序分别调用 onPause 和 onResume。这影响了我关于自动连接到物联网设备的逻辑。在某些情况下,onResume 在网络回调完成之前被调用。

  • 关于测试,我还不能仅使用 espresso 来绕过对话框,它可能会阻止一些在 API 29 之前工作的测试。使用其他框架(例如 uiautomator)可能是可能的。在我的情况下,我调整了测试,直到对话框显示,然后运行进一步的测试。使用 Intents.init() 不起作用。

  • 当找到网络时调用 onUnavailable,但用户取消。当未找到网络或用户在找到网络之前取消对话时不会调用它,在这种情况下没有调用其他方法,请使用 onResume 来捕获它。

  • 当它在 OnePlus 上失败时,它分别调用 onAvailable() -> onCapabilitiesChanged() -> onBlockedStatusChanged (blocked: false) -> onCapabilitiesChanged() -> onLost()

  • removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)不会帮助保持上万普拉斯的连接,说明这里

  • 设置BSSID不会帮助保持上万普拉斯的连接,说明这里

  • 谷歌不能帮助下,他们都表示这是他们手中的出来这里

  • OnePlus 论坛帖子确认更新后它适用于某些模型(但不是全部),请参见此处此处此处

  • GPS关闭时,网络的SSID名称不可用

  • 如果对话框多次出现,请检查您自己的活动生命周期,在我的情况下,某些模型在收到网络回调之前调用了 onResume。

  • 手动连接到没有互联网功能的网络需要用户确认以保持连接(有时以对话或通知的形式),如果忽略,系统将在不久之后与网络断开连接

测试设备列表:

  • Google Pixel 2 - 未发现任何问题
  • 三星 S10 SM-G970F - 未发现问题
  • 三星 S9 SM-G960F - 未发现问题
  • 一加 A5000 (OxegenOS 10.0.1) - 自动连接的主要问题
  • HTC One M8 (LineageOS 17.1) - 未发现问题
  • 小米米 Note 10 - 断开连接问题(已修复,请参阅代码示例)
  • 三星 A50 - 连接成功后重复出现对话框(有时)
  • 华为 Mate Pro 20 - 连接成功后重复出现对话框(有时)
  • 华为 P40 Lite - 不调用 onLost()
  • CAT S62 Pro - 未发现问题
  • Sony Xperia SZ2 - 未发现问题
  • 三星 Note10 - 未发现问题


Lex*_*bit 5

如果您想通过 INTERNET 连接到 WiFi,您应该使用这种NetworkRequest

NetworkRequest request = new NetworkRequest.Builder()
    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
    .setNetworkSpecifier(wifiNetworkSpecifier)
    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
    .build();
Run Code Online (Sandbox Code Playgroud)

此外,您需要为您的进程指定默认路由,以永久向连接的 WiFi AP 发出请求。只需将 next 方法的调用添加到onAvaliable下的NetworkCallback 中,如下所示:

networkCallback = new ConnectivityManager.NetworkCallback() {
    @Override
    public void onAvailable(Network network) {
        createNetworkRoute(network, connectivityManager);
        }
    };
    if (connectivityManager!= null) connectivityManager.requestNetwork(request, networkCallback);
Run Code Online (Sandbox Code Playgroud)

.

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private static void createNetworkRoute(Network network, ConnectivityManager connectivityManager) {
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
          connectivityManager.bindProcessToNetwork(network);
     } else {
          ConnectivityManager.setProcessDefaultNetwork(network);
     }
 } 
Run Code Online (Sandbox Code Playgroud)

不要忘记断开与绑定网络的连接:

connectivityManager.unregisterNetworkCallback(networkCallback);
Run Code Online (Sandbox Code Playgroud)

最后,您可以在WifiUtils等不同的库中找到最佳实践。


Eup*_*r08 0

所以,对我来说,解决方案是使用targetSdkVersion 28编译您的应用程序。要连接到 wifi,请使用此功能

connectToWifi(String ssid, String key)
Run Code Online (Sandbox Code Playgroud)

这只是暂时的解决方法,等待 Google 发布此错误的修复程序,有关向 Google 报告的问题的更多信息:issuetracker.google.com/issues/138335744

public void connectToWifi(String ssid, String key) {

Log.e(TAG, "connection wifi pre Q");
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = "\"" + ssid + "\"";
wifiConfig.preSharedKey = "\"" + key + "\"";
int netId = wifiManager.addNetwork(wifiConfig);
if (netId == -1) netId = getExistingNetworkId(wifiConfig.SSID);

    wifiManager.disconnect();
    wifiManager.enableNetwork(netId, true);
    wifiManager.reconnect();
}
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,自 2020 年 11 月起就不可能了 - “从 2020 年 11 月 2 日起,应用程序更新必须针对 Android 10(API 级别 29)或更高版本”,来自 [https://developer.android.com/distribute/best-practices/develop/target-sdk ](https://developer.android.com/distribute/best-practices/develop/target-sdk) (3认同)