当前位置: 首页 > news >正文

Android WiFi协议之P2P介绍与实践

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. 工作流程

  1. 发现附近设备

  2. 请求连接

  3. 建立 P2P 组

  4. 数据传输

  5. 断开连接

二、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;
    }
    
    @Override
    public 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() {
    @Override
    public void onSuccess() {
        // 发现过程成功启动
    }
    
    @Override
    public void onFailure(int reason) {
        // 发现过程启动失败
    }
});

// 处理发现的设备列表
private WifiP2pManager.PeerListListener peerListListener = new WifiP2pManager.PeerListListener() {
    @Override
    public 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() {
    @Override
    public void onSuccess() {
        // 连接请求成功发送
    }
    
    @Override
    public void onFailure(int reason) {
        // 连接失败
    }
});

5. 获取连接信息

private WifiP2pManager.ConnectionInfoListener connectionInfoListener = 
    new WifiP2pManager.ConnectionInfoListener() {
        @Override
        public 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() {
    @Override
    public void onSuccess() {
        // 成功断开连接
    }
    
    @Override
    public void onFailure(int reason) {
        // 断开连接失败
    }
});

四、常见问题与解决方案

  1. 设备无法发现其他设备

    • 确保两台设备都启用了 WiFi P2P

    • 检查是否授予了必要权限(特别是位置权限)

    • 确保设备之间距离足够近(通常不超过10米)

  2. 连接失败

    • 检查设备是否支持 WiFi Direct

    • 尝试不同的 WPS 配置方法(PBC 或 KEYPAD)

    • 重启设备的 WiFi

  3. 数据传输问题

    • 确保在获取连接信息后才尝试建立套接字连接

    • 检查防火墙设置是否阻止了端口通信

    • 确保正确处理了网络操作线程(不要在UI线程执行网络操作)

  4. Android 12 及更高版本的兼容性

    • 添加 NEARBY_WIFI_DEVICES 权限

    • 如果不需要位置信息,设置 usesPermissionFlags="neverForLocation"

    • 考虑添加 ACCESS_COARSE_LOCATION 或 ACCESS_FINE_LOCATION 权限以获得更好的兼容性

五、最佳实践

  1. 用户体验优化

    • 在发现和连接过程中显示适当的进度指示

    • 提供明确的连接状态反馈

    • 处理各种错误情况并提供恢复选项

  2. 性能考虑

    • 发现过程消耗较多电量,应在必要时才启动

    • 连接建立后及时停止发现过程

    • 考虑使用服务来处理长时间运行的网络操作

  3. 安全性

    • 验证连接设备的身份(如设备名称或其他标识)

    • 考虑在应用层添加加密机制

    • 敏感数据传输使用安全协议

  4. 兼容性处理

    • 检查设备是否支持 WiFi P2P:manager != null && channel != null

    • 为旧版本 Android 提供备用方案

    • 处理不同厂商设备的兼容性问题

相关文章:

  • git功能点管理
  • Redis 与 MongoDB 对比分析
  • Stable Diffusion XL、SD3 与 Flux 模型常用优化器总结
  • 【群晖】挂载小雅alist到AList网盘中
  • Android Automotive车载系统面试题及参考答案
  • Swift语言的云存储
  • 11231231
  • 轨检探伤专用一体机平板电脑:为铁路安全保驾护航
  • docker的几种网络模式
  • 从搜索丝滑过渡到动态规划的学习指南
  • 数据库50个练习
  • 各开源协议一览
  • js前端对时间进行格式处理
  • 数据结构与算法-数学-基础数学算法(筛质数,最大公约数,最小公倍数,质因数算法,快速幂,乘法逆元,欧拉函数)
  • pyTorch-迁移学习-图片数据增强-四种天气图片的多分类问题
  • 群体智能优化算法-白鲨优化算法(White Shark Optimizer,WSO,含Matlab源代码)
  • JS中的WeakMap
  • 思考 - 操作系统
  • 路由器工作在OSI模型的哪一层?
  • babel-runtime 如何缩小打包体积
  • 雀巢中国回应“巴黎水”丑闻报告:在中国销售的产品均符合相关法律法规要求
  • 上海合作组织减贫和可持续发展论坛开幕,沈跃跃宣读习近平主席贺信
  • 国家统计局答澎湃:我国投资的潜力依然巨大,支撑投资增长的有利因素仍然比较多
  • 东航C919航线上新!正式投入上海虹桥—深圳航线运营
  • 墨西哥海军一载两百余人帆船撞上纽约布鲁克林大桥,多人落水
  • 经济日报金观平:促进信贷资金畅达小微企业