Android Q, programmatically connect to different WiFi AP for internet
Solution 1
Try calling bindProcessToNetwork() in onAvailable() callback to regain network connectivity, it works fine for me.
Connect to network:
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);
Disconnect from the bound network:
cm.unregisterNetworkCallback(networkCallback);
Solution 2
WifiNetworkSuggestion API is used to suggest the user about joining an AP(System will post a notification for user to join)
Use WifiNetworkSpecifier to send your requests. Use the network object provided in 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);
}
};
After you are done using the Wifi access point do
connectivityManager.unregisterNetworkCallback(networkCallback);
From Google's Issue tracker by Google's Engineer:
The network suggestions API flow requires the user to approve the app (platform posts a notification to ask user for approval). Once the app is approved, the platform will consider all networks from the app in future auto-connection attempts. But, this API does not give you guarantees on when the device will connect to your AP for provisioning. So, WifiNetworkSuggestion is not the right API surface for the provided use-case (peer to peer instant connectivity).
Using WifiNetworkSpecifier establishes a local connection to the wifi access point as mentioned above. The default network will still be cellular in this case (we don't disrupt other app's internet connectivity). The app making the request should use the multi-network API's to route their traffic over the established connection. The |Network| object provided in the onAvailable() callback for the request is the handle that app needs to use for opening sockets over that local network (Look at https://developer.android.com/reference/android/net/Network.html#bindSocket(java.net.DatagramSocket) and other such API's available in the |Network| object surface.
Hope this helps.
Solution 3
As stated here, Android 10 made it intentionally so that the WifiNetworkSpecifier prevents actual internet connectivity. It is meant for peer to peer connections.
The WifiNetworkSuggestion API, however, provides internet connectivity and behaves similarly to the WifiNetworkSpecifier API. As long as the device is not currently connected to any Wifi network, the WifiNetworkSuggestion API will automatically connect to the specified network. The first time a device uses it, a notification will appear asking if the app can suggest networks. The user must accept this notification for the WifiNetworkSuggestion API to work.
I found that Android's provided code in the WifiNetworkSuggestion documentation had a few compile errors. Here is the code that I found to work:
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);
Comments
-
Vinodh about 2 years
As in Android Q, several WiFi APIs are restricted. I am trying to use alternate APIs to connect to different Wifi AP for internet.
Below is my code :
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);
This allows me to connect but Internet is disabled. This is working as defined in Android docs.
Alternate way i tried is below :
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);
declared permission in Manifest :
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
Using this didn't change anything in behavior.
Please let know sequence of APIs to connect successfully to different Wifi AP with internet capability.
-
Anand Khinvasara almost 5 yearsThere is an open ticket with google regarding this. I would recommend you guys to comment and voice over this ticket as it would help get google's attention. issuetracker.google.com/issues/138335744
-
Vinodh almost 5 years@AnandKhinvasara : As, These APIs are not giving internet capability. I am displaying a popup for user to go to settings and connect to AP manually. Hope, this alternate way can work for your usecase.
-
Anand Khinvasara almost 5 yearsI know but its not a good solution. Google should fix it.
-
Vinodh almost 5 years@AnandKhinvasara : Agreed.
-
Anand Khinvasara almost 5 yearsI got it to work. Please check my answer.
-
Anand Khinvasara almost 5 yearsDid that work for you?
-
R.singh over 2 years@AnandKhinvasara Did that work for you? Where is your answer?
-
-
Vinodh almost 5 yearsDoes it work on the connections established using WifiNetworkSpecifier ?
-
Vinodh almost 5 yearsThanks for your reply. But, I see network suggestions is not providing internet capability. Do you have any alternate work around for this ?
-
Anand Khinvasara almost 5 yearsFor me status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS is always true. Thus I cant make it work
-
Aristide13 over 4 yearsWith this code, I get the authorization window with the right AP ... but when I press connect it does not work. Obtaining ip address then reconnection to the normal network. An idea ? Thank you
-
Russell C. about 4 yearsHi, @Anand Khinvasara, would you be able to post the full code for this? I'm having a lot of problems with no internet when connecting programmatically. Thanks!
-
Faizan Mir about 4 yearsOk So I have tried the WifiNetworkSpecifier ... I have this issue that when a network is selected the device wont connect to the network ,I have tried the documentation code too , is there a solution for local networks without internet connection
-
Inception almost 4 yearsDoes that mean I am forced to use WiFiNetworkSuggestion to connect to WiFi and actually use the internet? I am able to connect to WiFi using WiFiNetworkSpecifier but no actual internet access.
-
Russell C. almost 4 yearsYes, you will need to use WifiNetworkSuggestion. WifiNetworkSpecifier is meant for if you want to connect to a network for some purpose other than internet access.
-
Sergiy Belozorov about 3 yearsSaved my day! Thanks a bunch.
-
mono about 2 yearsThis answer does not solve the problem This connection method does not have access to the Internet
-
FABiO about 2 yearsYou saved my day, thanks of lot! Regards!