充电桩 WiFi 局域网配网(Android/Kotlin)流程、指令及实例说明文档
文档概述本文档基于 Kotlin 语言详细阐述 Android App 为充电桩实现 WiFi 局域网配网的完整流程、指令规范及可直接复用的代码实例。核心原理与之前一致充电桩进入配网模式后创建临时 WiFi 热点App 接入该热点后通过 UDP 广播发送目标 WiFi 参数充电桩接收后连接目标 WiFi 并反馈结果。Kotlin 适配特性采用协程Coroutine处理异步通信、空安全Null Safety避免空指针、扩展函数简化 WiFi 信息获取符合 Android Jetpack 最佳实践。一、配网前提条件1. 硬件条件充电桩支持 WiFi 模块长按配网按键进入配网模式指示灯快闪创建临时热点如ChargingPile_XXXX手机Android 8.0已连接充电桩临时热点开启 WiFi 和位置服务Android 10 读取 SSID 必需。2. 软件权限Kotlin 申请方式App 需在AndroidManifest.xml声明以下权限并在运行时申请危险权限xml!-- 基础权限 -- uses-permission android:nameandroid.permission.ACCESS_WIFI_STATE / uses-permission android:nameandroid.permission.CHANGE_WIFI_STATE / uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE / uses-permission android:nameandroid.permission.INTERNET / !-- Android 10 读取SSID必需 -- uses-permission android:nameandroid.permission.ACCESS_COARSE_LOCATION / uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION / !-- UDP广播必需 -- uses-permission android:nameandroid.permission.CHANGE_NETWORK_STATE / uses-permission android:nameandroid.permission.WAKE_LOCK /二、配网完整流程预览查看代码否是充电桩进入配网模式手机连接充电桩临时热点App申请权限并获取目标WiFi参数App通过协程封装UDP配网指令并广播充电桩解析指令并尝试连接目标WiFi连接成功充电桩发送失败反馈充电桩保存WiFi参数并退出配网模式充电桩发送成功反馈App解析反馈并提示失败App解析反馈并提示成功flowchart TD A[充电桩进入配网模式] -- B[手机连接充电桩临时热点] B -- C[App申请权限并获取目标WiFi参数] C -- D[App通过协程封装UDP配网指令并广播] D -- E[充电桩解析指令并尝试连接目标WiFi] E -- F{连接成功} F -- 否 -- G[充电桩发送失败反馈] F -- 是 -- H[充电桩保存WiFi参数并退出配网模式] H -- I[充电桩发送成功反馈] G -- J[App解析反馈并提示失败] I -- K[App解析反馈并提示成功]否是充电桩进入配网模式手机连接充电桩临时热点App申请权限并获取目标WiFi参数App通过协程封装UDP配网指令并广播充电桩解析指令并尝试连接目标WiFi连接成功充电桩发送失败反馈充电桩保存WiFi参数并退出配网模式充电桩发送成功反馈App解析反馈并提示失败App解析反馈并提示成功流程分步说明充电桩配网模式启动用户长按充电桩配网键 3-5 秒指示灯快闪即进入配网模式手机网络连接用户在 WiFi 设置中连接充电桩临时热点权限与参数获取App 引导用户授权位置 / 网络权限自动读取当前连接的 WiFi SSID可选或让用户手动输入目标 WiFi 的 SSID 和密码UDP 指令发送App 通过 Kotlin 协程封装 JSON 格式配网指令以 UDP 广播形式发送至局域网充电桩处理充电桩监听指定 UDP 端口解析指令后尝试连接目标 WiFi结果反馈充电桩将连接结果封装为 JSON 指令通过 UDP 反馈给 AppApp 结果展示App 解析反馈指令通过 Toast / 弹窗提示用户配网成功 / 失败及原因。三、配网指令详细说明1. 通用规则传输协议UDP 广播优先无需知道充电桩 IP广播地址255.255.255.255端口6666数据格式JSONUTF-8 编码敏感字段密码建议 AES-128 加密示例中暂不加密超时规则App 监听反馈超时时间 15 秒充电桩连接 WiFi 超时时间 10 秒。2. 核心指令定义1配网指令App → 充电桩表格字段名类型必选说明cmd_typeString是固定值wifi_configdevice_idString是充电桩 SN / 设备 IDwifi_ssidString是目标 WiFi SSIDwifi_pwdString是目标 WiFi 密码空 无密码timestampLong是发送时间戳毫秒示例 JSONjson{ cmd_type:wifi_config, device_id:CP20240318001, wifi_ssid:Home_WiFi, wifi_pwd:12345678, timestamp:1710768000000 }2反馈指令充电桩 → App表格字段名类型必选说明cmd_typeString是固定值wifi_config_resultdevice_idString是充电桩 SN / 设备 IDresult_codeInt是结果码0 成功1 密码错误2SSID 不存在3 解析失败4 超时result_msgString是结果描述如 “配网成功”“密码错误”timestampLong是反馈时间戳毫秒成功示例json{ cmd_type:wifi_config_result, device_id:CP20240318001, result_code:0, result_msg:配网成功已连接Home_WiFi, timestamp:1710768010000 }四、Kotlin 核心代码实例1. 依赖配置build.gradle添加 GsonJSON 解析和协程依赖gradledependencies { // Gson解析JSON implementation com.google.code.gson:gson:2.10.1 // Kotlin协程 implementation org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 // 权限申请可选简化权限处理 implementation com.permissionx.guolindev:permissionx:1.7.1 }2. 工具类WiFi 信息扩展函数kotlinimport android.content.Context import android.net.wifi.WifiInfo import android.net.wifi.WifiManager import android.os.Build /** * Context扩展函数获取WiFi管理器 */ fun Context.getWifiManager(): WifiManager { return applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager } /** * 获取当前连接的WiFi SSID去除双引号处理空安全 */ fun Context.getCurrentWifiSsid(): String? { val wifiManager getWifiManager() if (!wifiManager.isWifiEnabled) return null val wifiInfo: WifiInfo wifiManager.connectionInfo ?: return null val ssid wifiInfo.ssid ?: return null // 移除Android默认给SSID加的双引号 return if (ssid.startsWith(\) ssid.endsWith(\)) { ssid.substring(1, ssid.length - 1) } else ssid } /** * 转义JSON特殊字符避免解析失败 */ fun String.escapeJsonChars(): String { return this.replace(\\, \\\\) .replace(\, \\\) .replace(\n, \\n) .replace(\r, \\r) }3. 核心类WiFi 配网管理器kotlinimport android.content.Context import com.google.gson.Gson import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.net.DatagramPacket import java.net.DatagramSocket import java.net.InetAddress /** * 充电桩WiFi配网管理器基于Kotlin协程 */ class ChargingPileWifiConfigManager(private val context: Context) { // 常量定义 private companion object { const val UDP_BROADCAST_IP 255.255.255.255 const val UDP_PORT 6666 const val LISTEN_TIMEOUT 15000 // 监听反馈超时时间15秒 val gson Gson() } // 配网结果回调 interface OnConfigResultListener { fun onSuccess(message: String) fun onFailed(errorCode: Int, errorMsg: String) } /** * 发送配网指令 * param targetSsid 目标WiFi SSID * param targetPwd 目标WiFi密码 * param deviceId 充电桩设备ID * param listener 结果回调 */ fun sendConfigCommand( targetSsid: String, targetPwd: String, deviceId: String, listener: OnConfigResultListener ) { // 协程处理异步操作IO线程 GlobalScope.launch(Dispatchers.IO) { try { // 1. 封装配网指令 val configCmd ConfigCommand( cmd_type wifi_config, device_id deviceId, wifi_ssid targetSsid.escapeJsonChars(), wifi_pwd targetPwd.escapeJsonChars(), timestamp System.currentTimeMillis() ) val cmdJson gson.toJson(configCmd) val cmdBytes cmdJson.toByteArray(Charsets.UTF_8) // 2. 创建UDP Socket并发送广播 val socket DatagramSocket(UDP_PORT) socket.broadcast true // 开启广播模式 socket.soTimeout LISTEN_TIMEOUT val broadcastAddress InetAddress.getByName(UDP_BROADCAST_IP) val packet DatagramPacket( cmdBytes, cmdBytes.size, broadcastAddress, UDP_PORT ) socket.send(packet) // 3. 监听充电桩反馈 val buffer ByteArray(1024) val resultPacket DatagramPacket(buffer, buffer.size) socket.receive(resultPacket) // 4. 解析反馈结果 val resultJson String( resultPacket.data, 0, resultPacket.length, Charsets.UTF_8 ) val result gson.fromJson(resultJson, ConfigResult::class.java) // 5. 回调结果切换到主线程 withContext(Dispatchers.Main) { if (result.result_code 0) { listener.onSuccess(result.result_msg) } else { listener.onFailed(result.result_code, result.result_msg) } } socket.close() } catch (e: Exception) { // 异常处理切换到主线程 withContext(Dispatchers.Main) { listener.onFailed(999, 配网失败${e.message ?: 未知错误}) } } } } // 配网指令数据类对应JSON结构 data class ConfigCommand( val cmd_type: String, val device_id: String, val wifi_ssid: String, val wifi_pwd: String, val timestamp: Long ) // 配网结果数据类对应JSON结构 data class ConfigResult( val cmd_type: String, val device_id: String, val result_code: Int, val result_msg: String, val timestamp: Long ) }4. 页面示例配网 Activitykotlinimport android.os.Bundle import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.permissionx.guolindev.PermissionX import kotlinx.android.synthetic.main.activity_config.* class WifiConfigActivity : AppCompatActivity() { private lateinit var configManager: ChargingPileWifiConfigManager override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_config) // 初始化配网管理器 configManager ChargingPileWifiConfigManager(this) // 自动填充当前连接的SSID tvCurrentSsid.text 当前连接WiFi${getCurrentWifiSsid() ?: 未检测到} etSsid.setText(getCurrentWifiSsid()) // 配网按钮点击事件 btnConfig.setOnClickListener { val ssid etSsid.text.toString().trim() val pwd etPwd.text.toString().trim() val deviceId etDeviceId.text.toString().trim() // 校验输入 if (ssid.isEmpty()) { Toast.makeText(this, 请输入WiFi名称, Toast.LENGTH_SHORT).show() returnsetOnClickListener } if (deviceId.isEmpty()) { Toast.makeText(this, 请输入充电桩设备ID, Toast.LENGTH_SHORT).show() returnsetOnClickListener } // 申请权限 requestPermissions { // 权限通过后发送配网指令 configManager.sendConfigCommand(ssid, pwd, deviceId, object : ChargingPileWifiConfigManager.OnConfigResultListener { override fun onSuccess(message: String) { Toast.makeText(thisWifiConfigActivity, message, Toast.LENGTH_SHORT).show() // 配网成功跳转结果页 // startActivity(Intent(thisWifiConfigActivity, SuccessActivity::class.java)) } override fun onFailed(errorCode: Int, errorMsg: String) { Toast.makeText(thisWifiConfigActivity, 失败$errorMsg, Toast.LENGTH_SHORT).show() } }) } } } /** * 申请必要权限位置网络 */ private fun requestPermissions(onGranted: () - Unit) { PermissionX.init(this) .permissions( android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.INTERNET ) .onExplainRequestReason { scope, deniedList - scope.showRequestReasonDialog(deniedList, 需要位置权限读取WiFi名称网络权限发送配网指令, 确定, 取消) } .onForwardToSettings { scope, deniedList - scope.showForwardToSettingsDialog(deniedList, 请在设置中开启权限, 去设置, 取消) } .request { allGranted, _, _ - if (allGranted) { onGranted() } else { Toast.makeText(this, 权限申请失败无法进行配网, Toast.LENGTH_SHORT).show() } } } }5. 布局文件activity_config.xmlxml?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightmatch_parent android:orientationvertical android:padding20dp TextView android:idid/tvCurrentSsid android:layout_widthmatch_parent android:layout_heightwrap_content android:marginBottom10dp android:text当前连接WiFi未检测到 / EditText android:idid/etDeviceId android:layout_widthmatch_parent android:layout_heightwrap_content android:hint请输入充电桩设备ID android:marginBottom10dp / EditText android:idid/etSsid android:layout_widthmatch_parent android:layout_heightwrap_content android:hint请输入目标WiFi名称 android:marginBottom10dp / EditText android:idid/etPwd android:layout_widthmatch_parent android:layout_heightwrap_content android:hint请输入目标WiFi密码无密码留空 android:inputTypetextPassword android:marginBottom20dp / Button android:idid/btnConfig android:layout_widthmatch_parent android:layout_heightwrap_content android:text开始配网 / /LinearLayout五、测试与验证步骤环境准备充电桩进入配网模式创建临时热点测试手机连接该热点安装 App 并授予位置、网络权限。操作步骤输入充电桩设备 ID、目标 WiFi SSID 和密码点击 “开始配网” 按钮观察 App 提示成功 / 失败同时查看充电桩指示灯常亮 配网成功快闪 失败。验证结果配网成功后充电桩会自动连接目标 WiFi可通过路由器管理页面查看设备是否上线App 可再次发送心跳指令验证充电桩是否在线。六、常见异常及处理方案表格异常场景错误码Kotlin 侧处理方式WiFi 密码错误1清空密码输入框提示用户 “密码错误请重新输入”SSID 不存在2校验 SSID 格式提示用户 “未找到该 WiFi请检查名称或确保 WiFi 已开启”UDP 发送失败999检查手机是否连接充电桩热点通过wifiManager.isWifiEnabled校验 WiFi 是否开启监听反馈超时999提示用户 “未收到充电桩响应请确认设备处于配网模式或重试”权限未授予-使用 PermissionX 引导用户授权未授权时禁用配网按钮JSON 解析失败999校验指令 JSON 格式通过escapeJsonChars处理特殊字符七、总结核心要点Kotlin 实现配网的核心是协程 UDP 广播协程替代传统 Thread 处理异步通信避免主线程阻塞UDP 广播无需提前知道充电桩 IP适配局域网内多设备场景指令规范JSON 格式需包含cmd_type指令类型、device_id设备标识、result_code结果码等核心字段特殊字符需转义权限处理Android 10 必须申请位置权限才能读取 WiFi SSID需引导用户授权并处理权限拒绝场景。Kotlin 开发注意事项空安全所有可能为空的字段如 SSID、反馈结果需添加?避免空指针异常协程作用域建议使用lifecycleScope替代GlobalScope避免内存泄漏加密传输正式环境需对 WiFi 密码进行 AES 加密可扩展ConfigCommand添加加密逻辑兼容性适配 Android 12 的 WiFi 权限变更如NEARBY_WIFI_DEVICES权限。