17

与 Android Q 一样,一些 WiFi API 受到限制。我正在尝试使用备用 API 连接到不同的 Wifi AP 进行互联网。

下面是我的代码:

    WifiNetworkSpecifier.Builder builder = new WifiNetworkSpecifier.Builder();
    builder.setSsid("wifi-ap-ssid");
    builder.setWpa2Passphrase("wifi-ap-password");

    WifiNetworkSpecifier wifiNetworkSpecifier = builder.build();

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

    NetworkRequest nr = networkRequestBuilder1.build();
    ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    cm.requestNetwork(nr, callback);

这允许我连接,但 Internet 被禁用。这是按照 Android 文档中的定义工作的。

我尝试的替代方法如下:

    WifiNetworkSuggestion.Builder wifiNetworkSuggestionBuilder1 = new WifiNetworkSuggestion.Builder();
    wifiNetworkSuggestionBuilder1.setSsid("wifi-ap-ssid");
    wifiNetworkSuggestionBuilder1.setWpa2Passphrase("wifi-ap-password");
    WifiNetworkSuggestion wifiNetworkSuggestion = wifiNetworkSuggestionBuilder1.build();
    List<WifiNetworkSuggestion> list = new ArrayList<>();
    list.add(wifiNetworkSuggestion);
    wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
    wifiManager.removeNetworkSuggestions(new ArrayList<WifiNetworkSuggestion>());
    wifiManager.addNetworkSuggestions(list);

Manifest 中声明的许可:

<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>

使用它并没有改变任何行为。

请告知 API 序列以成功连接到具有互联网功能的不同 Wifi AP。

4

5 回答 5

9

尝试在 onAvailable() 回调中调用 bindProcessToNetwork() 以重新获得网络连接,它对我来说很好。

连接到网络:

    WifiNetworkSpecifier.Builder builder = new WifiNetworkSpecifier.Builder();
    builder.setSsid("wifi-ap-ssid");
    builder.setWpa2Passphrase("wifi-ap-password");

    WifiNetworkSpecifier wifiNetworkSpecifier = builder.build();

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

    NetworkRequest nr = networkRequestBuilder1.build();
    ConnectivityManager cm = (ConnectivityManager)
            context.getSystemService(Context.CONNECTIVITY_SERVICE);
    ConnectivityManager.NetworkCallback networkCallback = new 
        ConnectivityManager.NetworkCallback() {
        @Override
        public void onAvailable(Network network) {
            super.onAvailable(network);
            Log.d(TAG, "onAvailable:" + network);
            cm.bindProcessToNetwork(network);
        }
    });
    cm.requestNetwork(nr, networkCallback);

断开绑定网络:

cm.unregisterNetworkCallback(networkCallback);
于 2019-11-20T06:01:29.540 回答
3

WifiNetworkSuggestion API用于建议用户加入AP(系统会发布通知用户加入)

使用 WifiNetworkSpecifier 发送您的请求。使用 onAvailable() 中提供的网络对象。

WifiNetworkSpecifier.Builder builder = new WifiNetworkSpecifier.Builder();
builder.setSsid("wifi-ap-ssid");
builder.setWpa2Passphrase("wifi-ap-password");

WifiNetworkSpecifier wifiNetworkSpecifier = builder.build();

NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
networkRequestBuilder1.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
networkRequestBuilder1.setNetworkSpecifier(wifiNetworkSpecifier);

