iOS无法连接ESP8266 WiFi软AP的问题排查与解决方案请求
ESP8266软AP无法被iOS 18.6.2设备连接的问题解决
问题描述
使用ESP8266WiFiHW-628 V0.0.1模块创建WiFi软AP,Windows设备可正常连接,但iOS 18.6.2系统的iPhone Xs、iPhone SE连接时提示“无法加入网络”。
开发环境及硬件配置
- ESP8266WiFiHW-628 V0.0.1
- VSCode + PlatformIO
- 5V/3A电源(实际最大电流0.8A)
- iOS 18.6.2系统的iPhone Xs与iPhone SE
已尝试的排查手段
- 更换4A电源,实际电流需求仍低于1A
- 尝试信道1、6、11,并关闭其他WiFi AP
- 将iOS设备置于ESP8266模块10cm范围内,排除信号弱问题
- 使用高强度密码(密码错误时提示信息不同)
- 更换AP IP地址(如10.0.0.1、118.118.4.1等),排除IP冲突
- 启动DNS服务器并在iPhone上手动设置DNS
- 关闭iPhone的“私有WiFi地址”功能
当前使用代码
#include <Arduino.h> #include <ESP8266WiFi.h> #include <ESPAsyncWebServer.h> #include <DNSServer.h> // 创建AsyncWebServer实例,端口80 AsyncWebServer server(80); DNSServer dnsServer; // iOS兼容的IP配置 IPAddress LocalIP(192, 168, 4, 1); IPAddress Gateway(192, 168, 4, 1); IPAddress Subnet(255, 255, 255, 0); void setup() { // 启动串口调试 Serial.begin(115200); Serial.println("\n--- 开始初始化 ---"); // 重置AP配置 WiFi.softAPdisconnect(true); if (WiFi.softAPConfig(LocalIP, Gateway, Subnet)) { Serial.println("AP IP配置成功"); // 创建AP:强密码、信道6、不隐藏、最大4个客户端 if (WiFi.softAP("CircularClockAP", "Clock123!@#", 6, false, 4)) { Serial.println("AP创建成功"); // 关闭WiFi休眠提升iOS连接稳定性 WiFi.setSleepMode(WIFI_NONE_SLEEP); // 打印AP IP地址 Serial.print("AP IP地址: "); Serial.println(WiFi.softAPIP()); Serial.printf("当前连接设备数: %d\n", WiFi.softAPgetStationNum()); } else { Serial.println("AP创建失败"); } } else { Serial.println("AP IP配置失败"); } // 启动DNS服务器用于 captive portal dnsServer.start(53, "*", LocalIP); Serial.println("DNS服务器启动"); // iOS captive portal检测处理 server.on("/hotspot-detect.html", HTTP_GET, [](AsyncWebServerRequest *request){ Serial.println("iOS热点检测请求"); request->send(200, "text/html", "<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>"); }); server.on("/library/test/success.html", HTTP_GET, [](AsyncWebServerRequest *request){ Serial.println("iOS成功页检测请求"); request->send(200, "text/html", "<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>"); }); // 安卓captive portal检测处理 server.on("/generate_204", HTTP_GET, [](AsyncWebServerRequest *request){ Serial.println("安卓连接检测请求"); request->send(204); // 返回无内容响应 }); // Windows连接检测处理 server.on("/connecttest.txt", HTTP_GET, [](AsyncWebServerRequest *request){ Serial.println("Windows连接检测请求"); request->send(200, "text/plain", "Microsoft Connect Test"); }); // 主页请求处理 server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ String userAgent = request->getHeader("User-Agent") ? request->getHeader("User-Agent")->value() : ""; // 处理Apple的CaptiveNetworkSupport验证请求 if (userAgent.indexOf("CaptiveNetworkSupport") >= 0) { Serial.println("Apple连接验证请求"); request->send(200, "text/html", "<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>"); return; } Serial.println("主页访问请求"); String html = "<!DOCTYPE html><html><head>"; html += "<meta charset='UTF-8'>"; html += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>"; html += "<title>Circular Clock 设置</title>"; html += "<style>body{font-family:Arial,sans-serif;margin:40px;background:#f5f5f5;}"; html += ".container{background:white;padding:30px;border-radius:8px;box-shadow:0 2px 10px rgba(0,0,0,0.1);}"; html += "h1{color:#333;text-align:center;}"; html += "p{color:#666;line-height:1.6;}"; html += ".status{background:#e8f5e8;padding:15px;border-radius:5px;margin:20px 0;}"; html += "</style></head><body>"; html += "<div class='container'>"; html += "<h1>🕐 Circular Clock 设置</h1>"; html += "<div class='status'>✅ 已成功连接到Circular Clock!</div>"; html += "<p>你的iOS设备已完成网络验证,可以开始配置时钟设置或关闭此页面。</p>"; html += "<p><strong>网络名称:</strong> CircularClockAP<br>"; html += "<strong>连接状态:</strong> 已验证并连接</p>"; html += "</div></body></html>"; request->send(200, "text/html", html); }); // 未匹配路径重定向到主页 server.onNotFound([](AsyncWebServerRequest *request){ Serial.println("重定向请求: " + request->url()); request->redirect("http://192.168.4.1/"); }); // 启动Web服务器 server.begin(); Serial.println("Web服务器启动"); Serial.println("--- 初始化完成 ---"); } void loop() { // 处理DNS请求 dnsServer.processNextRequest(); // 每10秒打印连接设备数 static unsigned long lastCheck = 0; if (millis() - lastCheck > 10000) { uint8_t stationCount = WiFi.softAPgetStationNum(); Serial.printf("AP状态 - 连接设备数: %d\n", stationCount); if (stationCount > 0) { Serial.println("iOS设备已成功连接!"); } lastCheck = millis(); } }
适配iOS 18.6.2的优化代码及配置说明
针对iOS 18.6.2的兼容性问题,对代码进行以下关键调整:
- 强制使用WPA2-PSK加密:iOS 18对WPA3或自动加密模式兼容性不佳,明确指定WPA2加密
- 锁定WiFi模式为802.11n:避免ESP8266自动切换到802.11b/g导致iOS连接失败
- 补充iOS 18新增检测路径:处理苹果新增的图标检测请求,避免设备判定网络不可用
- 优化WiFi参数稳定性:明确指定WiFi工作模式,减少自动切换带来的兼容性问题
优化后的代码:
#include <Arduino.h> #include <ESP8266WiFi.h> #include <ESPAsyncWebServer.h> #include <DNSServer.h> AsyncWebServer server(80); DNSServer dnsServer; // 固定IP配置 IPAddress LocalIP(192, 168, 4, 1); IPAddress Gateway(192, 168, 4, 1); IPAddress Subnet(255, 255, 255, 0); void setup() { Serial.begin(115200); Serial.println("\n--- 开始初始化 ---"); // 重置并设置WiFi为纯AP模式 WiFi.softAPdisconnect(true); WiFi.mode(WIFI_AP); // 配置AP IP if (WiFi.softAPConfig(LocalIP, Gateway, Subnet)) { Serial.println("AP IP配置成功"); // 强制WPA2-PSK加密,锁定802.11n,信道6 // 参数说明:SSID, 密码, 信道, 是否隐藏, 最大连接数, 加密模式 if (WiFi.softAP("CircularClockAP", "Clock123!@#", 6, false, 4, WIFI_AUTH_WPA2_PSK)) { Serial.println("AP创建成功"); // 关闭WiFi休眠,锁定为802.11n模式 WiFi.setSleepMode(WIFI_NONE_SLEEP); WiFi.setPhyMode(WIFI_PHY_MODE_11N); Serial.print("AP IP地址: "); Serial.println(WiFi.softAPIP()); Serial.printf("当前连接设备数: %d\n", WiFi.softAPgetStationNum()); } else { Serial.println("AP创建失败"); } } else { Serial.println("AP IP配置失败"); } // 启动DNS服务器,捕获所有域名请求 dnsServer.start(53, "*", LocalIP); Serial.println("DNS服务器启动"); // iOS 18 captive portal检测路径处理 server.on("/hotspot-detect.html", HTTP_GET, [](AsyncWebServerRequest *request){ Serial.println("iOS热点检测请求"); request->send(200, "text/html", "<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>"); }); server.on("/library/test/success.html", HTTP_GET, [](AsyncWebServerRequest *request){ Serial.println("iOS成功页检测请求"); request->send(200, "text/html", "<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>"); }); // Apple新增的连接检测路径 server.on("/apple-touch-icon-precomposed.png", HTTP_GET, [](AsyncWebServerRequest *request){ Serial.println("iOS图标检测请求"); request->send(404); }); server.on("/apple-touch-icon.png", HTTP_GET, [](AsyncWebServerRequest *request){ Serial.println("iOS图标检测请求"); request->send(404); }); // 安卓和Windows检测处理 server.on("/generate_204", HTTP_GET, [](AsyncWebServerRequest *request){ Serial.println("安卓连接检测请求"); request->send(204); }); server.on("/connecttest.txt", HTTP_GET, [](AsyncWebServerRequest *request){ Serial.println("Windows连接检测请求"); request->send(200, "text/plain", "Microsoft Connect Test"); }); // 主页处理,兼容Apple的CaptiveNetworkSupport检测 server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ String userAgent = request->getHeader("User-Agent") ? request->getHeader("User-Agent")->value() : ""; if (userAgent.indexOf("CaptiveNetworkSupport") >= 0) { Serial.println("Apple连接验证请求"); request->send(200, "text/html", "<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>"); return; } Serial.println("主页访问请求"); String html = "<!DOCTYPE html><html><head>"; html += "<meta charset='UTF-8'>"; html += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>"; html += "<title>Circular Clock 设置</title>"; html += "<style>body{font-family:Arial,sans-serif;margin:40px;background:#f5f5f5;}"; html += ".container{background:white;padding:30px;border-radius:8px;box-shadow:0 2px 10px rgba(0,0,0,0.1);}"; html += "h1{color:#333;text-align:center;}"; html += "p{color:#666;line-height:1.6;}"; html += ".status{background:#e8f5e8;padding:15px;border-radius:5px;margin:20px 0;}"; html += "</style></head><body>"; html += "<div class='container'>"; html += "<h1>🕐 Circular Clock 设置</h1>"; html += "<div class='status'>✅ 已成功连接到Circular Clock!</div>"; html += "<p>你的iOS设备已完成网络验证,可以开始配置时钟设置或关闭此页面。</p>"; html += "<p><strong>网络名称:</strong> CircularClockAP<br>"; html += "<strong>连接状态:</strong> 已验证并连接</p>"; html += "</div></body></html>"; request->send(200, "text/html", html); }); // 未匹配路径重定向到主页 server.onNotFound([](AsyncWebServerRequest *request){ Serial.println("重定向请求: " + request->url()); request->redirect("http://192.168.4.1/"); }); server.begin(); Serial.println("Web服务器启动"); Serial.println("--- 初始化完成 ---"); } void loop() { dnsServer.processNextRequest(); // 每10秒打印连接设备数 static unsigned long lastCheck = 0; if (millis() - lastCheck > 10000) { uint8_t stationCount = WiFi.softAPgetStationNum(); Serial.printf("AP状态 - 连接设备数: %d\n", stationCount); if (stationCount > 0) { Serial.println("iOS设备已成功连接!"); } lastCheck = millis(); } }
额外注意事项
- 确保ESP8266的核心固件版本更新到最新(PlatformIO中选择
esp8266:esp8266@3.2.0及以上) - 若仍无法连接,尝试将密码改为纯字母数字组合(避免特殊符号)
- 重启iOS设备后再尝试连接,清除之前的网络缓存
内容的提问来源于stack exchange,提问作者Erez




