Put the function in ViewModel
or Singleton
.
- The only way to get public ip seems to be via external website returning the client's connectiong ip address.
import kotlinx.coroutines.channels.awaitCloseimport kotlinx.coroutines.flow.callbackFlowimport kotlinx.coroutines.flow.catchimport kotlinx.coroutines.flow.flowimport okhttp3.*import okhttp3.Request.Builderimport java.io.IOExceptionclass Util { companion object { /* fun getIpv4HostAddress(): String? { try { NetworkInterface.getNetworkInterfaces()?.toList()?.map { networkInterface -> networkInterface.inetAddresses?.toList()?.find { !it.isLoopbackAddress && it is Inet4Address }?.let { return it.hostAddress } } return null } catch (e: Exception) { return null } } */ /* fun getPublicIp(): String? { val urls = listOf("https://ifcfg.me/", "https://icanhazip.com/") for (url in urls) { try { val ipAddress = getHttpRaw(url) if (ipAddress != null) return ipAddress } catch (e: Exception) { Timber.e("getPublicIp: $url") throw e } } return null } */ fun getHttpRawFlow(url: String) = callbackFlow { val client = OkHttpClient() val request: Request = Builder() .url(url) .build() client.newCall(request).enqueue(object : Callback { override fun onFailure(call: Call, e: IOException) { close(e) } override fun onResponse(call: Call, response: Response) { response.use { if (!response.isSuccessful) close(IOException("Unexpected code $response")) // close(Exception("TEST")) trySend(response.body!!.string()) } } }) awaitClose { } } val getPublicIpFlow = flow { val urls = listOf("https://ifcfg.me/", "https://icanhazip.com/") for (url in urls) { getHttpRawFlow(url) .catch { Timber.e(it, "getHttpRawFlow=$url") } .collect { emit(it) } } } }}
NOTE: OkHttp is required.
Usage
val ipAddress by Util.getPublicIpFlow.collectAsState(initial = null)