Skip to content

Commit 440c2f3

Browse files
authored
Merge pull request #432 from davidalo/add-targethostip-option
Add targetHostIp option, support concurrent STA in Android
2 parents 3e247b5 + bdfb24f commit 440c2f3

File tree

3 files changed

+957
-889
lines changed

3 files changed

+957
-889
lines changed

android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class ReactNativeBlobUtilConfig {
1414
public ReadableMap addAndroidDownloads;
1515
public Boolean trusty;
1616
public Boolean wifiOnly = false;
17+
public String targetHostIp;
1718
public String key;
1819
public String mime;
1920
public Boolean auto;
@@ -32,6 +33,7 @@ class ReactNativeBlobUtilConfig {
3233
this.appendExt = options.hasKey("appendExt") ? options.getString("appendExt") : "";
3334
this.trusty = options.hasKey("trusty") && options.getBoolean("trusty");
3435
this.wifiOnly = options.hasKey("wifiOnly") && options.getBoolean("wifiOnly");
36+
this.targetHostIp = options.hasKey("targetHostIp") ? options.getString("targetHostIp") : "";
3537
if (options.hasKey("addAndroidDownloads")) {
3638
this.addAndroidDownloads = options.getMap("addAndroidDownloads");
3739
}

android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java

Lines changed: 74 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
import android.net.NetworkCapabilities;
1212
import android.net.NetworkInfo;
1313
import android.net.Uri;
14+
import android.net.LinkProperties;
15+
import android.net.LinkAddress;
16+
import java.net.Inet4Address;
1417
import android.os.Build;
1518
import android.os.Bundle;
1619
import android.os.Environment;
@@ -388,33 +391,43 @@ else if (this.options.fileCache)
388391

389392
// wifi only, need ACCESS_NETWORK_STATE permission
390393
// and API level >= 21
394+
boolean targetHostIpAvailable = (this.options.targetHostIp != null && !this.options.targetHostIp.isEmpty());
391395
if (this.options.wifiOnly) {
392-
393396
boolean found = false;
394397

395398
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
396399
ConnectivityManager connectivityManager = (ConnectivityManager) ReactNativeBlobUtilImpl.RCTContext.getSystemService(ReactNativeBlobUtilImpl.RCTContext.CONNECTIVITY_SERVICE);
397400
Network[] networks = connectivityManager.getAllNetworks();
398-
401+
Network selectedNetwork;
402+
399403
for (Network network : networks) {
400404

401-
NetworkInfo netInfo = connectivityManager.getNetworkInfo(network);
402-
NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(network);
403-
404-
if (caps == null || netInfo == null) {
405+
if (!isValidWifiNetwork(connectivityManager, network)) {
405406
continue;
406407
}
407408

408-
if (!netInfo.isConnected()) {
409-
continue;
410-
}
409+
// if targetHostIpAvailable does not match, fallback to any wifi
410+
if (targetHostIpAvailable) {
411+
String targetHostIp = this.options.targetHostIp;
411412

412-
if (caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
413+
if (networkMatchesTargetIp(connectivityManager, network, targetHostIp)) {
414+
clientBuilder.proxy(Proxy.NO_PROXY);
415+
clientBuilder.socketFactory(network.getSocketFactory());
416+
found = true;
417+
break;
418+
}
419+
}
420+
421+
// wifiOnly. selects the first interface with wifi transport
422+
// if targetHostIp is available and it matches, this selection will be overriden
423+
if (!found) {
413424
clientBuilder.proxy(Proxy.NO_PROXY);
414425
clientBuilder.socketFactory(network.getSocketFactory());
415426
found = true;
416-
break;
417427

428+
if (!targetHostIpAvailable) {
429+
break;
430+
}
418431
}
419432
}
420433

@@ -423,10 +436,12 @@ else if (this.options.fileCache)
423436
releaseTaskResource();
424437
return;
425438
}
439+
440+
426441
} else {
427-
ReactNativeBlobUtilUtils.emitWarningEvent("ReactNativeBlobUtil: wifiOnly was set, but SDK < 21. wifiOnly was ignored.");
442+
ReactNativeBlobUtilUtils.emitWarningEvent("ReactNativeBlobUtil: wifiOnly or targetHostIp was set, but SDK < 21. wifiOnly was ignored.");
428443
}
429-
}
444+
}
430445

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

10121027
return client;
10131028
}
1029+
1030+
/**
1031+
* Check if a network is a valid connected WiFi network
1032+
*/
1033+
private boolean isValidWifiNetwork(ConnectivityManager cm, Network network) {
1034+
NetworkInfo netInfo = cm.getNetworkInfo(network);
1035+
NetworkCapabilities caps = cm.getNetworkCapabilities(network);
1036+
1037+
if (caps == null || netInfo == null) {
1038+
return false;
1039+
}
1040+
1041+
if (!netInfo.isConnected()) {
1042+
return false;
1043+
}
1044+
1045+
return caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
1046+
}
1047+
1048+
/**
1049+
* Check if a network matches the target host IP address
1050+
*/
1051+
private boolean networkMatchesTargetIp(ConnectivityManager cm, Network network, String targetHostIp) {
1052+
LinkProperties lp = cm.getLinkProperties(network);
1053+
if (lp == null) return false;
1054+
1055+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
1056+
// For Android R and above, use DHCP server address
1057+
Inet4Address dhcpServer = lp.getDhcpServerAddress();
1058+
if (dhcpServer != null && dhcpServer.getHostAddress().equals(targetHostIp)) {
1059+
return true;
1060+
}
1061+
}
1062+
1063+
// Always fall back to linkAddresses check
1064+
List<LinkAddress> linkAddresses = lp.getLinkAddresses();
1065+
if (linkAddresses != null && !linkAddresses.isEmpty()) {
1066+
for (LinkAddress la : linkAddresses) {
1067+
if (la.getAddress().getHostAddress().equals(targetHostIp)) {
1068+
return true;
1069+
}
1070+
}
1071+
}
1072+
1073+
return false;
1074+
}
10141075
}

0 commit comments

Comments
 (0)