Is it possible to force a WebView
load an URL via a specified Network
?
My device has two network connections open: wifi and mobile data.
The mobile data network is set to be the default network for outgoing connections (so the connectivity manager returns the mobile data network for connectivityManager.getActiveNetwork()
).
The webpage that I'm trying to load (from http://10.0.0.1:80
) is running on a web server which is connected over wifi. So the web view fails to load to page because it's unavailable via mobile data.
So I dug a little bit more in this topic by myself and found some helpful information:
If a connection should use a given network, you need to bind the sockets manually to that network or directly create the sockets via a socket factory.
There is no possibility with the standard implementation of WebView
to set a socket factory or to let it use given sockets.
But it's possible to bind the complete app process to a network. This will ensure that from that moment on all newly created sockets will be bound to that network. (The original method to set a default network was deprecated at level 23, just have a look at the method bindProcessToNetwork()
in my code below.)
Multiple network connections are only possible for Android devices running API level 21 and higher.
The NetworkCallback
can be used to listen for any newly connected networks which fulfil a specified NetworkRequest
.
With this knowledge I was able to finally find a working solution:
ConnectionFragment.java
public class ConnectionFragment extends Fragment {
private static final String TAG = ConnectionFragment.class.getSimpleName();
private final NetworkCallback networkCallback = new NetworkCallback();
private ConnectivityManager connectivityManager;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
Log.v(TAG, "onCreate");
super.onCreate(savedInstanceState);
connectivityManager = (ConnectivityManager) getActivity().getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
}
@Override
public void onStart() {
Log.v(TAG, "onStart");
super.onStart();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
registerNetworkCallback();
}
}
@Override
public void onStop() {
Log.v(TAG, "onStop");
super.onStop();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
unregisterNetworkCallback();
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void registerNetworkCallback() {
Log.v(TAG, "registerNetworkCallback");
final NetworkRequest networkRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
connectivityManager.registerNetworkCallback(networkRequest, networkCallback);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void unregisterNetworkCallback() {
Log.v(TAG, "unregisterNetworkCallback");
connectivityManager.unregisterNetworkCallback(networkCallback);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private class NetworkCallback extends ConnectivityManager.NetworkCallback {
@Override
public void onAvailable(Network network) {
Log.v(TAG, "onAvailable");
bindProcessToNetwork(network);
}
@Override
public void onLost(Network network) {
Log.v(TAG, "onLost");
bindProcessToNetwork(null);
}
private void bindProcessToNetwork(final Network network) {
Log.v(TAG, "bindProcessToNetwork: " + network);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
connectivityManager.bindProcessToNetwork(network);
} else {
ConnectivityManager.setProcessDefaultNetwork(network);
}
}
}
}
I hope this will help someone.
But keep in mind: for all other connection relying on another network you need to configure the sockets manually.
Best regards,
winklerrr
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With