☰
Android Wi-Fi Direct实战:官方Demo原理、常见坑与改造方案
2026/10/15 18:23:08 网站建设 项目流程

简介:Android官方Wi-Fi P2P示例项目(WiFiDirectDemo)是一份面向Android开发者的设备直连技术参考,演示了不经过无线接入点即可完成设备发现、群组创建、连接管理与高速文件传输的完整流程。压缩包共88个文件,约244KB,包含7个Java源码、14个XML布局与清单、26个class编译产物,以及32张界面与流程截图;资源包内同时提供src源码与res资源目录,方便逐步跟踪各回调状态,也保留了编译中间产物,适合对照学习Wi-Fi P2P从权限配置到核心API调用(如WifiP2pManager、discoverPeers、connect)的实现细节。已有781人学习下载。通过这份官方Demo,读者可得到可直接导入工程学习的源码结构、构建产物及运行说明,覆盖设备发现、连接请求、群组创建维护、Socket文件传输等模块;对理解设备发现状态机、群组主从协商和异步回调处理尤其有帮助,并可在此基础上扩展文件分享、联机对战或投屏等应用。

1. Android官方Wifi P2P Demo:花一个下午跑通,省一个月的弯路

Wi-Fi Direct 听起来很硬核,但官方这份 Demo 的核心目标其实非常朴素:让两台 Android 设备在没有路由器、没有热点、没有数据流量的前提下,直接通过 Wi-Fi 找到彼此并传数据。很多开发者第一次接触它,都是因为业务里出现了「局域网内文件互传」「设备配网」「IoT 设备间点对点通信」这类需求,然后搜到这个 Demo。它的价值在于把 Android 系统里最绕的一套 P2P 协议栈包装成了几个可调用的 API:WifiP2pManager 负责发现和连接,BroadcastReceiver 负责接收系统状态,ServerSocket 和 Socket 负责传输。但这份 Demo 有它的年代感,直接搬进项目里会踩很多坑。这篇文章我会从协议链路、工程结构、最小可运行实现、常见的翻车现场到进阶改造一路讲完,尽量让你少走弯路。

2. Wi-Fi Direct 的链路本质:从发现设备到建立连接,官方 Demo 帮你走完哪几步

很多人第一次打开官方 Demo 时,会被目录里的 Fragment、Receiver、Manager 等十几个类绕晕。实际上它做的事可以压缩成四步:发现附近设备、展示设备列表、发起连接、建立 Socket 传输。这一章把每一步背后系统到底发生了什么讲清楚,你后面调参和排错才有依据。

2.1 四个广播事件决定了 Demo 的所有逻辑分支

Android 的 Wi-Fi Direct 不像蓝牙那样靠回调就能完成大部分操作,它的状态变化主要是通过系统广播通知应用的。官方 Demo 里的 WiFiDirectBroadcastReceiver 本质就是监听四个关键广播:WIFI_P2P_STATE_CHANGED_ACTION 表示 Wi-Fi Direct 功能开关状态变化;WIFI_P2P_PEERS_CHANGED_ACTION 表示附近发现的设备列表有更新;WIFI_P2P_CONNECTION_CHANGED_ACTION 表示连接状态有变化,比如成功成为 Group Owner 或者连接断开;WIFI_P2P_THIS_DEVICE_CHANGED_ACTION 表示本机设备信息有变化。

理解这四个广播后,你就明白官方 Demo 的主流程是事件驱动而不是调用驱动。也就是说,你调用 discoverPeers() 之后,系统并不会立刻把设备列表塞给你,而是过一会发一个 PEERS_CHANGED 广播,你在这个广播里调用 requestPeers() 才能拿到列表。这个异步机制是新手最容易懵的地方:明明调用成功了,为什么列表是空的?因为广播还没到。

这类事件驱动模式也解释了为什么官方 Demo 里大量代码都在处理「当前状态是什么,就显示什么界面」。它本质上是一个状态机:初始化、正在搜索、已发现设备、正在连接、已连接、传输中。你把状态机画清楚,再回头看代码就会觉得很有条理。

2.2 从 discoverPeers 到 connect:Group Owner 协商机制

