首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >安卓开发中的网络交互:从服务端搭建到 IP获取​

安卓开发中的网络交互:从服务端搭建到 IP获取​

作者头像
Harry技术
发布2025-06-20 11:55:09
发布2025-06-20 11:55:09
3360
举报

在安卓开发的广阔天地里,网络交互是一个绕不开的重要环节。无论是搭建服务端接收外部请求,还是获取设备 IP 以便在局域网内通信,都蕴含着许多实用的技术与技巧。今天,就和大家聊聊这些在安卓开发中与网络相关的关键知识点。

图片
图片

一、搭建安卓服务端:Jetty 的魅力

在安卓中搭建服务端,Jetty 是一个值得推荐的选择。Jetty 是一款功能强大且灵活的 HTTP 服务器,它能帮助我们在安卓应用中轻松处理网络请求和响应。

首先,我们需要在项目中添加 Jetty 的依赖。如果你使用 Gradle 构建项目,只需在build.gradle文件中添加以下代码:

代码语言:javascript
复制
   // Jetty服务器依赖 - 使用较旧版本以兼容Android 5.1
    implementation("org.eclipse.jetty:jetty-server:9.2.30.v20200428") {
        exclude(group = "com.ibm.icu", module = "icu4j")
    }
    implementation("org.eclipse.jetty:jetty-servlet:9.2.30.v20200428")
    implementation("org.eclipse.jetty:jetty-util:9.2.30.v20200428") {
        exclude(group = "com.ibm.icu", module = "icu4j")
    }

这里我用的版本比较老,因为要考虑兼容Android 5.1系统。  exclude(group = "com.ibm.icu", module = "icu4j") 是为了解决中文乱码问题

添加好依赖后,就可以在代码中创建并启动 Jetty 服务器了。以下是一段简单的示例代码:

代码语言:javascript
复制
/**
 * Jetty服务器管理类
 * 用于提供HTTP API接口,允许外部应用访问用户管理数据
 */
class JettyServer private constructor(private val context: Context) {
    private val TAG = "JettyServer"
    private var server: Server? = null
    private val gson = Gson()
    private val prefsManager = AppPreferencesManager.getInstance(context)
    private val executor = Executors.newSingleThreadExecutor()

    companion object {
        private var instance: JettyServer? = null
        private const val DEFAULT_PORT = 8888

        fun getInstance(context: Context): JettyServer {
            return instance ?: synchronized(this) {
                instance ?: JettyServer(context.applicationContext).also { instance = it }
            }
        }
    }

    /**
     * 启动Jetty服务器
     */
    fun start(port: Int = DEFAULT_PORT) {
        executor.execute {
            try {
                if (server?.isRunning == true) {
                    Log.i(TAG, "服务器已经在运行中")
                    return@execute
                }

                server = Server(port).apply {
                    handler = createServletHandler()
                    start()
                }

                Log.i(TAG, "Jetty服务器已启动,端口:$port")
            } catch (e: Exception) {
                Log.e(TAG, "启动服务器失败: ${e.message}")
            }
        }
    }

    /**
     * 停止Jetty服务器
     */
    fun stop() {
        executor.execute {
            try {
                server?.stop()
                server = null
                Log.i(TAG, "Jetty服务器已停止")
            } catch (e: Exception) {
                Log.e(TAG, "停止服务器失败: ${e.message}")
            }
        }
    }

    /**
     * 创建Servlet处理器
     */
    private fun createServletHandler(): ServletContextHandler {
        return ServletContextHandler().apply {
            contextPath = "/"

            // 服务器状态API
            addServlet(ServletHolder(ServerStatusServlet()), "/api/status")

            // 用户管理API
            addServlet(ServletHolder(UserListServlet()), "/api/users")
            addServlet(ServletHolder(UserDetailServlet()), "/api/user/*")
            addServlet(ServletHolder(AddUserServlet()), "/api/user/add")
            addServlet(ServletHolder(UpdateUserServlet()), "/api/user/update")
            addServlet(ServletHolder(DeleteUserServlet()), "/api/user/delete")
        }
    }

    /**
     * 基础Servlet类,提供通用功能
     */
    private abstract inner class BaseServlet : HttpServlet() {
        fun <T> sendJsonResponse(
            response: HttpServletResponse,
            data: T,
            message: String = "操作成功"
        ) {
            response.contentType = "application/json;charset=UTF-8"
            response.characterEncoding = "UTF-8"
            response.status = HttpServletResponse.SC_OK
            val apiResponse = ApiResponse.success(data, message)
            response.writer.write(gson.toJson(apiResponse))
        }

        fun sendErrorResponse(response: HttpServletResponse, status: Int, message: String) {
            response.contentType = "application/json;charset=UTF-8"
            response.characterEncoding = "UTF-8"
            response.status = status
            val apiResponse = ApiResponse.errorFromHttp<Any>(status, message)
            response.writer.write(gson.toJson(apiResponse))
        }

        fun getRequestBody(request: HttpServletRequest): String {
            // 使用标准Java的编码处理,避免使用ICU实现
            val inputStream = request.inputStream
            val bytes = inputStream.readBytes()
            return String(bytes, StandardCharsets.UTF_8)
        }
    }
}

