一. 打开Wi-Fi direct
1.必须启用Wi-Fi功能:在设备设置中开启Wi-Fi主开关(即使未连接路由器)
关闭冲突功能:若已开启「热点共享」或连接到其他Wi-Fi网络,需先关闭相关功能以避免硬件占.
<!-- Wi-Fi Direct 核心权限 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
<!-- Android 10+ 需位置权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
1.1.代码调用打开WIFI
// 获取Wi-Fi管理器实例
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
// 开启Wi-Fi
if (!wifiManager.isWifiEnabled()) {
wifiManager.setWifiEnabled(true); // API 28以下可调用,高版本需跳转系统设置页:ml-citation{ref="1,4" data="citationList"}
}
1.2.跳转系统Wi-Fi设置页(适用于无法直接控制Wi-Fi的情况)
startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
2.在系统设置中进入Wi-Fi菜单,点击右上角「高级」选项,找到并启用Wi-Fi Direct(部分设备显示为「WLAN直连」或「附近设备」)
- 位置权限开关
Android 10及以上版本:需在设置中打开位置信息(GPS)权限,否则Wi-Fi Direct功能可能被禁用或无法扫描设备
动态权限申请:应用需通过弹窗申请ACCESS_FINE_LOCATION权限,用户需手动授
二.连接设备,数据通信
1.客户端设备处理
1.1 客户端注册广播监听
注册广播监听,包括:
#1.启用/禁用 Wi-Fi P2P 功能。
#2.扫描到附近的设备或者当设备处于可发现状态
#3.连接状态变化
java
WifiP2pManager manager = (WifiP2pManager) MyApplication.getAppContext().getSystemService(Context.WIFI_P2P_SERVICE);
WifiP2pManager.Channel channel = manager.initialize(MyApplication.getAppContext(), getMainLooper(), null);
// 客户端设备(主动发起连接的设备)注册广播接收器监听设备发现
private BroadcastReceiver clientReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
// 检查 Wi-Fi Direct 是否启用
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
// 功能已启用,一般是收到功能已启用执行1.设备发现
discoverPeers();
} else {
// 功能未启用
}
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
// 监听扫描到附近的设备或者当设备处于可发现状态(如其他设备开启 P2P 搜索或加入/退出网络)
manager.requestPeers(channel, peerList -> {
// 处理设备列表
Collection<WifiP2pDevice> devices = peerList.getDeviceList();
// 更新 UI 显示设备列表
for (WifiP2pDevice device : devices) {
//选择需要连接的WifiP2pDevice设备,
clientConnectP2pDevice(MacAddress.fromString(device.deviceAddress));
}
});
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
//连接状态变化监听 如服务端接受连接并创建组后
manager.requestConnectionInfo(channel, info -> {
InetAddress groupOwnerAddress = info.groupOwnerAddress;
if (info.groupFormed && !info.isGroupOwner) {
// 客户端逻辑:连接群主 IP 的指定端口
try {
clientSocketConnect(context, groupOwnerAddress.getHostAddress());
} catch (IOException e) {
throw new RuntimeException(e);
}
} else if (info.isGroupOwner) {
// 群主逻辑:启动服务端 Socket 这里是客户端不会处理这段
}
});
}
}
};
/**
* 客户端步骤1
* 注册广播监听,包括:
* 1.启用/禁用 Wi-Fi P2P 功能。
* 2.扫描到附近的设备或者当设备处于可发现状态
* 3.连接状态变化
*/
private void clientRegisterWifiListen() {
// 注册接收器
IntentFilter intentFilter = new IntentFilter();
//WIFI_P2P_STATE_CHANGED_ACTION监听 启用/禁用 Wi-Fi P2P 功能
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
MyApplication.getAppContext().registerReceiver(clientReceiver, intentFilter);
}
1.2 主动搜索设备
客户端在检查 Wi-Fi Direct已启用时,主动搜索设备
java
/**
* 客户端步骤2
* 客户端在检查 Wi-Fi Direct已启用时,主动搜索设备
*/
private void discoverPeers() {
manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
// 发现设备成功,客户端会收到WIFI_P2P_PEERS_CHANGED_ACTION广播
}
@Override
public void onFailure(int reason) {
// 失败处理
}
});
}
1.3 选择设备连接
客户端在扫描到附近设备,选择设备连接
java
/**
* 客户端步骤3
* 客户端在扫描到附近设备,选择设备连接
*
* @param targetDeviceAddress
*/
private void clientConnectP2pDevice(MacAddress targetDeviceAddress) {
WifiP2pConfig config = new WifiP2pConfig.Builder()
.setDeviceAddress(targetDeviceAddress)
.build();
manager.connect(channel, config, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
//连接成功后
}
@Override
public void onFailure(int reason) {
}
});
//发起 connect() 请求后,需验证连接是否成功建立
manager.requestConnectionInfo(channel, info -> {
InetAddress groupOwnerAddress = info.groupOwnerAddress;
if (info.groupFormed && !info.isGroupOwner) {
// 客户端逻辑:连接群主 IP 的指定端口
try {
clientSocketConnect(MyApplication.getAppContext(), groupOwnerAddress.getHostAddress());
} catch (IOException e) {
throw new RuntimeException(e);
}
} else if (info.isGroupOwner) {
// 群主逻辑:启动服务端 Socket 这里是客户端不会处理这段
}
});
}
1.4 socket连接数据通信
客户端在监听到连接状态变化(服务端同意连接并创建组)获取到服务端ip地址和服务端创建的socket端口进行数据通信。
java
/**
* 客户端步骤4
* 客户端在监听到连接状态变化(服务端同意连接并创建组)获取到服务端ip地址和服务端
* 创建的socket端口进行数据通信
*
* @param context
* @param serverIP
* @throws IOException
*/
private void clientSocketConnect(Context context, String serverIP) throws IOException {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
Socket socket = new Socket();
socket.connect(new InetSocketAddress(serverIP, 8888));
//连接之后就可以获取输入输出流进行 读写操作了
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
}
2.服务端设备处理
2.1 服务端注册广播监听
注册广播监听 连接状态变化(监听到客户端连接请求)
java
// 服务端(等待连接的设备)注册广播接收器
private final BroadcastReceiver p2pConnectReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
WifiP2pInfo p2pInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO);
if (networkInfo.isConnected()) {
// 连接已建立,处理群组信息(如群组所有者 IP 和角色)可进行数据传输
} else {
//服务端在收到连接请求后会默认成为组所有者并自动创建组。一般不需要调用acceptConnection
//若需要确保服务端始终为组所有者(而非由系统自动协商决定),需手动调用 createGroup()
acceptConnection();
}
}
}
};
/**
* 服务端步骤1
* 注册广播监听 连接状态变化(监听到客户端连接请求)
*/
private void serverRegisterWifiListen() {
// 服务端注册接收器
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
MyApplication.getAppContext().registerReceiver(p2pConnectReceiver, intentFilter);
}
2.2 接受连接创建群组
服务端如果接受连接后调用 WifiP2pManager.createGroup() 创建群组(作为群组所有者)
若设备需自动接受连接(如预配置场景),可直接调用 createGroup() 或响应连接请求
java
/**
* 服务端步骤2
* 服务端如果接受连接后调用 WifiP2pManager.createGroup() 创建群组(作为群组所有者)
* 若设备需自动接受连接(如预配置场景),可直接调用 createGroup() 或响应连接请求
*/
private void acceptConnection() {
WifiP2pManager manager = (WifiP2pManager) MyApplication.getAppContext().getSystemService(Context.WIFI_P2P_SERVICE);
WifiP2pManager.Channel channel = manager.initialize(MyApplication.getAppContext(), getMainLooper(), null);
manager.createGroup(channel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
//群组创建成功,被连接方成为群组所有者
//此时客户端会收到WIFI_P2P_PEERS_CHANGED_ACTION广播,且可以获取到当前服务端的WifiP2pDevice对象
//服务端创建socket 等待连接
createServiceSocket();
}
@Override
public void onFailure(int reason) {
// 处理失败逻辑(如显示错误提示)
}
});
}
2.3 创建服务端socket 和客户端通信
创建服务端socket等待客户端连接
java
/**
* 服务端步骤3
* 创建服务端socket等待客户端连接
*/
private void createServiceSocket() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8888);
Socket clientSocket = serverSocket.accept();
//连接之后就可以获取输入输出流进行 读写操作了
InputStream inputStream = clientSocket.getInputStream();
OutputStream outputStream = clientSocket.getOutputStream();
} catch (IOException e) {
throw new RuntimeException(e);
}
}