Android获取连接到手机热点上的设备信息

news2024/11/25 6:44:10
主题:在手机开启热点网络的情况下,想要获取是哪个设备已经连接上了当前开启的热点。

实现思路:Android通过读取  /proc/net/arp 文件可以得到连接当前热点的设备信息,包括Mac地址、IP地址等信息。

一. 方法逻辑:

    /**
     * 获取连接到手机热点上的设备信息
     * @return
     */
    public List<HashMap> getConnectedApInfo() {
        List<HashMap> connectedApInfo = new ArrayList<>();

        try {
            BufferedReader br = new BufferedReader(new FileReader("/proc/net/arp"));
            String line;

            while ((line = br.readLine()) != null) {
                /**
                 * 获取到的数组结果,示例:[192.168.227.138, 0x1, 0x2, 82:64:5e:01:49:fc, *, wlan2]
                 */
                String[] splitted = line.split(" +");
                HashMap hashMap = new HashMap();

                //设备信息判断标准
                if (splitted.length >= 4 && splitted[3].contains(":")) {
                    String ip = splitted[0];          //获取IP地址信息,代替设备名称
                    String address = splitted[3];     //获取Mac地址信息

                    hashMap.put("name", ip);
                    hashMap.put("address", address);

                    connectedApInfo.add(hashMap);
                    Log.d(TAG, "getConnectedApInfo(),获取连接到手机热点上的设备信息:" + Arrays.toString(splitted) + "    connectedApInfo:" + connectedApInfo.size() + "  " + connectedApInfo);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return connectedApInfo;
    }
二. 拓展工具类,控制热点的开启和关闭,热点信息的获取:
import static android.content.Context.CONNECTIVITY_SERVICE;
import java.io.BufferedReader;
import java.io.FileReader;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.ConnectivityManager;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.util.Log;
import com.android.dx.stock.ProxyBuilder;

/**
 * Description:控制热点的开启和关闭,热点信息的获取
 * 所需权限:
 * <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
 * <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
 * <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
 * <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 * <uses-permission android:name="android.permission.WRITE_SETTINGS"
 *     tools:ignore="ProtectedPermissions" /> <!-- 用于Android 6.0 (API 级别 23) 及以上版本 -->
 */
public class WifiHotspotManager {
    private static final String TAG = WifiHotspotManager.class.getSimpleName();
    private WifiManager wifiManager;
    private Method method;

    public WifiHotspotManager(Context context) {
        wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    }

    public boolean isApEnabled() {
        try {
            if (method == null) {
                method = wifiManager.getClass().getMethod("isWifiApEnabled");
            }
            return (boolean) method.invoke(wifiManager);
        } catch (Exception e) {
            Log.e(TAG, "Error checking if AP is enabled", e);
            return false;
        }
    }

    /**
     * 开启或关闭热点
     * @param enabled
     * @return
     */
    public boolean setApEnabled(boolean enabled) {
        if (enabled) {
            Log.d(TAG, "开启热点,Enabling hotspot");
        } else {
            Log.d(TAG, "关闭热点,Disabling hotspot");
        }

        try {
            if (method == null) {
                method = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
            }
            return (boolean) method.invoke(wifiManager, null, enabled);
        } catch (Exception e) {
            Log.e(TAG, "开启或关闭热点 is error,enabling/disabling AP:" + e);
            return false;
        }
    }

    /**
     * 配置热点的设置(如SSID和密码)
     * 需要创建一个WifiConfiguration对象来配置你的热点设置,然后将其传递给configureApState方法
     * @param apConfig
     * @return
     */
    public boolean configureApState(WifiConfiguration apConfig) {
        try {
            Method method = wifiManager.getClass().getMethod("setWifiApConfiguration", WifiConfiguration.class);
            return (boolean) method.invoke(wifiManager, apConfig);
        } catch (Exception e) {
            Log.e(TAG, "Error setting AP configuration", e);
            return false;
        }
    }

    /**
     * 控制热点的开启和关闭(一步到位)
     */
    public boolean controlApSwitch(Context context, boolean flag){
        WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        try{
            WifiConfiguration apConfig = new WifiConfiguration();
            String deviceModel = Build.MODEL;     //设备型号
            apConfig.SSID = deviceModel;          //配置热点的名称
            apConfig.preSharedKey = "12345678";   //配置热点的密码(至少8位)
            apConfig.allowedKeyManagement.set(4); //配置密码加密方式

            //通过反射调用设置热点
            Method method = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, Boolean.TYPE);
            Boolean rs = (Boolean) method.invoke(wifiManager, apConfig, flag);        //true 开启热点 ,false 关闭热点
            Log.d(TAG, flag ? "当前设备:" + deviceModel + " 开启热点网络是否成功:" + rs : " 关闭热点网络是否成功:" + rs);
            return rs;
        } catch(Exception e){
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 发送隐式广播。此方法会查询与给定意图相匹配的所有广播接收器,并向每个匹配的接收器发送一个显式广播。
     *
     * @param context 上下文,用于发送广播。
     * @param intent 需要发送的隐式广播意图。
     * @param action 执行的动作
     */
    public void sendImplicitBroadcast(Context context, Intent intent, String action) {
        // 获取包管理器,用于查询广播接收器
        PackageManager pm = context.getPackageManager();
        // 查询与intent相匹配的所有广播接收器
        List<ResolveInfo> matches = pm.queryBroadcastReceivers(intent, 0);

        // 遍历所有匹配的广播接收器
        for (ResolveInfo resolveInfo : matches) {
            // 创建一个新的意图,将其转换为显式意图,目标为当前接收器
            Intent explicit = new Intent(intent);
            // 设置组件名称,转换为显式意图
            ComponentName cn = new ComponentName(resolveInfo.activityInfo.applicationInfo.packageName, resolveInfo.activityInfo.name);
            explicit.setComponent(cn);
            // 向每个匹配的广播接收器发送显式广播
            context.sendBroadcast(explicit);
        }

        Log.d(TAG, "sendImplicitBroadcast(),发送隐式广播,action:" + action);
    }

    /**
     * 打开手机的热点
     * 需要在build.gradle文件添加三方库依赖:implementation 'com.linkedin.dexmaker:dexmaker-mockito:2.12.1'
     * @param context
     */
    public void startTethering(Context context){
        ConnectivityManager connectivityManager = ((ConnectivityManager)context.getSystemService(CONNECTIVITY_SERVICE));
        try{
            Class classOnStartTetheringCallback = Class.forName("android.net.ConnectivityManager$OnStartTetheringCallback");
            Method startTethering=connectivityManager.getClass().getDeclaredMethod("startTethering",int.class,boolean.class,classOnStartTetheringCallback);
            Object proxy = ProxyBuilder.forClass(classOnStartTetheringCallback).handler(new InvocationHandler(){
                @Override
                public Object invoke(Object o,Method method,Object[]objects)throws Throwable{
                    return null;
                }
            }).build();
            startTethering.invoke(connectivityManager,0,false,proxy);
        } catch(Exception e){
            e.printStackTrace();
        }

        Log.d(TAG, "startTethering(),打开手机的热点");
    }

    /**
     * 关闭手机的热点
     */
    public void stopTethering(Context context){
        ConnectivityManager connectivityManager=((ConnectivityManager)context.getSystemService(CONNECTIVITY_SERVICE));
        try{
            Method stopTethering = connectivityManager.getClass().getDeclaredMethod("stopTethering",int.class);
            stopTethering.invoke(connectivityManager,0);
        }catch(Exception e){
            e.printStackTrace();
        }
        Log.d(TAG, "stopTethering(),关闭手机的热点");
    }

    /**
     * 判断是否开启手机的热点
     * @param context
     * @return
     */
    public boolean isWifiApEnabled(Context context){
        WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(
                Context.WIFI_SERVICE);
        try{
            Method method=wifiManager.getClass().getMethod("isWifiApEnabled");
            method.setAccessible(true);
            return(Boolean)method.invoke(wifiManager);
        }catch(NoSuchMethodException e){
            e.printStackTrace();
        }catch(Exception e){
            e.printStackTrace();
        }

        Log.d(TAG, "isWifiApEnabled(),判断是否开启手机的热点");
        return false;
    }

    /**
     * 获取手机的热点信息
     * @param context
     * @return
     */
    public String getApInfo(Context context){
        WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        try{
            Method localMethod = wifiManager.getClass().getDeclaredMethod("getWifiApConfiguration", new Class[0]);
            Object config = localMethod.invoke(wifiManager);
            Log.d(TAG, "getApInfo(),获取手机的热点信息:" + config.toString());
        }catch(Exception localException){
            localException.printStackTrace();
        }
        return null;
    }

    /**
     * 获取连接到手机热点上的设备信息
     * @return
     */
    public List<HashMap> getConnectedApInfo() {
        List<HashMap> connectedApInfo = new ArrayList<>();

        try {
            BufferedReader br = new BufferedReader(new FileReader("/proc/net/arp"));
            String line;

            while ((line = br.readLine()) != null) {
                /**
                 * 获取到的数组结果,示例:[192.168.227.138, 0x1, 0x2, 82:64:5e:01:49:fc, *, wlan2]
                 */
                String[] splitted = line.split(" +");
                HashMap hashMap = new HashMap();

                //设备信息判断标准
                if (splitted.length >= 4 && splitted[3].contains(":")) {
                    String ip = splitted[0];          //获取IP地址信息,代替设备名称
                    String address = splitted[3];     //获取Mac地址信息

                    hashMap.put("name", ip);
                    hashMap.put("address", address);

                    connectedApInfo.add(hashMap);
                    Log.d(TAG, "getConnectedApInfo(),获取连接到手机热点上的设备信息:" + Arrays.toString(splitted) + "    connectedApInfo:" + connectedApInfo.size() + "  " + connectedApInfo);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return connectedApInfo;
    }
三. 调用示例:
//返回的是一个数据形式是包含HahMap集合的List集合,可根据HashMap的键值对取值并显示
WifiHotspotManager wifiHotspotManager = new WifiHotspotManager(requireActivity());

List<HashMap> connectedApInfo = wifiHotspotManager.getConnectedApInfo();

Log.d(TAG, "connectedApInfo:" + connectedApInfo.size() + "  " + connectedApInfo);
四.手机热点已连接设备与功能效果图

参考文章:Android获取实时连接热点的设备IP_安卓设备获取ip-CSDN博客

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

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

相关文章

秋招复习笔记——八股文部分:操作系统

笔试得刷算法题&#xff0c;那面试就离不开八股文&#xff0c;所以特地对着小林coding的图解八股文系列记一下笔记。 这一篇笔记是图解系统的内容。 硬件结构 CPU执行程序 计算机基本结构为 5 个部分&#xff0c;分别是运算器、控制器、存储器、输入设备、输出设备&#xf…

安全左移是什么,如何为网络安全建设及运营带来更多可能性

长久以来&#xff0c;网络安全技术产品和市场需求都聚焦于在“右侧”防护&#xff0c;即在各种系统、业务已经投入使用的网络环境外围或边界&#xff0c;检测进出的流量、行为等是不是存在风险&#xff0c;并对其进行管控或调整。 然而事实上&#xff0c;安全风险不仅是“跑”…

4套java开发的智慧系统源码 智慧校园系统源码 智慧工地系统源码 智慧城管系统源码

4套java智慧系统源码 智慧校园系统源码 智慧工地系统源码 智慧城管系统源码 3D 智能导诊系统源码 Java智慧校园系统源码 智慧学校源码 微信小程序电子班牌 智慧校园系统简介&#xff1a; 智慧校园的建设逐渐被师生、家长认可接受&#xff0c;智慧校园通过对在校师生、教务等…

tcp的全连接队列和半连接队列满时,客户端再connect发生的情况

首先简单介绍下tcp的全连接队列(accept queue)和半连接队列(syn queue)&#xff0c; 1.客户端发起syn请求时&#xff0c;服务端收到该请求&#xff0c;将其放入到syn queue&#xff0c;然后回复acksyn给客户端。 2.客户端收到acksyn&#xff0c;再发送ack给服务端。 3. 服务端从…

2_8.Linux系统引导过程及引导修复

# 1.磁盘引导 # mbr主引导记录0磁道1扇区446 作用&#xff1a; 记录grub2引导文件的位置 当mbr数据丢失系统会因为找不到启动分区而停止启动 问题模拟方式: 系统磁盘/dev/sda dd if/dev/zero of/dev/vda bs446 count1 ##清空系统/dev/sda上的mbr数据 恢复方式&#xff1a; &…

Java多线程实战-从零手搓一个简易线程池(四)线程池生命周期状态流转实现

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️本系列源码仓库&#xff1a;多线程并发编程学习的多个代码片段(github) &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正…

【IC前端虚拟项目】spyglass lint环境组织与lint清理

【IC前端虚拟项目】数据搬运指令处理模块前端实现虚拟项目说明-CSDN博客 和上个虚拟项目的lint清理环节一样&#xff0c;关于spyglass的lint清理功能与流程还是大家通过各种资料去学习下就好啦。和之前不同的事&#xff0c;这次的虚拟项目里我把流程封装为Makefile&#xff0c;…

C. MEX Game 1

本题如果我们去模拟这个算法的话会很麻烦&#xff0c;也会TLE&#xff0c;首先我们想 1&#xff0c;对于alice来说&#xff0c;先取小的&#xff0c;对于bob来说先删除alic想取的下一个小的 2&#xff0c;那如果这个数多于两个&#xff0c;那也就是说&#xff0c;alice肯定能…

Linux操作系统安装注意事项(新手简易版)

Linux操作系统安装注意事项&#xff08;新手简易版&#xff09; 目录&#xff1a; 1、字符集安装 2、磁盘分区 3、关闭KDUMP防火墙 4、时区选择 注&#xff1a;事例截图是centos8的安装&#xff0c;其他版本是一样的 1、字符集安装 ecology运行需要用到GBK和UTF8字符…

LeetCode-84. 柱状图中最大的矩形【栈 数组 单调栈】

LeetCode-84. 柱状图中最大的矩形【栈 数组 单调栈】 题目描述&#xff1a;解题思路一&#xff1a;单调栈解题思路二&#xff1a;解题思路三&#xff1a; 题目描述&#xff1a; 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且…

anaconda命令行创建虚拟环境并为其安装jupyter notebook同时指定jupyter notebook保存位置

查看有哪些虚拟环境&#xff08;一个环境一个版本的python或者其他库&#xff09; winr快捷键 输入cmd conda env list应该是进入conda的安装路径&#xff0c;但是我们已经添加环境变量 可以看到只有base默认的环境 我们现在新建虚拟环境 python版本为你需要的 conda create -…

Harmony鸿蒙南向驱动开发-GPIO

GPIO&#xff08;General-purpose input/output&#xff09;即通用型输入输出。通常&#xff0c;GPIO控制器通过分组的方式管理所有GPIO管脚&#xff0c;每组GPIO有一个或多个寄存器与之关联&#xff0c;通过读写寄存器完成对GPIO管脚的操作。 基本概念 GPIO又俗称为I/O口&am…

web安全学习笔记(8)

记一下第十二节课的内容。 一、PHP文件包含的四种方式 Include和Include_once 操作系统会读取包含的文件的内容&#xff0c;并将它插入主文件中&#xff0c;include方式的文件包含会在包含失败的情况下输出警告信息&#xff0c;而include_once方式会检查包含的文件是否已经被…

【数据结构与算法篇】单链表及相关OJ算法题

【数据结构与算法篇】单链表及相关OJ算法题 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;数据结构与算法&#x1f345; &#x1f33c;文章目录&#x1f33c; 1. 单链表的实现(近300行实现代码) 1.1 SList.h 头文件的声明 1.2 SLi…

指针 运算偏移

思维导图&#xff1a; 题目&#xff1a; 1.变量的指针&#xff0c;其含义是指该变量的 B 。 A&#xff09;值 B&#xff09;地址 C&#xff09;名 D&#xff09;一个标志 2.已有定义int k2;int *ptr1,*ptr2;且ptr1和ptr2均…

每日OJ题_两个数组dp⑥_力扣97. 交错字符串

目录 力扣97. 交错字符串 解析代码 力扣97. 交错字符串 97. 交错字符串 难度 中等 给定三个字符串 s1、s2、s3&#xff0c;请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。 两个字符串 s 和 t 交错 的定义与过程如下&#xff0c;其中每个字符串都会被分割成若干 非空 子…

YOLOv5标签值含义根据标签将检测框色块替换(马赛克)

以一个检测人脸的图片为例&#xff1a; 检测后生成的标签txt如下&#xff0c; 此时&#xff0c;如何根据标签值将检测到的人脸同色块替换呢&#xff1f; 关键是获取检测框的左上角坐标和右下角坐标。 img Image.open(D:/PythonWokspace/JINX/datasets_transform/dataset/im…

【grpc】三、grpc入门,内置日志打印

一、开启条件 通过查看 grpc 的内置文件可以看到&#xff0c;日志打印是由环境变量控制的&#xff1a; export GRPC_GO_LOG_VERBOSITY_LEVEL99 # 日志详细程度&#xff0c;这里99为最高 export GRPC_GO_LOG_SEVERITY_LEVELinfo # 日志等级&#xff0c;这里为info如果是用Gol…

接雨水(双指针)

11. 盛最多水的容器 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 样例输入 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,…

Vue文档

Vue是什么&#xff1f;为什么要学习他 Vue是什么&#xff1f; Vue是前端优秀框架&#xff0c; 是一套用于构建用户界面的渐进式框架 为什么要学习Vue Vue是目前前端最火的框架之一Vue是目前企业技术栈中要求的知识点Vue可以提升开发体验Vue学习难度较低… Vue开发前的准备 安…