Skip to content

Add targetHostIp option, support concurrent STA in Android #432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class ReactNativeBlobUtilConfig {
public ReadableMap addAndroidDownloads;
public Boolean trusty;
public Boolean wifiOnly = false;
public String targetHostIp;
public String key;
public String mime;
public Boolean auto;
Expand All @@ -32,6 +33,7 @@ class ReactNativeBlobUtilConfig {
this.appendExt = options.hasKey("appendExt") ? options.getString("appendExt") : "";
this.trusty = options.hasKey("trusty") && options.getBoolean("trusty");
this.wifiOnly = options.hasKey("wifiOnly") && options.getBoolean("wifiOnly");
this.targetHostIp = options.hasKey("targetHostIp") ? options.getString("targetHostIp") : "";
if (options.hasKey("addAndroidDownloads")) {
this.addAndroidDownloads = options.getMap("addAndroidDownloads");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.Uri;
import android.net.LinkProperties;
import android.net.LinkAddress;
import java.net.Inet4Address;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
Expand Down Expand Up @@ -388,33 +391,43 @@ else if (this.options.fileCache)

// wifi only, need ACCESS_NETWORK_STATE permission
// and API level >= 21
boolean targetHostIpAvailable = (this.options.targetHostIp != null && !this.options.targetHostIp.isEmpty());
if (this.options.wifiOnly) {

boolean found = false;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ConnectivityManager connectivityManager = (ConnectivityManager) ReactNativeBlobUtilImpl.RCTContext.getSystemService(ReactNativeBlobUtilImpl.RCTContext.CONNECTIVITY_SERVICE);
Network[] networks = connectivityManager.getAllNetworks();

Network selectedNetwork;

for (Network network : networks) {

NetworkInfo netInfo = connectivityManager.getNetworkInfo(network);
NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(network);

if (caps == null || netInfo == null) {
if (!isValidWifiNetwork(connectivityManager, network)) {
continue;
}

if (!netInfo.isConnected()) {
continue;
}
// if targetHostIpAvailable does not match, fallback to any wifi
if (targetHostIpAvailable) {
String targetHostIp = this.options.targetHostIp;

if (caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
if (networkMatchesTargetIp(connectivityManager, network, targetHostIp)) {
clientBuilder.proxy(Proxy.NO_PROXY);
clientBuilder.socketFactory(network.getSocketFactory());
found = true;
break;
}
}

// wifiOnly. selects the first interface with wifi transport
// if targetHostIp is available and it matches, this selection will be overriden
if (!found) {
clientBuilder.proxy(Proxy.NO_PROXY);
clientBuilder.socketFactory(network.getSocketFactory());
found = true;
break;

if (!targetHostIpAvailable) {
break;
}
}
}

Expand All @@ -423,10 +436,12 @@ else if (this.options.fileCache)
releaseTaskResource();
return;
}


} else {
ReactNativeBlobUtilUtils.emitWarningEvent("ReactNativeBlobUtil: wifiOnly was set, but SDK < 21. wifiOnly was ignored.");
ReactNativeBlobUtilUtils.emitWarningEvent("ReactNativeBlobUtil: wifiOnly or targetHostIp was set, but SDK < 21. wifiOnly was ignored.");
}
}
}

final Request.Builder builder = new Request.Builder();
try {
Expand Down Expand Up @@ -1011,4 +1026,50 @@ public static OkHttpClient.Builder enableTls12OnPreLollipop(OkHttpClient.Builder

return client;
}

/**
* Check if a network is a valid connected WiFi network
*/
private boolean isValidWifiNetwork(ConnectivityManager cm, Network network) {
NetworkInfo netInfo = cm.getNetworkInfo(network);
NetworkCapabilities caps = cm.getNetworkCapabilities(network);

if (caps == null || netInfo == null) {
return false;
}

if (!netInfo.isConnected()) {
return false;
}

return caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
}

/**
* Check if a network matches the target host IP address
*/
private boolean networkMatchesTargetIp(ConnectivityManager cm, Network network, String targetHostIp) {
LinkProperties lp = cm.getLinkProperties(network);
if (lp == null) return false;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// For Android R and above, use DHCP server address
Inet4Address dhcpServer = lp.getDhcpServerAddress();
if (dhcpServer != null && dhcpServer.getHostAddress().equals(targetHostIp)) {
return true;
}
}

// Always fall back to linkAddresses check
List<LinkAddress> linkAddresses = lp.getLinkAddresses();
if (linkAddresses != null && !linkAddresses.isEmpty()) {
for (LinkAddress la : linkAddresses) {
if (la.getAddress().getHostAddress().equals(targetHostIp)) {
return true;
}
}
}

return false;
}
}
Loading