这段代码创建了一个监听 8888端口的 Jetty 服务器。不过,在安卓应用中使用时,千万别忘了在AndroidManifest.xml文件中添加网络权限:

代码语言:javascript
复制
<uses-permission android:name="android.permission.INTERNET" />

这样,一个基础的 Jetty 服务端就在安卓应用中搭建起来了。后续,我们可以进一步完善它,处理各种请求和响应逻辑。

图片
图片

二、获取安卓应用的局域网 IP 地址

获取安卓应用的局域网 IP 地址,是实现局域网内设备通信的关键一步。我们可以通过以下代码来获取:

代码语言:javascript
复制
package cn.harry.smartcabinet.util

import android.util.Log
import java.net.NetworkInterface

/**
 * IP地址工具类
 */
object IpUtil {
    private const val TAG = "IpUtil"

    /**
     * 获取本地IP地址
     * @return 本地IP地址,如果获取失败则返回null
     */
    fun getLocalIpAddress(): String? {
        try {
            val networkInterfaces = NetworkInterface.getNetworkInterfaces()
            while (networkInterfaces.hasMoreElements()) {
                val networkInterface = networkInterfaces.nextElement()

                // 跳过回环接口、虚拟接口等
                if (networkInterface.isLoopback || !networkInterface.isUp) {
                    continue
                }

                val addresses = networkInterface.inetAddresses
                while (addresses.hasMoreElements()) {
                    val address = addresses.nextElement()

                    // 跳过IPv6地址和回环地址
                    if (address.isLoopbackAddress || address.hostAddress.contains(":")) {
                        continue
                    }

                    val ip = address.hostAddress
                    Log.d(TAG, "找到IP地址: $ip")

                    // 优先返回非保留地址(通常是外网地址)
                    if (!isReservedAddress(ip)) {
                        return ip
                    }
                }
            }

            // 如果没有找到非保留地址,再次遍历查找任何可用的IPv4地址
            val networkInterfaces2 = NetworkInterface.getNetworkInterfaces()
            while (networkInterfaces2.hasMoreElements()) {
                val networkInterface = networkInterfaces2.nextElement()
                if (!networkInterface.isUp) continue

                val addresses = networkInterface.inetAddresses
                while (addresses.hasMoreElements()) {
                    val address = addresses.nextElement()
                    if (address.isLoopbackAddress || address.hostAddress.contains(":")) {
                        continue
                    }

                    return address.hostAddress
                }
            }
        } catch (e: Exception) {
            Log.e(TAG, "获取IP地址失败: ${e.message}")
        }

        return null
    }

    /**
     * 判断IP地址是否为保留地址
     * @param ip IP地址
     * @return 如果是保留地址则返回true,否则返回false
     */
    private fun isReservedAddress(ip: String): Boolean {
        return ip.startsWith("10.") || 
               ip.startsWith("172.16.") || 
               ip.startsWith("192.168.") || 
               ip.startsWith("127.")
    }
}

这段代码通过遍历设备上的网络接口,筛选出可用的局域网 IP 地址并返回。需要注意的是,在安卓 10 及以上的系统中,由于权限管理更加严格,部分获取 IP 的方式可能受到限制,开发者可能需要采用更复杂的方式,如通过网络请求去查询。

图片
图片

三、开启局域网通信:从 IP 到端口的连接

当我们获取到安卓应用的局域网 IP 地址,并在服务端设置好监听端口后,就可以在同一局域网内,使用其他设备发起请求与安卓应用进行通信了。不过,在进行通信之前,还有一个容易被忽视的问题 —— 防火设置。

安卓设备虽然没有像电脑一样专门的防火设置入口,但部分手机厂商会在系统设置中集成类似功能。我们可以在手机的 “设置” 中,查找 “网络与互联网” 或 “安全” 相关选项,部分手机还会有 “流量管理”“应用联网权限” 等设置,在这里可以管理应用的网络访问权限,起到类似防火的作用。此外,一些第三方安全软件也提供防火功能,可在软件设置中进行详细配置。

掌握了这些知识,我们在安卓开发中进行网络交互时就能更加得心应手。无论是搭建服务端实现数据交互,还是获取 IP 地址完成局域网通信,每一个细节都可能影响到整个应用的网络功能体验。希望本文能对大家有所帮助,让我们在安卓开发的网络世界中不断探索,创造出更出色的应用!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-06-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Harry技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、搭建安卓服务端:Jetty 的魅力
  • 二、获取安卓应用的局域网 IP 地址
  • 三、开启局域网通信:从 IP 到端口的连接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档