Wi-Fi Direct 里没有路由器,但两台设备直连时必须有「一台负责管理连接」的角色,这个角色叫 Group Owner,简称 GO。GO 相当于迷你版 AP,另一台设备作为 Client 连入。谁当 GO 由协商决定,也就是 connect() 时的 groupOwnerIntent 参数,取值范围 0 到 15,数值越大越倾向于成为 GO。

官方 Demo 在连接阶段的做法是:用户点击列表里的某个设备,Demo 读取该设备的 MAC 地址,构造 WifiP2pConfig,然后调用 connect()。系统随后进行 GO 协商,期间会经历几次内部握手。协商完成后,你会收到 CONNECTION_CHANGED 广播,此时需要调用 requestGroupInfo() 拿到 GO 的 IP 地址。注意,只有 GO 能拿到自己作为服务端的 IP,Client 端通常在 WifiP2pInfo 里通过 groupOwnerAddress 字段拿到 GO 的地址。

我第一次在模拟项目X里跑这块时,犯了最经典的错误:Client 端拿自己的 IP 去监听端口,结果永远连不上。正确做法是 Client 端使用 groupOwnerAddress 作为 Socket 连接目标,GO 端则在 0.0.0.0 上监听。官方 Demo 为了简化,把传输逻辑做成了一台设备开 ServerSocket、另一台设备主动连接的模式,本质上就是传统 TCP 通信,只是 IP 来源从 P2P 信道里拿而已。

2.3 官方 Demo 的协议栈分层,和你的业务层应该怎么划分

官方 Demo 里典型的类包括 MainActivity、WiFiDirectBroadcastReceiver、DeviceListFragment、DeviceDetailFragment、WiFiDirectService。如果你仔细看它们的职责,会发现系统其实把「链路层」和「业务层」分得很清楚:WifiP2pManager 和 BroadcastReceiver 属于链路层,负责发现、连接、状态维护;Socket 传输和业务数据属于业务层,官方 Demo 用的是最原始的文本消息传输,没有任何协议封装。

这就引出一个重要的设计建议:你从官方 Demo 迁移到自己的项目时,不要把它当成品,而要把它当参考实现。链路层可以保留并适度封装,业务层应该全部替换掉。我自己通常会额外抽象一个 ConnectionManager 类,对外暴露发现、连接、断开三个 suspend 方法,内部把 WifiP2pManager 的 Callback 转成协程回调。这样业务层就不用再去订阅广播,而是等待一个连接成功的对象,然后直接通过 TCP 交换数据。

3. 把官方 Demo 搬进 Android Studio:目录结构、权限清单与最小运行配置

这一章的实用价值在于:拿到官方 Demo 源码后,不要直接按下 Run。你需要先看懂它的工程切入点在哪、哪些文件是 AndroidManifest 必须声明的、哪些配置会直接影响能不能跑起来。在没有头绪的源码包面前,按下面的顺序做能省下大半天时间。

3.1 官方 Demo 的文件结构:哪些类值得保留,哪些可以删掉

官方 Demo 的代码量不大,但类与类之间的引用比较绕。一个典型的文件清单如下,你可以对照自己的工程看哪些改动成本最低。

文件清单表格:

文件职责是否建议保留
MainActivity初始化 manager/channel,注册广播接收器,控制 Fragment 跳转保留但建议瘦身
WiFiDirectBroadcastReceiver监听四个系统广播,转发给 Activity保留,可改造成独立类
DeviceListFragment展示发现的对等设备列表保留,UI 可以重写
DeviceDetailFragment展示连接后的设备信息和传输入口建议删除,业务迁移后替换
WiFiDirectService封装 Socket 连接的 IntentService建议删除,换成协程封装

你可能会问,为什么不直接照抄?因为官方 Demo 的 DeviceListFragment 用的是 ListFragment 加自定义 adapter,这种写法放在现代项目里太偏老;而 WiFiDirectService 那个 IntentService 在传输大文件时很容易被系统限制。我建议只留下核心的链路层片段,UI 和传输层完全可以按自己的技术栈重写。

3.2 权限清单:从 Android 6 到 Android 14,缺一个都跑不起来

Wi-Fi Direct 牵扯到 Wi-Fi 状态、位置信息、附近设备权限。不同 Android 版本对权限的要求差异很大,这是新手最容易「翻车」的地方。通常 AndroidManifest 里需要声明以下权限:

