一、最稳方案:请求公开 IP 接口
权限(AndroidManifest.xml)
<uses-permission android:name="android.permission.INTERNET" />
Kotlin 代码(协程版)
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.net.URL
/** 获取公网IP */
suspend fun getPublicIp(): String = withContext(Dispatchers.IO) {
try {
// 常用接口,任选一个
val ip = URL("https://api.ipify.org").readText()
// val ip = URL("https://icanhazip.com").readText()
ip
} catch (e: Exception) {
e.toString()
}
}lifecycleScope.launch {
val ip = getPublicIp()
Log.d("PublicIP", ip)
}遇到的 java.net.ConnectException 是典型的网络连接失败问题,api.ipify.org 虽然稳定,但会受网络环境(如代理、防火墙、DNS解析、HTTPS证书)影响导致连接失败。下面完整的解决方案,包含「备用接口 + 超时重试 + 异常处理」,彻底解决这个问题。
上面使用时返回java.net.ConnectException: Failed to connect to api.ipify.org/172.67.74.152:443错误,更改方案如下
第一步:先理解错误原因
DNS解析到了 172.67.74.152,但无法建立TCP连接(443端口是HTTPS);
常见原因:网络禁用HTTPS、代理配置错误、接口被墙、设备网络权限未生效。
第二步:修复后的完整代码(Android + Kotlin)
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.net.HttpURLConnection
import java.net.URL
import java.util.concurrent.TimeUnit
object IpUtils {
// 备用公网IP接口列表(优先选国内可访问的)
private val IP_API_LIST = listOf(
"https://api.ipify.org", // 基础版
"https://icanhazip.com", // 备用1
"https://ifconfig.me/ip", // 备用2
"http://icanhazip.com", // 降级为HTTP(避免HTTPS证书问题)
"http://ifconfig.me/ip" // 降级为HTTP(最后兜底)
)
/**
* 获取公网IP(带重试+超时)
* @return 公网IP字符串,失败返回具体原因
*/
suspend fun getPublicIpWithRetry(): String = withContext(Dispatchers.IO) {
var lastException: Exception? = null
// 遍历接口列表,逐个尝试
for (apiUrl in IP_API_LIST) {
try {
val url = URL(apiUrl)
// 手动创建连接,添加超时控制(关键)
val connection = url.openConnection() as HttpURLConnection
connection.apply {
connectTimeout = 5000 // 连接超时5秒
readTimeout = 5000 // 读取超时5秒
requestMethod = "GET"
instanceFollowRedirects = true // 允许重定向
}
// 检查响应码
if (connection.responseCode == 200) {
val ip = connection.inputStream.bufferedReader().readText().trim()
connection.disconnect()
// 过滤空值/无效IP
if (ip.isNotBlank() && ip.contains(".")) {
return@withContext ip
}
}
} catch (e: Exception) {
lastException = e
// 打印当前接口失败原因,继续试下一个
println("接口 $apiUrl 失败: ${e.message}")
continue
}
}
// 所有接口都失败,返回最后一次异常信息
return@withContext "获取失败: ${lastException?.message ?: "未知错误"}"
}
}第三步:调用方式
lifecycleScope.launch {
val ip = IpUtils.getPublicIpWithRetry()
// 更新UI(已回到主线程)
tvIp.text = "公网IP:$ip"
}第四步:额外排查步骤(如果仍失败)
检查网络权限:确认 AndroidManifest.xml 中
已添加,且没有
缺失(可选);
关闭代理/VPN:如果设备开启了代理、VPN,先关闭再测试(很多时候是代理导致HTTPS连接失败);
测试HTTP接口:代码中已加入HTTP接口兜底,优先尝试 http://icanhazip.com(避免HTTPS证书问题);
检查网络环境:切换Wi-Fi/手机流量测试(部分局域网会屏蔽外网接口);
手动验证接口:在浏览器/Postman中访问 https://api.ipify.org,确认能返回IP(如果浏览器也打不开,说明该接口在当前网络不可用)。
总结
核心问题:api.ipify.org 连接失败是网络环境导致,而非代码问题;
解决方案:通过「多接口重试 + 超时控制 + HTTP降级」提升稳定性;
排查重点:优先检查网络权限、代理/防火墙、接口可访问性。
版权声明
本文章如果涉及侵权,请联系我。
部分文章系本人原创未经许可,不得转载。



蒙公网安备 15090202000037号
评论列表
发表评论