NetworkRequest networkRequest = networkRequestBuilder.build();
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
cm.requestNetwork(networkRequest, networkCallback);
networkCallback = new ConnectivityManager.NetworkCallback() {
            @Override
            public void onAvailable(@NonNull Network network) {
                //Use this network object to Send request. 
                //eg - Using OkHttp library to create a service request
                 //Service is an OkHttp interface where we define docs. Please read OkHttp docs
                 Service service = null;

                 OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder();
                okHttpBuilder.socketFactory(network.getSocketFactory());

                service = new Retrofit.Builder()                                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                        .addConverterFactory(GsonConverterFactory.create(gson))
                         .client(okHttpBuilder.build())
                         .build()
                         .create(Service.class);


               Observable<Object> observable = null;
               try {
                  if (service != null) {
                     observable = service.yourRestCall();
                  }
                  Subscriber<Object> sub = new Subscriber< Object >() {
                     @Override
                     public void onError(Throwable e) {
                        //Do on error
                     }

                     @Override
                     public void onNext(Object logs) {
                        //Do on next
                     }
                  };
                 if(observable != null) {
                     observable.subscribeOn(Schedulers.io())
                                          .observeOn(AndroidSchedulers.mainThread()).subscribe(sub);
                 }

                super.onAvailable(network);
            }
        };

使用 Wifi 接入点完成后,请执行

connectivityManager.unregisterNetworkCallback(networkCallback);

来自 Google工程师的 Google问题跟踪器:

网络建议 API 流程需要用户批准应用程序(平台发布通知请求用户批准)。一旦应用程序获得批准,平台将在未来的自动连接尝试中考虑应用程序中的所有网络。但是,此 API 不能保证设备何时连接到您的 AP 进行配置。因此,WifiNetworkSuggestion 不是所提供用例(点对点即时连接)的正确 API 界面。

如上所述,使用 WifiNetworkSpecifier 建立到 wifi 接入点的本地连接。在这种情况下,默认网络仍将是蜂窝网络(我们不会中断其他应用程序的互联网连接)。发出请求的应用程序应使用多网络 API 通过已建立的连接路由其流量。|网络| 在请求的 onAvailable() 回调中提供的对象是应用程序需要用于在该本地网络上打开套接字的句柄(查看https://developer.android.com/reference/android/net/Network.html#bindSocket (java.net.DatagramSocket)和其他此类 API 在 |Network| 对象表面中可用。

希望这可以帮助。

于 2019-08-09T15:03:19.783 回答
2

如此处所述,Android 10 故意这样做是为了让 WifiNetworkSpecifier 阻止实际的互联网连接。它用于点对点连接。

但是,WifiNetworkSuggestion API 提供 Internet 连接,其行为类似于 WifiNetworkSpecifier API。只要设备当前没有连接到任何 Wifi 网络,WifiNetworkSuggestion API 就会自动连接到指定的网络。设备第一次使用它时,会出现一条通知,询问该应用程序是否可以建议网络。用户必须接受此通知,WifiNetworkSuggestion API 才能工作。

我发现 WifiNetworkSuggestion 文档中 Android 提供的代码有一些编译错误。这是我发现工作的代码:

final WifiNetworkSuggestion suggestion1 = new WifiNetworkSuggestion.Builder()
.setSsid("SSID here")
.setWpa2Passphrase("password here")
.setIsAppInteractionRequired(true) // Optional (Needs location permission)
.build();

// Optional extra suggesstion, you can delete this or add more
final WifiNetworkSuggestion suggestion2 = new WifiNetworkSuggestion.Builder()
.setSsid("SSID here 2")
.setWpa2Passphrase("password here 2")
.setIsAppInteractionRequired(true) // Optional (Needs location permission)
.build();

final List<WifiNetworkSuggestion> suggestionsList = new ArrayList<WifiNetworkSuggestion>();
suggestionsList.add(suggestion1);
suggestionsList.add(suggestion2); // Optional extra suggestion
final WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
final int status = wifiManager.addNetworkSuggestions(suggestionsList);

if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
     // Error handling
}

final IntentFilter intentFilter = new IntentFilter(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION);

final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
    @Override public void onReceive(Context context, Intent intent) {
        if (!intent.getAction().equals(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)) {
              return;
        }
        // Post connection
    }
};
getApplicationContext().registerReceiver(broadcastReceiver, intentFilter);
于 2020-04-18T00:41:01.987 回答
0

onAvailable(Network)回调中ConnectivityManager.NetworkCallback()(在您设置WifiNetworkSpecifier.Builder()and之后NetworkRequest.Builder()),调用ConnectivityManager.bindProcessNetwork以将您的流量引导到连接的网络上,如NetworkAPI 中所述:https ://developer.android.com/reference/android/net/Network

标识网络。这通过 ConnectivityManager.NetworkCallback 提供给应用程序,以响应主动 ConnectivityManager#requestNetwork 或被动 ConnectivityManager#registerNetworkCallback 调用。它用于将流量引导到给定的网络,或者通过目标 SocketFactory 以 Socket 为基础,或者通过 ConnectivityManager#bindProcessToNetwork 在进程范围内引导流量。

....
private inner class MyCallback : ConnectivityManager.NetworkCallback() {
    override fun onAvailable(network: Network) {
        // Call this method once this callback is triggered after
        // your call to mConnectivityManager.requestNetwork()
        mConnectivityManager.bindProcessToNetwork(network)
    }
    ....
}
....
于 2020-08-10T01:02:06.480 回答
0

您应该在 Q 中使用Wi-Fi 网络建议 API

final WifiNetworkSuggestion suggestion1 =
  new WifiNetworkSuggestion.Builder()
  .setSsid("test111111")
  .setIsAppInteractionRequired() // Optional (Needs location permission)
  .build()

final WifiNetworkSuggestion suggestion2 =
  new WifiNetworkSuggestion.Builder()
  .setSsid("test222222")
  .setWpa2Passphrase("test123456")
  .setIsAppInteractionRequired() // Optional (Needs location permission)
  .build()

final WifiNetworkSuggestion suggestion3 =
  new WifiNetworkSuggestion.Builder()
  .setSsid("test333333")
  .setWpa3Passphrase("test6789")
  .setIsAppInteractionRequired() // Optional (Needs location permission)
  .build()

final List<WifiNetworkSuggestion> suggestionsList =
  new ArrayList<WifiNetworkSuggestion> {{
    add(suggestion1);
    add(suggestion2);
    add(suggestion3);
  }};

final WifiManager wifiManager =
  (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

final int status = wifiManager.addNetworkSuggestions(suggestionsList);
if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
// do error handling here…
}

// Optional (Wait for post connection broadcast to one of your suggestions)
final IntentFilter intentFilter =
  new IntentFilter(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION);

final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
    if (!intent.getAction().equals(
      WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)) {
      return;
    }
    // do post connect processing here..
  }
};
context.registerReceiver(broadcastReceiver, intentFilter);
于 2019-07-16T02:26:16.523 回答