权限用途最低版本要求
ACCESS_FINE_LOCATION扫描附近 Wi-Fi Direct 设备时系统要求Android 6.0 及以上需要动态申请
CHANGE_WIFI_STATE修改 Wi-Fi 状态,启用 Wi-Fi Direct 扫描需要所有版本
ACCESS_WIFI_STATE获取当前 Wi-Fi 状态所有版本
INTERNET建立 TCP Socket 连接所必需所有版本
NEARBY_WIFI_DEVICES替代部分位置权限的新版附近设备权限Android 13 及以上需要动态申请

这里有个关键点:Android 13 及以后的系统引入了 NEARBY_WIFI_DEVICES 这个运行时权限,它看名字是普通权限,但官方标注为「不需要位置权限即可使用附近的 Wi-Fi 设备」。不过如果你要兼容老版本,估计还是得动态申请位置权限。我见过很多项目在 Android 14 设备上怎么都扫描不到设备,查来查去最后发现是位置权限没有弹窗授权。

另一个非常隐蔽的坑:只声明权限但没在系统设置里打开「位置服务」开关,同样收不到 PEERS_CHANGED 广播。因为 Android 的 Wi-Fi Direct 扫描接口依赖系统位置服务提供基础信息,开关没开时扫描接口会静默失败。所以你在调试时必须主动判断权限和开关两个维度,而不是只看代码逻辑。

3.3 最小运行配置:模拟器跑不了,必须是两台真机

很多人在模拟器上跑官方 Demo,然后发现自己和自己当然搜不到任何设备。这不是你的代码有问题,而是模拟器的无线网卡不支持和实体设备交互。正确测试方法是一台机器作为 GO、一台作为 Client,或者准备两台真机。如果你的机型支持「双 Wi-Fi Direct」功能,也可以拿同一台设备开两个 App 实例来模拟,但不是所有机器都支持这个模式。

我建议的测试配置是两台 Android 10 以上、支持 5GHz 频段的手机,关闭其中一台的移动数据,把两台设备放在一米内的距离。这样能排除频段和距离对扫描结果的影响。如果你手头只有一台设备,那就退回到传统 TCP 测试:先用 PC 开一个临时服务器,把 App 改成连接固定 IP,先把 Socket 链路跑通,再回来测 P2P 发现。

4. 一个可改可跑的最小实现:从「扫描到对端」到「自定义字节传输」

官方 Demo 是参考实现,但它把「发现」和「传输」绑定在界面上,不利于直接复用。这一章我会给出一套基于官方思路、但更利于改造成业务代码的最小实现。你可以把它视为官方 Demo 的「协程版」,每段代码都贴出来,并标注关键参数的含义。

4.1 初始化 WifiP2pManager、Channel 与广播接收器的标准写法

下面这段代码是 Wi-Fi Direct 的基础骨架。通常在 Application 或主 Activity 的 onCreate 里完成。

public class P2pManagerHolder { private final WifiP2pManager manager; private final WifiP2pManager.Channel channel; private final BroadcastReceiver receiver; private final Context context; public P2pManagerHolder(Context context) { this.context = context.getApplicationContext(); manager = (WifiP2pManager) context.getSystemService(Context.WIFI_P2P_SERVICE); channel = manager.initialize(context, context.getMainLooper(), null); receiver = new P2pBroadcastReceiver(); context.registerReceiver(receiver, getIntentFilter()); } private static IntentFilter getIntentFilter() { IntentFilter filter = new IntentFilter(); filter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); filter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); filter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); return filter; } }

这段代码的关键点在 channel 的初始化。initialize() 的第二个参数是 Looper,必须传主线程的 Looper,不要自己 new 一个 HandlerThread 的 Looper,否则所有回调都会脱离主线程,UI 更新时容易引发崩溃。第三个参数是 ChannelListener,用于监听通道关闭事件,官方 Demo 里经常传 null,但在实际业务里建议传一个回调,在 channel 失效时重新初始化。

registerReceiver 的调用时机也很重要。我一般放在 Application 的 onCreate 里而不是 MainActivity 里,因为它要对整个应用生命周期负责。如果你放在 Activity 里,每次旋转屏幕都会重复注册,LeakCanary 马上就会报警。另外,静态注册 BroadcastReceiver 在 Android 8.0 以后对隐式广播基本失效,这里必须用动态注册。

