Custom OkHttpClientFactory to ensure IPv4 preference in order to fix hanging fetch requests.

This commit is contained in:
minibits-cash
2025-02-07 21:26:26 +01:00
parent 4a7955af31
commit 8a044a18fc
4 changed files with 105 additions and 9 deletions
+13 -9
View File
@@ -95,7 +95,7 @@ android {
applicationId "com.minibits_wallet"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 58024
versionCode 58025
versionName "0.2.0"
}
@@ -159,7 +159,7 @@ android {
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
defaultConfig.versionCode * 1000 + versionCodes.get(abi)
defaultConfig.versionCode * 1000 + versionCodes.get(abi)
}
}
@@ -177,14 +177,18 @@ dependencies {
implementation jscFlavor
}
// Fetch request hang issue
// define a BOM and its version
implementation(platform("com.squareup.okhttp3:okhttp-bom:5.0.0-alpha.12"))
// define any required OkHttp artifacts without version
// Minibits: Fetch requests hanging issue - not used for now, does not work with custom DNS selector IPV4_FIRST strategy
/* implementation(platform("com.squareup.okhttp3:okhttp-bom:5.0.0-alpha.12"))
implementation("com.squareup.okhttp3:okhttp")
implementation("com.squareup.okhttp3:logging-interceptor")
implementation("com.squareup.okhttp3:okhttp-urlconnection")
implementation("com.squareup.okhttp3:logging-interceptor")
configurations.all {
resolutionStrategy {
force "com.squareup.okhttp3:okhttp:5.0.0-alpha.12"
force "com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.12"
}
}*/
}
// code-push
@@ -0,0 +1,36 @@
package com.minibits_wallet
import android.util.Log
import com.facebook.react.modules.network.OkHttpClientProvider
import com.facebook.react.modules.network.OkHttpClientFactory
import okhttp3.OkHttp
import okhttp3.OkHttpClient
import okhttp3.EventListener
import okhttp3.Call
import java.net.InetSocketAddress
import java.net.Proxy
import java.util.concurrent.TimeUnit
class CorePlaneOkHttpClientFactory : OkHttpClientFactory {
override fun createNewNetworkModuleClient(): OkHttpClient {
val okHttpVersion = OkHttp.VERSION
Log.d("OkHttpFactory", "Using OkHttp version: $okHttpVersion")
return OkHttpClientProvider.createClientBuilder()
.dns(CorePlaneOkHttpDNSSelector(CorePlaneOkHttpDNSSelector.IPvMode.IPV4_FIRST))
/* .eventListener(object : EventListener() {
override fun connectStart(call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy) {
Log.d("OkHttpNetwork", "Connecting to ${inetSocketAddress.address}")
}
})
.addInterceptor { chain ->
val request = chain.request()
Log.d("OkHttpFactory", "Sending request: ${request.url}")
val response = chain.proceed(request)
Log.d("OkHttpFactory", "Received response: ${response.code} from ${response.request.url}")
response
} */
.connectTimeout(10, TimeUnit.SECONDS)
.build()
}
}
@@ -0,0 +1,52 @@
package com.minibits_wallet
import okhttp3.Dns
import java.net.Inet4Address
import java.net.Inet6Address
import java.net.InetAddress
import android.util.Log
class CorePlaneOkHttpDNSSelector(private val mode: IPvMode) : Dns {
enum class IPvMode(val code: String) {
SYSTEM("system"),
IPV6_FIRST("ipv6"),
IPV4_FIRST("ipv4"),
IPV6_ONLY("ipv6only"),
IPV4_ONLY("ipv4only");
companion object {
@JvmStatic
fun fromString(ipMode: String): IPvMode =
values().find { it.code == ipMode } ?: throw IllegalArgumentException("Unknown value: $ipMode")
}
}
override fun lookup(hostname: String): List<InetAddress> {
var addresses = try {
Dns.SYSTEM.lookup(hostname)
} catch (e: Exception) {
Log.e("OkHttpFactory", "DNS lookup failed for $hostname", e)
throw e
}
// Log the raw DNS result before filtering
// Log.d("OkHttpFactory", "Raw DNS lookup for $hostname -> ${addresses.joinToString(", ")}")
val sortedAddresses = when (mode) {
IPvMode.IPV6_FIRST -> addresses.sortedByDescending { it is Inet6Address } // IPv6 before IPv4
IPvMode.IPV4_FIRST -> addresses.sortedByDescending { it is Inet4Address } // IPv4 before IPv6
IPvMode.IPV6_ONLY -> addresses.filter { it is Inet6Address }
IPvMode.IPV4_ONLY -> addresses.filter { it is Inet4Address }
IPvMode.SYSTEM -> addresses
}
if (sortedAddresses.isEmpty()) {
throw RuntimeException("No resolved sortedAddresses for $hostname with mode $mode")
}
// Log.d("OkHttpFactory", "DNS lookup for $hostname -> ${sortedAddresses.joinToString(", ")}")
return sortedAddresses
}
}
@@ -11,6 +11,7 @@ import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.soloader.SoLoader
import com.facebook.react.modules.network.OkHttpClientProvider
import com.microsoft.codepush.react.CodePush
class MainApplication : Application(), ReactApplication {
@@ -45,6 +46,9 @@ class MainApplication : Application(), ReactApplication {
override fun onCreate() {
super.onCreate()
SoLoader.init(this, OpenSourceMergedSoMapping)
OkHttpClientProvider.setOkHttpClientFactory(CorePlaneOkHttpClientFactory())
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
load()