Android WiFi P2P
WiFi P2P (Peer-to-Peer) 是 Android 提供的一种允许设备之间直接通过 WiFi 进行通信的技术,无需接入传统的 WiFi 网络或互联网。这种技术也被称为 WiFi Direct。
一、WiFi P2P 基本概念
1. 核心组件
-
P2P 设备:支持 WiFi P2P 的 Android 设备
-
P2P 组:由一个组所有者(Group Owner, GO)和多个客户端组成
-
组所有者(GO):相当于传统 WiFi 网络中的接入点(AP)
-
客户端:连接到 GO 的设备
2. 工作流程
-
发现附近设备
-
请求连接
-
建立 P2P 组
-
数据传输
-
断开连接
二、WiFi P2P API 详解
1. 主要类
-
WifiP2pManager
:主管理类,提供发现、连接等方法 -
WifiP2pManager.Channel
:与 WiFi P2P 框架通信的通道 -
WifiP2pDevice
:表示一个 P2P 设备 -
WifiP2pInfo
:包含 P2P 连接信息 -
WifiP2pGroup
:表示 P2P 组信息 -
WifiP2pConfig
:用于配置 P2P 连接
2. 权限要求
在 AndroidManifest.xml 中添加:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" android:usesPermissionFlags="neverForLocation" />
注意:从 Android 12 开始,需要 NEARBY_WIFI_DEVICES 权限来发现和连接附近的设备
三、WiFi P2P 实现代码
1. 初始化
// 获取 WifiP2pManager 和 Channel
WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
Channel channel = manager.initialize(this, getMainLooper(), null);// 创建广播接收器
private final IntentFilter intentFilter = new IntentFilter();@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 添加必要的 Intent 过滤器intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);// 注册广播接收器receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);registerReceiver(receiver, intentFilter);
}
2. 广播接收器实现
public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {private WifiP2pManager manager;private Channel channel;private Activity activity;public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel, Activity activity) {this.manager = manager;this.channel = channel;this.activity = activity;}@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {// 检查 WiFi P2P 是否启用int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {// WiFi P2P 已启用} else {// WiFi P2P 未启用}} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {// 发现对等设备列表已更新if (manager != null) {manager.requestPeers(channel, peerListListener);}} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {// P2P 连接状态改变if (manager != null) {NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);if (networkInfo.isConnected()) {// 已连接,请求连接信息manager.requestConnectionInfo(channel, connectionInfoListener);}}} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {// 本设备信息已更新}}
}
3. 发现附近设备
// 开始发现设备
manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {@Overridepublic void onSuccess() {// 发现过程成功启动}@Overridepublic void onFailure(int reason) {// 发现过程启动失败}
});// 处理发现的设备列表
private WifiP2pManager.PeerListListener peerListListener = new WifiP2pManager.PeerListListener() {@Overridepublic void onPeersAvailable(WifiP2pDeviceList peers) {// 处理发现的设备列表List<WifiP2pDevice> devices = new ArrayList<>(peers.getDeviceList());// 更新UI或进行其他处理}
};
4. 连接设备
// 选择要连接的设备
WifiP2pDevice device = ...; // 从发现的设备列表中选择// 创建连接配置
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
config.wps.setup = WpsInfo.PBC; // 使用按钮配置方式// 发起连接
manager.connect(channel, config, new WifiP2pManager.ActionListener() {@Overridepublic void onSuccess() {// 连接请求成功发送}@Overridepublic void onFailure(int reason) {// 连接失败}
});
5. 获取连接信息
private WifiP2pManager.ConnectionInfoListener connectionInfoListener = new WifiP2pManager.ConnectionInfoListener() {@Overridepublic void onConnectionInfoAvailable(WifiP2pInfo info) {// 处理连接信息InetAddress groupOwnerAddress = info.groupOwnerAddress;if (info.groupFormed && info.isGroupOwner) {// 当前设备是组所有者(GO)// 需要在此处设置服务器套接字} else if (info.groupFormed) {// 当前设备是客户端// 需要连接到GO的IP地址}}};
6. 数据传输
建立连接后,可以使用套接字进行数据传输:
组所有者(GO)端代码
// 创建服务器套接字
ServerSocket serverSocket = new ServerSocket(8888);
Socket client = serverSocket.accept();// 获取输入输出流
DataInputStream inputStream = new DataInputStream(client.getInputStream());
DataOutputStream outputStream = new DataOutputStream(client.getOutputStream());// 读取数据
String message = inputStream.readUTF();// 发送数据
outputStream.writeUTF("Hello from GO!");
客户端端代码
// 连接到GO
Socket socket = new Socket(groupOwnerAddress.getHostAddress(), 8888);// 获取输入输出流
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());// 发送数据
outputStream.writeUTF("Hello from client!");// 读取数据
String message = inputStream.readUTF();
7. 断开连接
manager.removeGroup(channel, new WifiP2pManager.ActionListener() {@Overridepublic void onSuccess() {// 成功断开连接}@Overridepublic void onFailure(int reason) {// 断开连接失败}
});
四、常见问题与解决方案
-
设备无法发现其他设备
-
确保两台设备都启用了 WiFi P2P
-
检查是否授予了必要权限(特别是位置权限)
-
确保设备之间距离足够近(通常不超过10米)
-
-
连接失败
-
检查设备是否支持 WiFi Direct
-
尝试不同的 WPS 配置方法(PBC 或 KEYPAD)
-
重启设备的 WiFi
-
-
数据传输问题
-
确保在获取连接信息后才尝试建立套接字连接
-
检查防火墙设置是否阻止了端口通信
-
确保正确处理了网络操作线程(不要在UI线程执行网络操作)
-
-
Android 12 及更高版本的兼容性
-
添加 NEARBY_WIFI_DEVICES 权限
-
如果不需要位置信息,设置 usesPermissionFlags="neverForLocation"
-
考虑添加 ACCESS_COARSE_LOCATION 或 ACCESS_FINE_LOCATION 权限以获得更好的兼容性
-
五、最佳实践
-
用户体验优化
-
在发现和连接过程中显示适当的进度指示
-
提供明确的连接状态反馈
-
处理各种错误情况并提供恢复选项
-
-
性能考虑
-
发现过程消耗较多电量,应在必要时才启动
-
连接建立后及时停止发现过程
-
考虑使用服务来处理长时间运行的网络操作
-
-
安全性
-
验证连接设备的身份(如设备名称或其他标识)
-
考虑在应用层添加加密机制
-
敏感数据传输使用安全协议
-
-
兼容性处理
-
检查设备是否支持 WiFi P2P:
manager != null && channel != null
-
为旧版本 Android 提供备用方案
-
处理不同厂商设备的兼容性问题
-