4.2 扫描设备与监听对等设备列表:把回调改成协程

扫描设备的传统写法是 manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {...})。问题在于回调是嵌套的,业务代码一复杂就变成回调地狱。我习惯用 suspendCancellableCoroutine 把它包装成挂起函数。

suspend fun discoverPeers(): Boolean = suspendCancellableCoroutine { continuation -> manager.discoverPeers(channel, object : WifiP2pManager.ActionListener() { override fun onSuccess() { continuation.resume(true) } override fun onFailure(reasonCode: Int) { Log.e(TAG, "discoverPeers failed, reason: $reasonCode") continuation.resume(false) } }) }

reasonCode是排错的重要线索:WifiP2pManager.P2P_UNSUPPORTED表示设备不支持 Wi-Fi Direct,你不用继续往下走了;BUSY表示系统正在处理上一个请求,需要稍后重试;ERROR表示内部错误。发现成功之后,通过requestPeers拿到WifiP2pDeviceList,这里的 WifiP2pDevice 对象包含设备名、MAC 地址、状态和 capabilities。

状态字段里有一个坑:device.status 的取值可能是 AVAILABLE、INVITED、CONNECTED 等。如果设备已经连接,它的列表中可能仍然显示状态为 INVITED 或 CONNECTED,这并不代表当前可以发起新的连接。我建议在界面展示时只对 AVAILABLE 状态的设备开放点击事件。

4.3 建立连接:groupOwnerIntent 与连接超时处理

当你从设备列表里选中一台设备后,需要构造 WifiP2pConfig 并调用 connect()。

