如何在Android中通过编程获取设备的公网IP地址?
在Android中获取公网IP地址的方法
嘿,我懂你要在Android里用代码拿公网IP的需求——和用WifiManager或者InetAddress获取本地局域网IP完全不一样,公网IP是你的设备在互联网上的标识,本地设备自己是不知道的,得靠调用外部的公开API来获取。下面给你两种实用的实现方式,都是经过验证的:
前置准备:添加必要权限
首先得在你的AndroidManifest.xml里添加网络权限,不然连不上网:
<uses-permission android:name="android.permission.INTERNET" /> <!-- 可选权限,用来先检查网络状态,避免无网时白跑请求 --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
方法一:使用原生HttpURLConnection(无需额外依赖)
Android自带的HttpURLConnection就能搞定,不过要注意网络请求绝对不能在主线程执行,这里用Kotlin协程来处理(比已弃用的AsyncTask更优雅):
完整代码实现
import android.content.Context import android.net.ConnectivityManager import android.net.NetworkCapabilities import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.io.BufferedReader import java.io.InputStreamReader import java.net.HttpURLConnection import java.net.URL // 挂起函数,用于获取公网IP suspend fun getPublicIp(context: Context): String? { // 先检查网络是否可用,避免浪费资源 if (!isNetworkAvailable(context)) { return null } return withContext(Dispatchers.IO) { // 用ipify的API,返回纯文本格式的公网IP,简单易处理 val apiUrl = URL("https://api.ipify.org") val connection = apiUrl.openConnection() as HttpURLConnection try { // 设置超时时间,避免一直等待 connection.connectTimeout = 5000 connection.readTimeout = 5000 if (connection.responseCode == HttpURLConnection.HTTP_OK) { // 读取返回的IP文本 BufferedReader(InputStreamReader(connection.inputStream)).use { reader -> reader.readLine() } } else { // 请求失败,返回null null } } catch (e: Exception) { // 捕获异常,比如网络波动、API不可用等 e.printStackTrace() null } finally { // 记得关闭连接 connection.disconnect() } } } // 辅助方法:检查当前网络是否可用 private fun isNetworkAvailable(context: Context): Boolean { val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val activeNetwork = connectivityManager.activeNetwork ?: return false val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false // 判断是否有互联网访问权限 return networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) }
调用示例(在Activity中)
import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.launch class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 在生命周期协程里调用,避免内存泄漏 lifecycleScope.launch { val publicIp = getPublicIp(this@MainActivity) publicIp?.let { // 成功获取到公网IP,这里可以做你需要的操作 println("当前公网IP: $it") } ?: run { // 获取失败,处理错误情况 println("获取公网IP失败,请检查网络") } } } }
方法二:使用OkHttp(更简洁,适合已有依赖的项目)
如果你的项目已经在用OkHttp做网络请求,用它来获取公网IP会更简洁:
第一步:添加OkHttp依赖
在Module级别的build.gradle(或build.gradle.kts)里添加依赖:
implementation("com.squareup.okhttp3:okhttp:4.12.0")
完整代码实现
import android.content.Context import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import okhttp3.OkHttpClient import okhttp3.Request // 初始化OkHttp客户端,全局单例即可 private val okHttpClient = OkHttpClient.Builder() .connectTimeout(5, java.util.concurrent.TimeUnit.SECONDS) .readTimeout(5, java.util.concurrent.TimeUnit.SECONDS) .build() suspend fun getPublicIpWithOkHttp(context: Context): String? { // 同样先检查网络状态 if (!isNetworkAvailable(context)) { return null } return withContext(Dispatchers.IO) { val request = Request.Builder() .url("https://api.ipify.org") .build() try { okHttpClient.newCall(request).execute().use { response -> // 请求成功则返回IP文本 if (response.isSuccessful) { response.body?.string() } else { null } } } catch (e: Exception) { e.printStackTrace() null } } } // 复用之前的isNetworkAvailable方法 private fun isNetworkAvailable(context: Context): Boolean { val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val activeNetwork = connectivityManager.activeNetwork ?: return false val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false return networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) }
调用示例和方法一类似,直接在协程里调用即可
额外小贴士
- 除了
api.ipify.org,你还可以用其他免费的公网IP API,比如https://icanhazip.com、https://ifconfig.me/ip,这些都是返回纯文本IP的,用法完全一致 - 尽量用HTTPS的API,避免明文传输,而且Android 10及以上默认禁止明文HTTP请求,用HTTPS就不用额外配置
android:usesCleartextTraffic="true" - 记得处理异常情况,比如网络超时、API不可用、没有网络权限等,给用户友好的提示
内容的提问来源于stack exchange,提问作者Gaurav Mistry
相关产品推荐
相关产品推荐

