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;}@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) {// 断开连接失败}
});

四、常见问题与解决方案

  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 提供备用方案

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/76435.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浅谈在HTTP中GET与POST的区别

从 HTTP 报文来看&#xff1a; GET请求方式将请求信息放在 URL 后面&#xff0c;请求信息和 URL 之间以 &#xff1f;隔开&#xff0c;请求信息的格式为键值对&#xff0c;这种请求方式将请求信息直接暴露在 URL 中&#xff0c;安全性比较低。另外从报文结构上来看&#xff0c…

若依微服务集成Flowable仿钉钉工作流

项目简介 本项目工作流模块集成在若依项目单独一个模块&#xff0c;可实现单独运行部署&#xff0c; 前端采用微前端&#xff0c;嵌入在若依的前端项目中。因博主是后端开发&#xff0c;对前端不是太属性&#xff0c;没将工作流模块前端代码移到若依前端。下面贴上代码工程结构…

WPS JS宏编程教程(从基础到进阶)-- 第六部分:JS集合与映射在 WPS 的应用

目录 第6章 JS集合与映射在 WPS 的应用6-1 集合的创建(实例:唯一值提取)示例代码详细解析Excel 环境模拟说明6-2 集合的不重复特性应用(案例:提取唯一值记录)示例代码详细解析案例说明6-3 集合成员添加与删除示例代码代码解析直观示意(Excel 模拟表格)6-4 集合成员添加…

MySQL 约束(入门版)

目录 一、约束的基本概念 二、约束演示 三、外键约束 &#xff08;一&#xff09;介绍 &#xff08;二&#xff09;外键约束语法 &#xff08;三&#xff09;删除/更新行为 一、约束的基本概念 1、概念&#xff1a;约束是作用于表中字段上的规则&#xff0c;用于限制存储…

【ISP】ISP pipeline(AI)

ISP Pipeline 全流程概览 ISP&#xff08;Image Signal Processing&#xff0c;图像信号处理&#xff09;流程通常从原始 Bayer 数据出发&#xff0c;经过一系列模块处理&#xff0c;逐步完成图像校正和增强&#xff0c;最终生成用于显示或编码的标准图像。常见处理模块包括&a…

【Rust开发】Rust快速入门,开发出Rust的第一个Hello World

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

Google Chrome下载受限制的解决方案【方法指南】

在国内使用网络时&#xff0c;部分用户在尝试访问Google Chrome官网下载谷歌浏览器时&#xff0c;常常遇到网页无法打开或文件下载失败的情况。这种下载受限制的问题多由网络访问政策或DNS解析异常导致。为了正常获取Google Chrome的最新版安装程序&#xff0c;用户需要通过一些…

使用 new EventSource 实现前端实时通信

示例&#xff1a; eventSource单向通信 1. 什么是 EventSource&#xff1f; EventSource 是浏览器提供的一种实现服务器推送&#xff08;Server-Sent Events&#xff0c;简称 SSE&#xff09;功能的 API。它是基于 HTTP 协议的单向通信机制&#xff0c;可以通过服务器将实时数…

Android Input——查找并添加目标窗口(七)

在 Android 输入系统中,InputDispatcher 的核心职责之一是将输入事件正确地传递到目标窗口。上一篇文章我们介绍到 InputDispatcher 事件分发调用到 findFocusedWindowTargetsLocked() 函数查找焦点窗口,并将焦点窗口添加到目标窗口,这里我们继续往下看。 一、获取焦点窗口…

Spring Boot中Spring MVC相关配置的详细描述及表格总结

以下是Spring Boot中Spring MVC相关配置的详细描述及表格总结&#xff1a; Spring MVC 配置项详解 1. 异步请求配置 spring.mvc.async.request-timeout 描述&#xff1a;设置异步请求的超时时间&#xff08;单位&#xff1a;毫秒&#xff09;。默认值&#xff1a;未设置&…

HTTP GET 和 POST 请求有什么区别

