Android 应用wifi direct连接通信实现

news2025/5/9 18:23:18

一. 打开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直连」或「附近设备」)
3. 位置权限开关
Android 10及以上版本:需在设置中打开位置信息(GPS)权限,否则Wi-Fi Direct功能可能被禁用或无法扫描设备
动态权限申请:应用需通过弹窗申请ACCESS_FINE_LOCATION权限,用户需手动授

二.连接设备,数据通信

1.客户端设备处理

1.1 客户端注册广播监听

注册广播监听,包括:
#1.启用/禁用 Wi-Fi P2P 功能。
#2.扫描到附近的设备或者当设备处于可发现状态
#3.连接状态变化

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已启用时,主动搜索设备

/**
 * 客户端步骤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 选择设备连接

客户端在扫描到附近设备,选择设备连接

/**
 * 客户端步骤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端口进行数据通信。

/**
 * 客户端步骤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 服务端注册广播监听

注册广播监听 连接状态变化(监听到客户端连接请求)

// 服务端(等待连接的设备)注册广播接收器
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() 或响应连接请求

/**
 * 服务端步骤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等待客户端连接

/**
 * 服务端步骤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);
    }
}

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

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

相关文章

【android telecom 框架分析 01】【基本介绍 2】【BluetoothPhoneService为何没有源码实现】

1. 背景 我们会在很多资料上看到 BluetoothPhoneService 类&#xff0c;但是我们在实际 aosp 中确找不到具体的实现&#xff0c; 这是为何&#xff1f; 这是一个很好的问题&#xff01;虽然在车载蓝牙电话场景中我们经常提到类似 BluetoothPhoneService 的概念&#xff0c;但…

【Harmony】文本公共接口EditMenuOptions的使用

文章目录 一、EditMenuOptions介绍二、相关接口介绍2.1、editMenuOptions2.2、EditMenuOptionsonCreateMenu函数说明onMenuItemClick函数说明 2.3、TextRange对象说明2.4、TextMenuItem对象说明2.5、TextMenuItemId属性ofequals 三、简单案例 一、EditMenuOptions介绍 EditMen…

《软件设计师》复习笔记(14.1)——面向对象基本概念、分析设计测试

目录 一、面向对象基本概念 对象&#xff08;Object&#xff09; 类&#xff08;Class&#xff09; 抽象&#xff08;Abstraction&#xff09; 封装&#xff08;Encapsulation&#xff09; 继承&#xff08;Inheritance&#xff09; 多态&#xff08;Polymorphism&#…

JS中实现类似sleep、wait、delay的延时功能

前言 编写代码时很多时候需要进行流程化的操作&#xff0c;各个流程间通常需要等待一定时间&#xff0c;这在很多语言中通常可以使用 sleep 、 wait 、 delay 等函数来实现。JavaScript原生并没有类似的功能&#xff0c;想要延时通常就是使用 setTimeout(functionRef, delay) …

Banana Pi BPI-RV2 RISC-V 路由器开发板发售, 全球首款RISC-V路由器

Banana Pi BPI-RV2 开源路由器是矽昌通信和⾹蕉派开源社区&#xff08;Banana Pi &#xff09;合作设计, 联合打造全球首款RISC-V架构路由器开发板。 这是香蕉派开源社区与矽昌通信继BPI-Wifi5 低成本Wifi5 路由器合作之后的又一力作&#xff0c;为全球开发者与商业客户提供基于…

MAUI项目iOS应用以进 App Store 分发

目录 一.通过Visual Studio分发应用1. 登录Apple 开发者帐户到 Visual Studio2.创建分发证书和配置文件3. 分发应用4. 在App Store Connect 中创建应用程序记录5. 如果你想使用mac发布应用 一.通过Visual Studio分发应用 1. 登录Apple 开发者帐户到 Visual Studio 首先我们要…

CentOS 7系统yum报错解决方案(CentOS 7官方EOL问题修复)

摘要 解决CentOS 7因EOL导致的yum update报错问题&#xff0c;通过替换阿里云镜像源恢复软件安装功能&#xff0c;包含详细操作步骤、操作截图、验证方法与备选镜像源&#xff0c;附有安全风险提示。 一、故障现象与原因分析 1.1 典型报错信息 # 执行yum命令时出现&#xff…

解决Windows update服务启动拒绝访问的问题 | wuauserv 注册表拒绝访问的方法

在某些情况下,为了配置系统更新相关服务(例如禁用 Windows 自动更新),我们需要更改注册表中 wuauserv 项的权限。本教程将带你一步步操作,成功获取并修改权限。 修改注册表路径: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\wuauserv 步骤一:打开注册表编辑…

深入解析 JDK jstack 命令:线程分析的利器

你点赞了吗&#xff1f;你关注了吗&#xff1f;每天分享干货好文。 高并发解决方案与架构设计。 海量数据存储和性能优化。 通用框架/组件设计与封装。 如何设计合适的技术架构&#xff1f; 如何成功转型架构设计与技术管理&#xff1f; 在竞争激烈的大环境下&#xff0c…

【操作系统原理03】处理机调度与死锁

文章目录 大纲一.处理机调度概念与层次0.大纲1.基本概念2.三个层次3.七状态模型4.三层调度都对比与联系 二.进程调度的时机&#xff0c;切换与过程的调度方式0.大纲1.进程调度时机2.调度方式3.进程的切换与过程 三.调度器和闲逛资源1.调度器/调度程序2.闲逛进程 四.调度算法的评…

Quipus,LightRag的Go版本的实现

1 项目简介 奇谱系统当前版本以知识库为核心&#xff0c;基于知识库可以快构建自己的问答系统。知识库的Rag模块的构建算法是参考了LightRag的算法流程的Go版本优化实现&#xff0c;它可以帮助你快速、准确地构建自己的知识库&#xff0c;搭建属于自己的AI智能助手。与当前LLM…

使用 Vite 快速搭建现代化 React 开发环境

1.检查环境 说明&#xff1a;检测环境&#xff0c;node版本为18.20.6。 2.创建命令 说明&#xff1a;创建命令&#xff0c;选择对应的选项。 npm create vitelatest 3.安装依赖 说明&#xff1a;安装相关依赖。 npm i

PG数据库推进医疗AI向量搜索优化路径研究(2025年3月修订版)

PG数据库推进医疗AI向量搜索优化路径研究 一、医疗 AI 向量搜索的发展现状与挑战 1.1 医疗数据特征与检索需求 医疗数据作为推动医疗领域进步与创新的关键要素,具有鲜明且复杂的特征。从多模态角度看,医疗数据涵盖了结构化数据,如患者基本信息、检验检查报告中的数值结果;…

可穿戴经颅多通道直流电刺激产品测试总结

一 概念原理 tDCS 是一种非侵入性的神经调节技术&#xff0c;利用恒定、低强度直流电&#xff08;通常为 0 - 2mA&#xff09;通过电极作用于特定的大脑区域。其工作原理是通过调节神经元的膜电位&#xff0c;来增加或降低神经元兴奋性的特定区域&#xff0c;从而改变大脑运作。…

详解与HTTP服务器相关操作

HTTP 服务器是一种遵循超文本传输协议&#xff08;HTTP&#xff09;的服务器&#xff0c;用于在网络上传输和处理网页及其他相关资源。以下是关于它的详细介绍&#xff1a; 工作原理 HTTP 服务器监听指定端口&#xff08;通常是 80 端口用于 HTTP&#xff0c;443 端口用于 HT…

Moldflow模流分析教程

Moldflow模流分析教程&#xff1a;

计算机网络 3-4 数据链路层(局域网)

4.1 局域网LAN 特点 1.覆盖较小的地理范围 2.较低的时延和误码率 3.局域网内的各节点之间 4.支持单播、广播、多播 分类 关注三要素 &#xff08;出题点&#xff09; ①拓扑结构 ②传输介质 ③介质访问控制方式 硬件架构 4.2 以太网 4.2.1 层次划分 4.2.2 物理层标准…

单片机AIN0、AIN1引脚功能

目录 1. 模拟-数字转换器&#xff08;ADC&#xff09; 2. 交流电源&#xff08;AC&#xff09; 总结 这两部分有什么区别&#xff1f; 在这个电路图中&#xff0c;两个部分分别是模拟-数字转换器&#xff08;ADC&#xff09;和交流电源&#xff08;AC&#xff09;。以下是这…

如何增加 Elasticsearch 中的 primary shard 数量

作者&#xff1a;来自 Elastic Kofi Bartlett 探索增加 Elasticsearch 中 primary shard 数量的方法。 更多阅读&#xff1a; Elasticsearch&#xff1a;Split index API - 把一个大的索引分拆成更多分片 Elasticsearch&#xff1a;通过 shrink API 减少 shard 数量来缩小 El…

Java 并发性能优化:线程池的最佳实践

Java 并发性能优化&#xff1a;线程池的最佳实践 在 Java 并发编程的世界里&#xff0c;线程池堪称提高应用性能与稳定性的神器。恰如其分地运用线程池&#xff0c;能让我们在多线程任务调度时游刃有余&#xff0c;既能避免线程频繁创建销毁带来的开销&#xff0c;又能合理管控…