Send request over WiFi (without connection) even if Mobile data is ON (with connection) on Android M
Stanislav's answer is correct but incomplete because only works in Lollipop.
I've wrote a complete solution for Lollipop and Marshmallow onwards for you to route all network requests through WiFi when connected to a specific network of your choice.
Kotlin
In your Activity,
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class RoutingActivity : Activity() {
private var mConnectivityManager: ConnectivityManager? = null
private var mNetworkCallback: ConnectivityManager.NetworkCallback? = null
//...
override fun onCreate(savedInstanceState: Bundle?) {
//...
routeNetworkRequestsThroughWifi("Access-Point-SSID-You-Want-To-Route-Your-Requests")
}
Route future network requests from application through WiFi (even if given WiFi network is without internet and mobile data has internet connection)
/**
* This method sets a network callback that is listening for network changes and once is
* connected to the desired WiFi network with the given SSID it will bind to that network.
*
* Note: requires android.permission.INTERNET and android.permission.CHANGE_NETWORK_STATE in
* the manifest.
*
* @param ssid The name of the WiFi network you want to route your requests
*/
private fun routeNetworkRequestsThroughWifi(ssid: String) {
mConnectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
// ensure prior network callback is invalidated
unregisterNetworkCallback(mNetworkCallback)
// new NetworkRequest with WiFi transport type
val request = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build()
// network callback to listen for network changes
mNetworkCallback = object : ConnectivityManager.NetworkCallback() {
// on new network ready to use
override fun onAvailable(network: Network) {
if (getNetworkSsid(this@RoutingActivity).equals(ssid, ignoreCase = false)) {
releaseNetworkRoute()
createNetworkRoute(network)
} else {
releaseNetworkRoute()
}
}
}
mConnectivityManager?.requestNetwork(request, mNetworkCallback)
}
Unregister network callback
private fun unregisterNetworkCallback(networkCallback: ConnectivityManager.NetworkCallback?) {
if (networkCallback != null) {
try {
mConnectivityManager?.unregisterNetworkCallback(networkCallback)
} catch (ignore: Exception) {
} finally {
mNetworkCallback = null
}
}
}
Create network route
private fun createNetworkRoute(network: Network): Boolean? {
var processBoundToNetwork: Boolean? = false
when {
// 23 = Marshmallow
Build.VERSION.SDK_INT >= 23 -> {
processBoundToNetwork = mConnectivityManager?.bindProcessToNetwork(network)
}
// 21..22 = Lollipop
Build.VERSION.SDK_INT in 21..22 -> {
processBoundToNetwork = ConnectivityManager.setProcessDefaultNetwork(network)
}
}
return processBoundToNetwork
}
Release network route
private fun releaseNetworkRoute(): Boolean? {
var processBoundToNetwork: Boolean? = false
when {
// 23 = Marshmallow
Build.VERSION.SDK_INT >= 23 -> {
processBoundToNetwork = mConnectivityManager?.bindProcessToNetwork(null)
}
// 21..22 = Lollipop
Build.VERSION.SDK_INT in 21..22 -> {
processBoundToNetwork = ConnectivityManager.setProcessDefaultNetwork(null)
}
}
return processBoundToNetwork
}
Helper
private fun getNetworkSsid(context: Context?): String {
// WiFiManager must use application context (not activity context) otherwise a memory leak can occur
val mWifiManager = context?.applicationContext?.getSystemService(Context.WIFI_SERVICE) as WifiManager
val wifiInfo: WifiInfo? = mWifiManager.connectionInfo
if (wifiInfo?.supplicantState == SupplicantState.COMPLETED) {
return wifiInfo.ssid.removeSurrounding("\"")
}
return ""
}
Send data through wifi (no internet) when mobile data on
After a lot of research and time trying to understand it all I found out that this isn't possible in versions previous to Android 5.0 (Lollipop), the OS only keeps one network interface up at a time and the apps don't have control over this.
So to do this on versions greater or equal to the Lollipop I did the following:
- Before doing your socket connection check if android greater or equal to Lollipop, in case it isn't you just do whatever you have to do normally;
In case the version is equal or greater to Lollipop you need to do something like this:
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
final ConnectivityManager manager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder builder;
builder = new NetworkRequest.Builder();
//set the transport type do WIFI
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
manager.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
manager.bindProcessToNetwork(network);
} else {
//This method was deprecated in API level 23
ConnectivityManager.setProcessDefaultNetwork(network);
}
try {
//do a callback or something else to alert your code that it's ok to send the message through socket now
} catch (Exception e) {
e.printStackTrace();
}
manager.unregisterNetworkCallback(this);
}
});
}After you finish you should stop binding the process with this:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ConnectivityManager manager = (ConnectivityManager) InovePlugApplication.getContext()
.getSystemService(Context.CONNECTIVITY_SERVICE);
manager.bindProcessToNetwork(null);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ConnectivityManager.setProcessDefaultNetwork(null);
}
This answer helped me unsderstand how to do it https://stackoverflow.com/a/29837637/2550932.
Send request over Mobile data when WIFI is ON.(Android L)
Well finally found solution for this. Trick was to use capability as NET_CAPABILITY_INTERNET
. Which is same as startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, FEATURE_ENABLE_HIPRI);
See the Firmware design here
builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
After this I am able to get onAvailable
callback from system and later I set my process default network as mobile data.
Hence all the request goes over mobile data even if wifi is on. WOW!
Note: This was not working in initial releases of Preview L.
Edit 19-10-2015: setProcessDefaultNetwork is now depcreated use bindProcessToNetwork
Send a POST request only through WiFi interface
Since Android 5 (API 21), you can force connections to use the WiFi even if it's not the default network.
One solution is to find the corresponding network, for example with ConnectivityManager.getAllNetworks()
and ConnectivityManager.getNetworkInfo()
:
Once you have the Network
, you can either :
Open a connection on this network using
Network.openConnection()
.Bind the application to the network with
ConnectivityManager.setProcessDefaultNetwork
orConnectivityManager.bindProcessToNetwork()
(API 23+)
See Connecting your App to a Wi-Fi Device (especially Routing network requests) for more details.
Related Topics
Access_Coarse_Location Permission Gives a Cell Tower Precision on Android
Yuv to Rgb Conversion by Fragment Shader
Onserviceconnected Never Called After Bindservice Method
Android Sdk Content Loader Failing with Nullpointerexception
How to Display Images from a Specific Folder on Android Gallery
R.Java Disappears After Project Clean
How to Add Parameters to API (Http Post) Using Okhttp Library in Android
Back to Main Activity from Notification-Created Activity
Findfragmentbytag() Returns Null After Perform a Fragmenttransaction Using Replace() Method
Custom 'Keyboard' Built in an Application on Android
Android: Subscribe to Firebase Cloud Messaging(Fcm) Topic
How to Detect "Recent Apps" System Button Clicks (Honeycomb+)
How to Use Default Android Drawables
Proxy Which Requires Authentication with Android Emulator
Okhttp Library - Networkonmainthreadexception on Simple Post