HTTP 的 GET 和 POST 请求是两种常见的 HTTP 请求方法&#xff0c;它们有不同的特点和应用场景。以下是它们的主要区别&#xff1a; 1. 用途 GET&#xff1a;用于从服务器获取数据或资源。GET 请求会附带查询参数在 URL 中&#xff0c;通常用于请求数据&#xff0c;如加载网页…

从入门到精通【MySQL】 联合查询

文章目录 &#x1f4d5;摘要&#x1f4d5;1. 多表联合查询时MySQL内部原理✏️1.1 实例&#xff1a;一个完整的联合查询过程 &#x1f4d5;2. 内连接&#x1f4d5;3. 外连接&#x1f4d5;4. 自连接&#x1f4d5;5. 子查询✏️5.1 单行子查询✏️5.2 多行子查询✏️5.3 多列子查…

高可用之战:Redis Sentinal(哨兵模式)

参考&#xff1a;Redis系列24&#xff1a;Redis使用规范 - Hello-Brand - 博客园 1 背景 在我们的《Redis高可用之战&#xff1a;主从架构》篇章中&#xff0c;介绍了Redis的主从架构模式&#xff0c;可以有效的提升Redis服务的可用性&#xff0c;减少甚至避免Redis服务发生完…

加密≠安全:文件夹密码遗忘背后的数据丢失风险与应对

在数字化时代&#xff0c;保护个人隐私和数据安全变得尤为重要。许多人选择对重要文件夹进行加密&#xff0c;以防止未经授权的访问。然而&#xff0c;一个常见且令人头疼的问题也随之而来——文件夹加密密码遗忘。当你突然发现自己无法访问那些加密的文件夹时&#xff0c;那种…

WPS宏开发手册——附录

目录 系列文章7、附录 系列文章 使用、工程、模块介绍 JSA语法 JSA语法练习题 Excel常用Api Excel实战 常见问题 附录 7、附录 颜色序列&#xff1a;在excel中设置颜色&#xff0c;只能设置颜色序号&#xff0c;不能直接设置rgb颜色 1、黑色 (Black)…

C++基础精讲-02

文章目录 1.C/C申请、释放堆空间的方式对比1.1C语言申请、释放堆空间1.2C申请、释放堆空间1.2.1 new表达式申请数组空间 1.3回收空间时的注意事项1.4malloc/free 和 new/delete 的区别 2.引用2.1 引用的概念2.2 引用的本质2.3 引用与指针的联系与区别2.4 引用的使用场景2.4.1 引…

Spring Boot MongoDB 分页工具类封装 (新手指南)

Spring Boot MongoDB 分页工具类封装 (新手指南) 目录 引言&#xff1a;为何需要分页工具类&#xff1f;工具类一&#xff1a;PaginationUtils - 简化 Pageable 创建 设计目标代码实现 (PaginationUtils.java)如何使用 PaginationUtils 工具类二&#xff1a;PageResponse<…

MyBatis的缓存、逆向工程、使用PageHelper、使用PageHelper

一、MyBatis的缓存 缓存&#xff1a;cache 缓存的作用&#xff1a;通过减少IO的方式&#xff0c;来提高程序的执行效率。 mybatis的缓存&#xff1a;将select语句的查询结果放到缓存&#xff08;内存&#xff09;当中&#xff0c;下一次还是这条select语句的话&#xff0c;直…

java中的JNI调用c库

1. 简单demo 如果是在某个项目中有包名就需要自己找ai问问去改写下cmd命令去编译执行等 java文件&#xff08;HelloJNI.java&#xff09; public class HelloJNI {// 声明 native 方法public native void sayHello();// 加载本地库static {System.loadLibrary("hello&quo…

人工智能:GPT技术应用与未来展望

GPT(Generative Pre-trained Transformer)作为自然语言处理领域的代表性技术,近年来在各行业的实际应用中展现出广泛潜力。结合其技术特性与行业需求,以下是GPT的主要应用场景、案例分析及未来挑战的总结: 一、核心应用领域与案例 文本生成与内容创作 自动化内容生产:GPT…