Send a request via WiFi (without connection), even if mobile data is turned on (with connection) on Android M

I need to send UDP packets to the WiFi module (with my own access point) without an Internet connection, but when I connect my mobile phone to the AP, Android redirects my packets to the mobile data transfer interface because it has an Internet connection.

I used the code below to do my job, but it doesn't seem to work on Android M.

@TargetApi(Build.VERSION_CODES.LOLLIPOP) private void setWifiInterfaceAsDefault() { ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkRequest.Builder builder = new NetworkRequest.Builder(); NetworkRequest networkRequest= builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .build(); connectivityManager.requestNetwork(networkRequest, new ConnectivityManager.NetworkCallback()); } 

I also added

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

on my AndroidManifest.xml, and I made sure Settings.System.canWrite(this) returns true , but still nothing.

Thanks in advance.

+10
source share
3 answers

Networking with ConnectivityManager.setProcessDefaultNetwork () prevents roaming and allows full TCP access. Thus, in the onAvailable () callback, you can bind the application process to this network, rather than opening a connection with a specific URL.

 ConnectivityManager connection_manager = (ConnectivityManager) activity.getApplication().getSystemService(Context.CONNECTIVITY_SERVICE); NetworkRequest.Builder request = new NetworkRequest.Builder(); request.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); connection_manager.registerNetworkCallback(request.build(), new NetworkCallback() { @Override public void onAvailable(Network network) { ConnectivityManager.setProcessDefaultNetwork(network); } } 

Original answer

+6
source

Stanislav's answer is correct, but incomplete, because it only works in Lollipop.

I wrote a complete solution for Lollipop and Marshmallow and so on, so that you can forward all network requests via WiFi when connected to a specific network of your choice.


Kotlin

In your business,

 @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") } 

Send future network requests from the application via WiFi (even if this WiFi network is not connected to the Internet, and mobile data is connected to the Internet)

 /** * 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 callback on the network

 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 } 

assistant

 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 "" } 
+6
source

Kotlin decision

 class ConnectWithoutInternetTest constructor( private val mContext: Context, private val connectivityManager: ConnectivityManager, private val wifiManager: WifiManager ) { private val mWifiBroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { when (intent.action) { WifiManager.NETWORK_STATE_CHANGED_ACTION -> { val info = intent.getParcelableExtra<NetworkInfo>(WifiManager.EXTRA_NETWORK_INFO) val isConnected = info.isConnected val ssid: String? = normalizeAndroidWifiSsid(wifiManager.connectionInfo?.ssid) if (isConnected) { val builder = NetworkRequest.Builder() builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI) connectivityManager.registerNetworkCallback( builder.build(), object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network) { super.onAvailable(network) val networkInfo = connectivityManager.getNetworkInfo(network) val networkSsid = networkInfo.extraInfo if (networkSsid == ssid) { connectivityManager.unregisterNetworkCallback(this) } } }) } } } } } private fun init() { val intentFilter = IntentFilter() intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION) mContext.registerReceiver(mWifiBroadcastReceiver, intentFilter) } private fun destroy() { mContext.unregisterReceiver(mWifiBroadcastReceiver) } private fun normalizeAndroidWifiSsid(ssid: String?): String? { return ssid?.replace("\"", "") ?: ssid } fun connectToWifi(ssidParam: String, password: String?) { init() val ssid = "\"$ssidParam\"" val config = wifiManager.configuredNetworks.find { it.SSID == ssid } val netId = if (config != null) { config.networkId } else { val wifiConfig = WifiConfiguration() wifiConfig.SSID = ssid password?.let { wifiConfig.preSharedKey = "\"$password\"" } wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE) wifiManager.addNetwork(wifiConfig) } wifiManager.disconnect() val successful = wifiManager.enableNetwork(netId, true) } 
0
source

Source: https://habr.com/ru/post/1247233/


All Articles