fun connectToDevice(device: WifiP2pDevice) { val config = WifiP2pConfig().apply { deviceAddress = device.deviceAddress groupOwnerIntent = 6 } manager.connect(channel, config, object : WifiP2pManager.ActionListener() { override fun onSuccess() { // 连接请求已发出,真正成功要看 CONNECTION_CHANGED 广播 } override fun onFailure(reasonCode: Int) { // 常见 reasonCode: P2P_BUSY, P2P_NO_SERVICE } }) }

groupOwnerIntent默认值是 7,范围是 0 到 15。0 表示设备不希望成为 GO,15 表示设备强烈希望成为 GO。如果两台设备同时发起连接,可能会出现协商冲突,所以我的习惯是:主动发起连接的一端设为 6 到 10,被连接的一端不调用 connect,直接等待系统自动加入或通过createGroup来建立群组。deviceAddress是设备的 MAC 地址字符串,注意不要传成deviceName。

连接过程中最常见的现象是「一直在转圈,最后超时」。这个超时不是 connect() 自动触发的,系统默认的 Wi-Fi Direct 连接超时在 30 秒左右。你最好在业务层自己起一个 15 秒的定时器,超时就提示用户。因为系统底层的超时在被 App 层面感知到之前,用户早就失去耐心了。

4.4 获取 Group Owner 信息与建立 Socket 传输

连接成功后会收到 CONNECTION_CHANGED 广播,典型的回调代码是下面的样子。

fun handleConnectionChanged(networkInfo: NetworkInfo, p2pInfo: WifiP2pInfo) { if (networkInfo.isConnected && p2pInfo.groupFormed) { if (p2pInfo.isGroupOwner) { // 本机是 GO,监听固定端口 startServerSocket(PORT) } else { // 本机是 Client,连接 GO 的 IP val address = p2pInfo.groupOwnerAddress.hostAddress startClientSocket(address, PORT) } } else { // 连接断开 } }

groupOwnerAddress在其他资料里也写作InetAddress,它的值通常是一个 192.168.49.x 的局域网地址,这是 Wi-Fi Direct 默认分配的网段。这里有一个特别值得注意的点:Wi-Fi Direct 群组建立后,GO 和 Client 处于同一个局域网段,但该网段与设备原本连接的 AP 网段不是同一个,所以不能直接使用设备原来的局域网 IP。

Socket 传输部分,使用传统的ServerSocket和Socket即可。不要在客户端刚连接时就立刻发送大块数据,最好先做一个握手:客户端发送一个自定义字节头如0xAA,服务端收到后回复0xBB,双方确认后再进入正式的数据传输。这段「先握手再传数据」并不是官方 Demo 的做法,但对于业务系统来说,它能显著减少连接刚建立时信道尚未稳定的丢包概率。

5. 官方 Demo 的五个典型坑:现象、根因与排错方法

这一章我挑出自己在实操中反复碰到的问题,按统一格式写:现象描述,根因分析,解决方式。这些问题如果你没经历过,很难从代码层面直接定位,但它们几乎都会在集成官方 Demo 后的第一天出现。

5.1 两台真机互相扫描不到设备

常见现象:两台设备都在主界面,点「搜索设备」按钮没有任何反馈或短暂转圈后列表仍为空。Wi-Fi 和蓝牙都已打开,系统权限全部授予。

根因:多数情况下不是 App 的问题。第一,Android 6.0 以上的扫描依赖位置服务,系统「位置信息」开关被关闭则 scanning 静默失败;第二,部分厂商 ROM 对 Wi-Fi Direct 有兼容性问题,比如某些定制系统默认禁用了 5GHz 频段的 Wi-Fi Direct 扫描;第三,两台设备距离过远或中间有金属障碍物导致信号丢失。

解决:先确认系统 Wi-Fi 已经连接到一个网络(不一定非要有外网,但要处于 Wi-Fi 开启状态)。再把两台设备距离缩短到半米以内,重启 Wi-Fi 开关,在系统设置里打开位置服务。如果还不行,把通道里的groupOwnerIntent临时调到最大值重启一次扫描。我遇到过一个厂商设备必须完全关闭蓝牙才能扫描到对端,属于极端兼容性问题,只能做设备适配兜底。

5.2 discoverPeers 回调成功但 peers 列表为空

常见现象:onSuccess()已经触发了,说明系统已经开启了发现流程,但等了一两分钟 PEERS_CHANGED 广播始终不来,请求 peers 拿到的列表是空的。

根因:这个场景通常是目标设备处于休眠状态或没有进入可被发现状态。Wi-Fi Direct 的发现过程依赖目标设备周期性发送信标帧,如果目标设备屏幕关闭时间较长,系统会自动进入省电模式并关闭信标发送。另一种可能是设备已经处于某个群组中,系统不会向新的扫描方暴露自己。

解决:确保目标设备屏幕保持常亮,最好保持在系统自带的 Wi-Fi Direct 设置页并停留在那个界面。如果目标设备已经在别的群组中,先退出该群组再回到可被发现状态。这里还有一个经验值:连续调用discoverPeers的时间间隔不要小于 10 秒,因为系统在频繁扫描时会触发节流机制,导致回调迟迟不来。一旦你的代码里出现了循环调用discoverPeers,把循环去掉,改成「点击一次,扫描一次」的模式。

5.3 connect 后一直处于「邀请中」状态

常见现象:点击某台设备发起连接后,目标设备也弹出了邀请确认框,用户点了「接受」,但连接状态始终停留在「邀请中」,CONNECTION_CHANGED 广播迟迟不触发。

根因:系统在 GO 协商阶段发生了频繁的内部握手失败。常见原因有两种:一是两台设备同时在对方的界面上发起 connect,导致双方都尝试成为 GO,协商轮流切换直到超时;二是设备所处的信道拥塞,特别是周围有大量 2.4GHz Wi-Fi 信号时,协商报文丢失概率变大。

解决:在业务上设定明确的「主动方」和「被动方」。被邀请方不要自己调用connect(),只需自动接受系统弹窗即可。主动方的groupOwnerIntent设为 8 到 10,被邀请方设备不要设置该字段。如果你要做一个传输工具 App,这个「谁发起连接」的规则应该由用户操作来隐式决定:先点击对方设备的用户是主动方,对方只要等待弹窗确认。这里的经验是,connect()后两秒内目标设备如果没有弹出确认框,主动方自己主动调用一次cancelConnect()再重试,能杀掉很多悬挂状态。

5.4 Socket 连接成功但数据收不到

常见现象:两台设备显示已连接,TCP 也成功建立了对端连接,但发送方传数据后接收方没有触发 read 回调,或者过很长时间才收到一次。

根因:这块不太可能出在 Wi-Fi Direct 协议上,而是你的传输代码把 Socket 的读取方式写错了。最容易犯的错误是只写了outputStream.write(),但没有调用flush()。Java 的BufferedOutputStream只有在缓冲区满或显式 flush 时才会真正发数据。第二个错误是inputStream.read()在数据到来之前会阻塞,你如果在主线程直接读取,UI 会卡死。

解决:写数据后一定调用outputStream.flush()。读数据放到子线程,典型写法是用while (true)循环去 read,并用一个volatile boolean标志来控制退出。如果你传的是文本,最好约定用\n作为消息结尾并readLine()。这种「两端协商一个结束符」的方式比固定长度字节头更容易排错。

5.5 Activity 旋转屏幕后连接状态丢失,界面不刷新

常见现象:连接已经建立,旋转屏幕后界面回到初始状态,设备列表清空,连接状态变成「未连接」,但 Wi-Fi Direct 实际上还保持着连接。

根因:官方 Demo 把所有状态都放在 Activity 里,旋转导致 Activity 重建后,WifiP2pManager.Channel对象失效,广播接收器被注销,状态自然全部丢失。Wi-Fi Direct 的底层连接并未被系统切断,但你的应用已经没有通道去感知它了。

解决:把P2pManagerHolder或核心状态对象放到 ViewModel 或 Application 级别的单例中持有,Channel只在初始化时创建一次。Activity 重建时,通过 ViewModel 恢复状态,再重新注册 BroadcastReceiver。如果你的项目用了 AppCompat,还要注意 Android 13 上动态广播注册会增加RECEIVER_EXPORTED参数,Wi-Fi Direct 广播属于系统广播,通常不需要 exported 标志,传Context.RECEIVER_EXPORTED即可。

6. 进阶改造:从 Demo 到可用模块的三项值得做的事

官方 Demo 里有一句话很重要:它演示的是链路层的用法,不提供企业级的稳定性。当你决定在业务里正式使用 Wi-Fi Direct 时,至少要完成以下三项改造。

第一项改造是建立自己的连接超时与重试机制。上面提到的连接超时只是表面问题,更深层的是设备在出现异常状态时,系统很容易把后续请求都标记为BUSY。我的做法是封装一个ConnectionSupervisor,它会监控所有 ActionListener 回调,如果连续三次收到BUSY,强制重启 Wi-Fi Direct 通道并重置状态机。看起来不复杂,但在生产环境里能减少一半的客服反馈。

第二项改造是把文件传输和消息传输分开。Wi-Fi Direct 本身和 TCP 的传输能力是绑定在一起的,但大文件传输时直接写Socket很容易阻塞,最好引入一个简单的分包协议:固定 8 字节包头表示总长度和当前分片序号,每次分片大小设为 64KB。Wi-Fi Direct 的实际吞吐量在不同设备上差异很大,有的旧设备只能跑 5 MB/s,但在一些手机上能做到 20 MB/s,不要按理论值去设并发数或缓冲区。

第三项改造是增加一个设备级的自检接口。这个接口用来在正式通信前确认对方 App 是否在线。我之前在模拟项目X里就是一个 Android 端和一个嵌入式 Linux 端互相连,嵌入式端不懂 Android 的 Wi-Fi Direct 附加服务,于是双方约定连接建立后先发一个PROBE_DEVICE指令,收到PROBE_RESPONSE后才开始正式业务。这个「应用层 ping」机制可以过滤掉大量「连接成功但业务不可用」的假象。

最后说一个我踩过的坑:连接建立后,系统可能因为网络切换或休眠而悄悄断开底层的 P2P 群组,但你的 App 完全没有收到通知。Wi-Fi Direct 默认不提供心跳机制,所以我在业务层每秒发送一次心跳数据,连续三次没有回应就判定连接失效并自动发起重连。这个机制后来救过我很多次,尤其是在设备被用户锁定屏幕后,系统会进入省电模式,可能导致群组被系统自动关闭。维护一个 8 字节的心跳包成本极低,但带来的稳定性提升非常明显。

如果你刚接触 Wi-Fi Direct,建议先按第五章的清单把官方 Demo 完整跑通一次,别急着设计复杂的业务协议。链路层的手感和坑是写不出来的,只能靠真机反复试。等到你能闭着眼睛说出「现在设备处于什么状态、下一步该调用什么 API」的时候,再动手改造也不迟。希望这些经验能帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询