HarmonyOS APP点对点直连通信
HarmonyOS APP点对点直连通信
传统的WiFi通信需要路由器作为中转,但有时候我们希望两台设备直接"对话"——不经过任何中间设备,速度更快、延迟更低。这就是WiFi P2P(Wi-Fi Direct)的用武之地。今天咱们就来聊聊鸿蒙系统中的WiFi P2P技术,看看如何实现设备间的点对点直连通信。
一、背景与动机
1.1 WiFi P2P的优势与应用场景
WiFi P2P(也叫Wi-Fi Direct)允许两台设备在不需要路由器的情况下直接建立WiFi连接。相比传统方案,它有这些优势:
| 对比项 | 传统WiFi | WiFi热点 | WiFi P2P |
|---|---|---|---|
| 是否需要路由器 | 需要 | 不需要 | 不需要 |
| 连接速度 | 受路由器限制 | 较快 | 最快 |
| 配置复杂度 | 中等 | 较高 | 低(一键连接) |
| 功耗 | 低 | 高 | 中等 |
| 同时连接数 | 多 | 多 | 有限 |
典型应用场景:
- 快速文件传输:两台手机间传输大文件,速度可达数百Mbps
- 无线投屏:手机直接投屏到电视,无需同一WiFi
- 多人游戏:本地多人游戏,低延迟通信
- 打印机连接:手机直接连接WiFi打印机
- 设备发现:快速发现附近的设备
1.2 WiFi P2P工作原理
WiFi P2P的核心是"Group Owner(GO)"机制。连接时,一台设备会自动成为GO(类似热点),另一台成为Client。这个过程对用户是透明的,系统自动协商决定。

二、核心原理
2.1 P2P连接流程详解
完整的P2P连接包含发现、连接、数据传输三个阶段:

2.2 P2P设备信息结构
interface P2pDeviceInfo {
// 设备名称
deviceName: string;
// 设备MAC地址
deviceAddress: string;
// 设备类型(手机、电视、打印机等)
primaryDeviceType: string;
// 是否为Group Owner
isGroupOwner: boolean;
// WPS配置方法
wpsConfigMethod: number;
// 设备状态
deviceStatus: P2pDeviceStatus;
// 信号强度
signalStrength?: number;
}
2.3 GO协商机制
GO协商是P2P的核心机制,决定了哪台设备成为"热点":
协商因素:
- Intent值:每台设备有一个3-15的Intent值,值越大越倾向于成为GO
- 设备能力:有些设备(如电视)更适合做GO
- 电量状态:低电量设备倾向于做Client
// Intent值说明
const P2P_INTENT = {
MIN: 0, // 最小值,倾向于做Client
LOW: 3, // 低优先级
NORMAL: 7, // 正常优先级
HIGH: 11, // 高优先级
MAX: 15 // 最大值,倾向于做GO
};
// 设置Intent值
await wifiP2p.setP2pIntent(P2P_INTENT.HIGH); // 更倾向于成为GO
三、代码实战
3.1 P2P管理核心类封装
import wifiP2p from '@ohos.wifiP2p';
import { BusinessError } from '@ohos.base';
/**
* WiFi P2P管理器
* 封装P2P发现、连接、通信等核心功能
*/
export class WifiP2pManager {
private static instance: WifiP2pManager;
private discoveredDevices: Array<wifiP2p.WifiP2pDevice> = [];
private connectedDevice: wifiP2p.WifiP2pDevice | null = null;
private p2pGroupInfo: wifiP2p.WifiP2pGroupInfo | null = null;
// 回调函数
private onDeviceDiscovered: ((device: wifiP2p.WifiP2pDevice) => void) | null = null;
private onConnectionChanged: ((state: wifiP2p.P2pConnectState) => void) | null = null;
private onGroupChanged: ((info: wifiP2p.WifiP2pGroupInfo) => void) | null = null;
private constructor() {
this.initEventListeners();
}
/**
* 获取单例实例
*/
public static getInstance(): WifiP2pManager {
if (!WifiP2pManager.instance) {
WifiP2pManager.instance = new WifiP2pManager();
}
return WifiP2pManager.instance;
}
/**
* 初始化事件监听
*/
private initEventListeners(): void {
// 监听P2P设备发现
wifiP2p.on('p2pDeviceChange', (device: wifiP2p.WifiP2pDevice) => {
console.info(`[P2P] 发现设备: ${device.deviceName}`);
// 更新设备列表
const index = this.discoveredDevices.findIndex(
d => d.deviceAddress === device.deviceAddress
);
if (index >= 0) {
this.discoveredDevices[index] = device;
} else {
this.discoveredDevices.push(device);
}
if (this.onDeviceDiscovered) {
this.onDeviceDiscovered(device);
}
});
// 监听连接状态变化
wifiP2p.on('p2pConnectionChange', (state: wifiP2p.P2pConnectState) => {
console.info(`[P2P] 连接状态: ${state}`);
if (this.onConnectionChanged) {
this.onConnectionChanged(state);
}
});
// 监听P2P组变化
wifiP2p.on('p2pGroupChange', () => {
this.updateGroupInfo();
});
// 监听本设备状态变化
wifiP2p.on('p2pStateChange', (state: number) => {
const stateText = state === 1 ? '可用' : '不可用';
console.info(`[P2P] 状态变化: ${stateText}`);
});
}
/**
* 开启P2P功能
*/
public async enableP2p(): Promise<boolean> {
try {
await wifiP2p.enableP2p();
console.info('[P2P] 已开启');
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[P2P] 开启失败: ${err.message}`);
return false;
}
}
/**
* 关闭P2P功能
*/
public async disableP2p(): Promise<boolean> {
try {
await wifiP2p.disableP2p();
console.info('[P2P] 已关闭');
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[P2P] 关闭失败: ${err.message}`);
return false;
}
}
/**
* 发起设备发现
*/
public async startDiscovery(): Promise<boolean> {
try {
// 清空已发现的设备列表
this.discoveredDevices = [];
await wifiP2p.discoverDevices();
console.info('[P2P] 开始发现设备');
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[P2P] 发现失败: ${err.message}`);
return false;
}
}
/**
* 停止设备发现
*/
public async stopDiscovery(): Promise<boolean> {
try {
await wifiP2p.stopDiscoverDevices();
console.info('[P2P] 停止发现');
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[P2P] 停止失败: ${err.message}`);
return false;
}
}
/**
* 获取已发现的设备列表
*/
public getDiscoveredDevices(): Array<wifiP2p.WifiP2pDevice> {
return this.discoveredDevices;
}
/**
* 连接到指定设备
* @param deviceAddress 设备MAC地址
* @param configMethod WPS配置方法
*/
public async connectToDevice(
deviceAddress: string,
configMethod: wifiP2p.WpsConfigMethod = wifiP2p.WpsConfigMethod.WPS_PBC
): Promise<boolean> {
try {
// 构建连接配置
const config: wifiP2p.WifiP2pConfig = {
deviceAddress: deviceAddress,
wpsInfo: {
wpsConfigMethod: configMethod
}
};
await wifiP2p.connect(config);
console.info(`[P2P] 正在连接到 ${deviceAddress}`);
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[P2P] 连接失败: ${err.message}`);
return false;
}
}
/**
* 使用PIN码连接
* @param deviceAddress 设备地址
* @param pin PIN码
*/
public async connectWithPin(deviceAddress: string, pin: string): Promise<boolean> {
try {
const config: wifiP2p.WifiP2pConfig = {
deviceAddress: deviceAddress,
wpsInfo: {
wpsConfigMethod: wifiP2p.WpsConfigMethod.WPS_PIN_DISPLAY,
pin: pin
}
};
await wifiP2p.connect(config);
console.info(`[P2P] 使用PIN连接: ${pin}`);
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[P2P] PIN连接失败: ${err.message}`);
return false;
}
}
/**
* 断开P2P连接
*/
public async disconnect(): Promise<boolean> {
try {
await wifiP2p.disconnect();
this.connectedDevice = null;
this.p2pGroupInfo = null;
console.info('[P2P] 已断开连接');
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[P2P] 断开失败: ${err.message}`);
return false;
}
}
/**
* 创建P2P组(成为GO)
*/
public async createGroup(): Promise<boolean> {
try {
await wifiP2p.createGroup();
console.info('[P2P] 已创建组(成为GO)');
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[P2P] 创建组失败: ${err.message}`);
return false;
}
}
/**
* 删除P2P组
*/
public async removeGroup(): Promise<boolean> {
try {
await wifiP2p.removeGroup();
console.info('[P2P] 已删除组');
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[P2P] 删除组失败: ${err.message}`);
return false;
}
}
/**
* 获取当前组信息
*/
public async getGroupInfo(): Promise<wifiP2p.WifiP2pGroupInfo | null> {
try {
const info = await wifiP2p.getCurrentGroup();
this.p2pGroupInfo = info;
console.info(`[P2P] 组信息: GO=${info.isGroupOwner}, 地址=${info.groupOwnerAddress}`);
return info;
} catch (error) {
const err = error as BusinessError;
console.error(`[P2P] 获取组信息失败: ${err.message}`);
return null;
}
}
/**
* 更新组信息
*/
private async updateGroupInfo(): Promise<void> {
const info = await this.getGroupInfo();
if (info && this.onGroupChanged) {
this.onGroupChanged(info);
}
}
/**
* 获取P2P连接信息
*/
public async getLinkedInfo(): Promise<wifiP2p.WifiP2pLinkedInfo | null> {
try {
const info = await wifiP2p.getP2pLinkedInfo();
console.info(`[P2P] 连接信息: ${info.connectState}`);
return info;
} catch (error) {
const err = error as BusinessError;
console.error(`[P2P] 获取连接信息失败: ${err.message}`);
return null;
}
}
/**
* 设置回调函数
*/
public setOnDeviceDiscovered(callback: (device: wifiP2p.WifiP2pDevice) => void): void {
this.onDeviceDiscovered = callback;
}
public setOnConnectionChanged(callback: (state: wifiP2p.P2pConnectState) => void): void {
this.onConnectionChanged = callback;
}
public setOnGroupChanged(callback: (info: wifiP2p.WifiP2pGroupInfo) => void): void {
this.onGroupChanged = callback;
}
/**
* 移除所有监听
*/
public removeAllListeners(): void {
wifiP2p.off('p2pDeviceChange');
wifiP2p.off('p2pConnectionChange');
wifiP2p.off('p2pGroupChange');
wifiP2p.off('p2pStateChange');
console.info('[P2P] 已移除所有监听');
}
/**
* 判断是否为Group Owner
*/
public async isGroupOwner(): Promise<boolean> {
const info = await this.getGroupInfo();
return info ? info.isGroupOwner : false;
}
/**
* 获取对方设备的IP地址
*/
public async getPeerIpAddress(): Promise<string | null> {
const info = await this.getGroupInfo();
if (!info) return null;
if (info.isGroupOwner) {
// 本设备是GO,对方是Client
// 需要从组信息中获取Client的IP
return info.groupOwnerAddress; // 简化处理
} else {
// 本设备是Client,对方是GO
return info.groupOwnerAddress;
}
}
}
3.2 P2P设备发现与连接UI
import { WifiP2pManager } from './WifiP2pManager';
import wifiP2p from '@ohos.wifiP2p';
@Entry
@Component
struct P2pConnectPage {
private p2pManager: WifiP2pManager = WifiP2pManager.getInstance();
@State isP2pEnabled: boolean = false;
@State isDiscovering: boolean = false;
@State discoveredDevices: Array<wifiP2p.WifiP2pDevice> = [];
@State isConnected: boolean = false;
@State connectedDeviceName: string = '';
@State isGroupOwner: boolean = false;
@State groupInfo: string = '';
aboutToAppear(): void {
this.checkP2pState();
this.registerCallbacks();
}
aboutToDisappear(): void {
this.p2pManager.removeAllListeners();
}
/**
* 检查P2P状态
*/
async checkP2pState(): Promise<void> {
// 假设有方法检查状态
this.isP2pEnabled = true; // 实际需要调用API
}
/**
* 注册回调
*/
registerCallbacks(): void {
// 设备发现回调
this.p2pManager.setOnDeviceDiscovered((device: wifiP2p.WifiP2pDevice) => {
this.discoveredDevices = this.p2pManager.getDiscoveredDevices();
});
// 连接状态回调
this.p2pManager.setOnConnectionChanged((state: wifiP2p.P2pConnectState) => {
if (state === wifiP2p.P2pConnectState.P2P_CONNECTED) {
this.isConnected = true;
this.updateConnectionInfo();
} else {
this.isConnected = false;
this.connectedDeviceName = '';
}
});
// 组信息回调
this.p2pManager.setOnGroupChanged((info: wifiP2p.WifiP2pGroupInfo) => {
this.isGroupOwner = info.isGroupOwner;
this.groupInfo = info.isGroupOwner ? '本设备为GO' : '对方为GO';
});
}
/**
* 更新连接信息
*/
async updateConnectionInfo(): Promise<void> {
const info = await this.p2pManager.getGroupInfo();
if (info) {
this.isGroupOwner = info.isGroupOwner;
this.groupInfo = `GO: ${info.passphrase}`;
}
}
/**
* 开启P2P
*/
async enableP2p(): Promise<void> {
const success = await this.p2pManager.enableP2p();
if (success) {
this.isP2pEnabled = true;
}
}
/**
* 开始发现设备
*/
async startDiscovery(): Promise<void> {
this.isDiscovering = true;
const success = await this.p2pManager.startDiscovery();
if (!success) {
this.isDiscovering = false;
}
// 设置发现超时
setTimeout(() => {
if (this.isDiscovering) {
this.p2pManager.stopDiscovery();
this.isDiscovering = false;
}
}, 60000); // 60秒超时
}
/**
* 停止发现
*/
async stopDiscovery(): Promise<void> {
await this.p2pManager.stopDiscovery();
this.isDiscovering = false;
}
/**
* 连接到设备
*/
async connectDevice(device: wifiP2p.WifiP2pDevice): Promise<void> {
const success = await this.p2pManager.connectToDevice(device.deviceAddress);
if (success) {
this.connectedDeviceName = device.deviceName;
}
}
/**
* 断开连接
*/
async disconnect(): Promise<void> {
await this.p2pManager.disconnect();
this.isConnected = false;
this.connectedDeviceName = '';
}
build() {
Column() {
// 标题栏
Row() {
Text('WiFi P2P')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor('#FFFFFF')
Blank()
Toggle({ type: ToggleType.Switch, isOn: this.isP2pEnabled })
.onChange((isOn: boolean) => {
if (isOn) {
this.enableP2p();
} else {
this.p2pManager.disableP2p();
this.isP2pEnabled = false;
}
})
}
.width('100%')
.padding(20)
.backgroundColor('#1A1A2E')
// 连接状态
if (this.isConnected) {
Column() {
Row() {
Text('已连接')
.fontSize(16)
.fontColor('#4CAF50')
Text(this.connectedDeviceName)
.fontSize(14)
.fontColor('#FFFFFF')
.margin({ left: 10 })
}
.width('100%')
Row() {
Text(this.groupInfo)
.fontSize(12)
.fontColor('#AAAAAA')
Blank()
Text(this.isGroupOwner ? 'GO' : 'Client')
.fontSize(12)
.fontColor('#F5A623')
}
.width('100%')
.margin({ top: 10 })
Button('断开连接')
.width('100%')
.height(40)
.backgroundColor('#FF5722')
.margin({ top: 15 })
.onClick(() => {
this.disconnect();
})
}
.width('90%')
.padding(20)
.backgroundColor('#16213E')
.borderRadius(12)
.margin({ top: 20 })
}
// 发现按钮
if (this.isP2pEnabled && !this.isConnected) {
Button(this.isDiscovering ? '发现中...' : '发现设备')
.width('90%')
.height(50)
.backgroundColor(this.isDiscovering ? '#666666' : '#4A90E2')
.enabled(!this.isDiscovering)
.onClick(() => {
this.startDiscovery();
})
.margin({ top: 20 })
if (this.isDiscovering) {
Button('停止发现')
.width('90%')
.height(40)
.backgroundColor('#F5A623')
.margin({ top: 10 })
.onClick(() => {
this.stopDiscovery();
})
}
}
// 设备列表
if (this.discoveredDevices.length > 0) {
Column() {
Text(`发现 ${this.discoveredDevices.length} 台设备`)
.fontSize(16)
.fontColor('#FFFFFF')
.width('100%')
.margin({ bottom: 15 })
List() {
ForEach(this.discoveredDevices, (device: wifiP2p.WifiP2pDevice) => {
ListItem() {
Row() {
Column() {
Text(device.deviceName || '未知设备')
.fontSize(16)
.fontColor('#FFFFFF')
Text(device.deviceAddress)
.fontSize(12)
.fontColor('#AAAAAA')
.margin({ top: 5 })
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
Button('连接')
.width(70)
.height(35)
.backgroundColor('#4A90E2')
.onClick(() => {
this.connectDevice(device);
})
}
.width('100%')
.padding(15)
.backgroundColor('#1A1A2E')
.borderRadius(8)
.margin({ bottom: 10 })
}
}, (device: wifiP2p.WifiP2pDevice) => device.deviceAddress)
}
.width('100%')
.layoutWeight(1)
}
.width('90%')
.padding(20)
.backgroundColor('#16213E')
.borderRadius(12)
.margin({ top: 20 })
.layoutWeight(1)
}
// 提示信息
if (!this.isP2pEnabled) {
Column() {
Text('P2P功能未开启')
.fontSize(18)
.fontColor('#AAAAAA')
Text('请开启WiFi P2P功能')
.fontSize(14)
.fontColor('#666666')
.margin({ top: 10 })
}
.margin({ top: 100 })
}
}
.width('100%')
.height('100%')
.backgroundColor('#0F0F1A')
}
}
3.3 P2P数据传输实现
P2P连接建立后,需要通过Socket进行数据传输:
import socket from '@ohos.net.socket';
import { WifiP2pManager } from './WifiP2pManager';
/**
* P2P数据传输管理器
* 处理Socket通信
*/
export class P2pDataTransfer {
private static instance: P2pDataTransfer;
private p2pManager: WifiP2pManager = WifiP2pManager.getInstance();
private serverSocket: socket.TCPSocket | null = null;
private clientSocket: socket.TCPSocket | null = null;
private port: number = 8888;
private isServer: boolean = false;
// 数据接收回调
private onDataReceived: ((data: string) => void) | null = null;
private constructor() {}
public static getInstance(): P2pDataTransfer {
if (!P2pDataTransfer.instance) {
P2pDataTransfer.instance = new P2pDataTransfer();
}
return P2pDataTransfer.instance;
}
/**
* 初始化数据通道
* GO作为服务端,Client作为客户端
*/
public async initDataChannel(): Promise<boolean> {
const isGO = await this.p2pManager.isGroupOwner();
this.isServer = isGO;
if (isGO) {
// 作为服务端,监听连接
return await this.startServer();
} else {
// 作为客户端,连接服务端
return await this.connectToServer();
}
}
/**
* 启动服务端(GO)
*/
private async startServer(): Promise<boolean> {
try {
this.serverSocket = socket.constructTCPSocketInstance();
// 绑定端口
await this.serverSocket.bind({
address: '0.0.0.0',
port: this.port,
family: 1 // IPv4
});
// 监听连接
this.serverSocket.on('connect', (client: socket.TCPSocket) => {
console.info('[P2P传输] 客户端已连接');
this.clientSocket = client;
this.setupDataReceiver(client);
});
await this.serverSocket.listen(5);
console.info(`[P2P传输] 服务端已启动,端口: ${this.port}`);
return true;
} catch (error) {
console.error('[P2P传输] 启动服务端失败:', error);
return false;
}
}
/**
* 连接到服务端(Client)
*/
private async connectToServer(): Promise<boolean> {
try {
const peerIp = await this.p2pManager.getPeerIpAddress();
if (!peerIp) {
console.error('[P2P传输] 无法获取对方IP');
return false;
}
this.clientSocket = socket.constructTCPSocketInstance();
// 连接服务端
await this.clientSocket.connect({
address: peerIp,
port: this.port,
family: 1,
timeout: 10000
});
console.info(`[P2P传输] 已连接到服务端: ${peerIp}:${this.port}`);
this.setupDataReceiver(this.clientSocket);
return true;
} catch (error) {
console.error('[P2P传输] 连接服务端失败:', error);
return false;
}
}
/**
* 设置数据接收器
*/
private setupDataReceiver(socket: socket.TCPSocket): void {
socket.on('message', (value: socket.SocketMessageInfo) => {
const data = String.fromCharCode.apply(null, Array.from(value.message));
console.info(`[P2P传输] 收到数据: ${data.length} 字节`);
if (this.onDataReceived) {
this.onDataReceived(data);
}
});
socket.on('close', () => {
console.info('[P2P传输] 连接已关闭');
this.clientSocket = null;
});
socket.on('error', (err: socket.SocketError) => {
console.error('[P2P传输] Socket错误:', err);
});
}
/**
* 发送数据
*/
public async sendData(data: string): Promise<boolean> {
if (!this.clientSocket) {
console.error('[P2P传输] 未连接');
return false;
}
try {
const buffer = new ArrayBuffer(data.length);
const view = new Uint8Array(buffer);
for (let i = 0; i < data.length; i++) {
view[i] = data.charCodeAt(i);
}
await this.clientSocket.send({
data: buffer
});
console.info(`[P2P传输] 发送成功: ${data.length} 字节`);
return true;
} catch (error) {
console.error('[P2P传输] 发送失败:', error);
return false;
}
}
/**
* 发送文件
* 大文件分块发送
*/
public async sendFile(filePath: string, onProgress?: (progress: number) => void): Promise<boolean> {
// 实际项目中需要:
// 1. 读取文件
// 2. 分块发送
// 3. 报告进度
console.info(`[P2P传输] 发送文件: ${filePath}`);
return true;
}
/**
* 设置数据接收回调
*/
public setOnDataReceived(callback: (data: string) => void): void {
this.onDataReceived = callback;
}
/**
* 关闭数据通道
*/
public async closeDataChannel(): Promise<void> {
if (this.clientSocket) {
await this.clientSocket.close();
this.clientSocket = null;
}
if (this.serverSocket) {
await this.serverSocket.close();
this.serverSocket = null;
}
console.info('[P2P传输] 数据通道已关闭');
}
}
四、踩坑与注意事项
4.1 权限配置
// module.json5
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.GET_WIFI_INFO",
"reason": "获取WiFi信息"
},
{
"name": "ohos.permission.SET_WIFI_INFO",
"reason": "修改WiFi设置"
},
{
"name": "ohos.permission.LOCATION",
"reason": "P2P发现需要位置权限"
},
{
"name": "ohos.permission.INTERNET",
"reason": "Socket通信需要"
}
]
}
}
4.2 发现超时处理
坑点:设备发现不会自动停止,需要手动控制。
/**
* 带超时的设备发现
*/
async function discoverWithTimeout(timeout: number = 60000): Promise<Array<wifiP2p.WifiP2pDevice>> {
const p2pManager = WifiP2pManager.getInstance();
await p2pManager.startDiscovery();
return new Promise((resolve) => {
const devices: Array<wifiP2p.WifiP2pDevice> = [];
p2pManager.setOnDeviceDiscovered((device) => {
devices.push(device);
});
setTimeout(async () => {
await p2pManager.stopDiscovery();
resolve(devices);
}, timeout);
});
}
4.3 连接重试机制
坑点:P2P连接可能失败,需要重试。
/**
* 带重试的P2P连接
*/
async function connectWithRetry(
deviceAddress: string,
maxRetries: number = 3
): Promise<boolean> {
const p2pManager = WifiP2pManager.getInstance();
for (let i = 0; i < maxRetries; i++) {
console.info(`[P2P] 连接尝试 ${i + 1}/${maxRetries}`);
const success = await p2pManager.connectToDevice(deviceAddress);
if (success) {
// 等待连接结果
const connected = await waitForConnection(10000);
if (connected) {
return true;
}
}
// 断开并重试
await p2pManager.disconnect();
await delay(2000);
}
return false;
}
async function waitForConnection(timeout: number): Promise<boolean> {
return new Promise((resolve) => {
let resolved = false;
const timer = setTimeout(() => {
if (!resolved) {
resolved = true;
resolve(false);
}
}, timeout);
const p2pManager = WifiP2pManager.getInstance();
p2pManager.setOnConnectionChanged((state) => {
if (!resolved && state === wifiP2p.P2pConnectState.P2P_CONNECTED) {
resolved = true;
clearTimeout(timer);
resolve(true);
}
});
});
}
function delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
4.4 GO与Client的IP分配
坑点:Client需要知道GO的IP才能建立Socket连接。
/**
* 获取正确的连接IP
*/
async function getConnectAddress(): Promise<string | null> {
const p2pManager = WifiP2pManager.getInstance();
const groupInfo = await p2pManager.getGroupInfo();
if (!groupInfo) return null;
if (groupInfo.isGroupOwner) {
// 本设备是GO,返回自己的IP
// 通常GO的IP是192.168.49.1
return '192.168.49.1';
} else {
// 本设备是Client,返回GO的IP
return groupInfo.groupOwnerAddress;
}
}
4.5 WiFi与P2P互斥
坑点:某些设备上,WiFi连接和P2P可能互斥。
/**
* 检查P2P可用性
*/
async function checkP2pAvailability(): Promise<boolean> {
try {
// 检查WiFi是否连接
const wifiLinked = await wifiManager.getLinkedInfo();
if (wifiLinked && wifiLinked.connState === wifiManager.WifiConnState.WIFI_CONNECTED) {
console.warn('[P2P] WiFi已连接,P2P可能受限');
// 某些设备支持并发,某些不支持
// 需要根据实际情况处理
}
return true;
} catch (error) {
return false;
}
}
五、HarmonyOS 6适配
5.1 API变更
| API | HarmonyOS 5 | HarmonyOS 6 | 说明 |
|---|---|---|---|
| discoverDevices() | 返回void | 返回Promise<boolean> | 改为异步 |
| connect() | 同步返回 | 异步返回 | 统一异步模式 |
| 新增 | - | getP2pDeviceInfo() | 获取详细设备信息 |
适配代码:
/**
* HarmonyOS 6 P2P适配
*/
async function discoverDevicesAdaptive(): Promise<boolean> {
const apiVersion = getApiVersion();
try {
if (apiVersion >= 6) {
// HarmonyOS 6
const result = await wifiP2p.discoverDevices();
return result;
} else {
// HarmonyOS 5
await wifiP2p.discoverDevices();
return true;
}
} catch (error) {
console.error('[P2P] 发现失败:', error);
return false;
}
}
5.2 新增功能
HarmonyOS 6增强了P2P能力:
// 1. 获取P2P设备详细信息
const detailedInfo = await wifiP2p.getP2pDeviceInfo(deviceAddress);
console.info(`设备类型: ${detailedInfo.primaryDeviceType}`);
console.info(`支持WFD: ${detailedInfo.wfdInfo?.wfdEnabled}`);
// 2. Wi-Fi Display(WFD)支持
await wifiP2p.startWfd({
deviceType: 'source', // 或'sink'
audioSupport: true
});
// 3. 服务发现(Service Discovery)
await wifiP2p.startServiceDiscovery({
serviceType: '_http._tcp',
protocol: 'bonjour'
});
// 4. P2P节能模式
await wifiP2p.setP2pPowerSaveMode(true);
5.3 性能优化
HarmonyOS 6提供了更多性能调优选项:
// 设置发现参数
await wifiP2p.setDiscoveryConfig({
scanInterval: 5000, // 扫描间隔
listenChannel: 6, // 监听信道
listenInterval: 500 // 监听间隔
});
// 设置连接参数
await wifiP2p.setConnectionConfig({
intentValue: 10, // Intent值
timeout: 30000, // 连接超时
retryCount: 3 // 重试次数
});
六、总结
WiFi P2P为设备间直接通信提供了高效的解决方案,特别适合文件传输、投屏、多人游戏等场景。本文全面讲解了鸿蒙系统中P2P的核心要点:
核心要点回顾:
- GO协商机制:理解Group Owner的角色分配逻辑
- 设备发现:合理控制发现时间和频率
- 连接管理:处理连接失败、重试、断开等场景
- 数据传输:通过Socket实现双向通信
- 互斥处理:注意WiFi连接与P2P的互斥关系
最佳实践建议:
- 封装统一的P2P管理类,简化使用
- 实现完善的连接重试机制
- 处理好GO和Client的角色差异
- 做好版本适配和兼容性处理
下一步学习:
- 蓝牙BLE扫描与连接(下一篇文章)
- 近场通信技术对比
- 多设备协同方案
- 无线投屏实现
WiFi P2P看似复杂,但掌握了核心原理后,实现起来其实并不困难。希望本文能帮助你建立起完整的知识体系,在实际开发中得心应手!
- 点赞
- 收藏
- 关注作者
评论(0)