Android Q,以编程方式连接到不同的WiFi AP进行互联网连接

时间:2019-07-01 06:41:53

标签: android android-wifi android-developer-api android-connectivitymanager androidq

与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);

这使我可以连接,但互联网已禁用。它正在按照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);

已在清单中声明为许可:

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

使用此操作不会改变任何行为。

请告知API顺序,以成功连接到具有Internet功能的其他Wifi AP。

5 个答案:

答案 0 :(得分:2)

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 Issue跟踪器:

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

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

希望这会有所帮助。

答案 1 :(得分:1)

here所述,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);

答案 2 :(得分:0)

您应该在Q中使用Wi-Fi network suggestion API

test %>%
  filter((lead(`fruit`) != `fruit`)| is.na(lead(`fruit`)) ) %>%
  select(-temp) %>%
  mutate(mean_temp = c(91,101,94.8,92,92,101))

答案 3 :(得分:0)

尝试在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);

答案 4 :(得分:0)

onAvailable(Network)上的ConnectivityManager.NetworkCallback()回调中(设置WifiNetworkSpecifier.Builder()NetworkRequest.Builder()之后),调用ConnectivityManager.bindProcessNetwork来将流量定向到连接的网络上,如Network API中所述:https://developer.android.com/reference/android/net/Network

标识网络。响应于主动ConnectivityManager#requestNetwork或被动ConnectivityManager#registerNetworkCallback调用,通过ConnectivityManager.NetworkCallback将其提供给应用程序。它用于将流量定向到给定的网络,既可以通过目标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)
    }
    ....
}
....