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

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

实现思路: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博客

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Webots常用的执行器(Python版)

文章目录 1. RotationalMotor2. LinearMotor3. Brake4. Propeller5. Pen6. LED 1. RotationalMotor # -*- coding: utf-8 -*- """motor_controller controller."""from controller import Robot# 实例化机器人 robot Robot()# 获取基本仿真步长…

IDEA无法成功配置Tomcat的解决方法(IDEA版本问题)

在创建Servlet时&#xff0c;下载了Tomcat文件夹以及成功配置了环境变量之后&#xff0c;在IDEA中怎么都找不到Tomcat&#xff0c;尝试了网络中的各种方法&#xff0c;都不行&#xff0c;结果发现时IDEA版本的问题。因为我下的IDEA是社区版的&#xff0c;所以没有自带的Tomcat&…

Flutter开发之图片选择器

使用FLutter开发了一个图片选择的组件&#xff0c;功能如下&#xff1a; 1、支持设置最大可选图片的个数&#xff1b; 2、根据选择的图片个数自适应容器组件的高度&#xff1b; 3、可设置容器的最大高度&#xff1b; 4、支持点击放大和删除功能&#xff1b; 具体效果如下 …

Linux系统安装内网穿透实现固定公网地址访问本地MinIO服务

文章目录 前言1. 创建Buckets和Access Keys2. Linux 安装Cpolar3. 创建连接MinIO服务公网地址4. 远程调用MinIO服务小结5. 固定连接TCP公网地址6. 固定地址连接测试 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的 人工智能学习网站&#xff0c; 通俗易懂&am…

【计算机考研】408算法大题怎么练?

先说结论&#xff1a;基础阶段学好各个数据结构与&#xff0c;重点是数组、链表、树、图。然后强化阶段突破算法提 在基础阶段&#xff0c;并不需要过于专门地练习算法。相反&#xff0c;基础阶段的重点应该放在对各种数据结构原理的深入理解上。在我个人的经验中&#xff0c;…

计算机考研择校|408还是自命题,哪个上岸难度大?

我一般是建议选择408&#xff0c;但是现在考408的同学太多了 所以408的竞争压力会比较大&#xff0c;加上复习难度大&#xff0c;复习过程中&#xff0c;心态很容易崩掉。 其实到底选自命题还是408&#xff0c;我觉得还是要看自己的目标。如果目标院校是自命题&#xff0c;那…

C语言的显式类型转换和隐式类型转换详细讲解

目录 一、类型转换 1、显式类型转换 2、隐式类型转换 二、算术转换 三、总结 每个编译器都会对表达式做两件事情&#xff0c;一是判断表达式中操作符的优先级和结合性&#xff0c;二是判断表达式中的操作数类型是否一致&#xff0c;如果不一致则需要进行类型转换。第一点在…

吴恩达机器学习实践实验室:决策树(Decision Trees)

在本练习中&#xff0c;您将从头开始实施决策树&#xff0c;并将其应用于蘑菇可食用还是有毒的分类任务。 文章目录 1-包2-问题陈述3-数据集3.1一个热编码数据集 4-决策树4.1计算熵4.2分割数据集4.3计算信息增益4.4获得最佳分割 5-构建树 1-包 首先&#xff0c;让我们运行下面…

【问题解决】ubuntu安装新版vscode报code-insiders相关错误

问题 目前 vscode官网 最新的包为 insiders_1.89.0-1712297812_amd64.deb &#xff0c;双击或者使用sudo dpkg -i code-insiders_1.89.0-1712297812_amd64.deb安装后报错&#xff0c;执行其他命令也报错。 安装环境&#xff1a;ubuntu18.04 dpkg: 处理软件包 code-insiders (…

代码随想录算法训练营第四十九天 | 121. 买卖股票的最佳时机、22. 买卖股票的最佳时机 II

代码随想录算法训练营第四十九天 | 121. 买卖股票的最佳时机、22. 买卖股票的最佳时机 II 121. 买卖股票的最佳时机题目解法 122. 买卖股票的最佳时机 II题目解法 感悟 121. 买卖股票的最佳时机 题目 解法 题解链接 没看题解想出来的&#xff1a;贪心 class Solution { pub…

归档模式下,物理删除数据文件的完全的恢复

归档模式下&#xff0c;物理删除数据文件的完全的恢复 1、实验环境 环境归档模式 SQL> archive log list Database log mode Archive Mode Automatic archival Enabled Archive destination /arch/archivelog Oldest online log seq…

用户态网络缓冲区的设计

一、网络缓冲区 在内核中也是有网络缓冲区的&#xff0c;比如使用 read 读取数据&#xff08;read 是一种系统调用&#xff0c;第一个参数为 fd&#xff09;&#xff0c;当陷入到内核态的时候&#xff0c;会通过 fd 指定 socket&#xff0c;socket 会找到对应的接收缓冲区。在…

抓住风口,快速上手RAG应用开发!

免责声明~ 任何文章不要过度深思&#xff01; 万事万物都经不起审视&#xff0c;因为世上没有同样的成长环境&#xff0c;也没有同样的认知水平&#xff0c;更「没有适用于所有人的解决方案」&#xff1b; 不要急着评判文章列出的观点&#xff0c;只需代入其中&#xff0c;适度…

37-代码测试(下):Go语言其他测试类型及IAM测试介绍

。 Go中的两类测试&#xff1a;单元测试和性能测试。 我就来介绍下Go 语言中的其他测试类型&#xff1a;示例测试、TestMain函数、Mock测试、Fake测试等&#xff0c; 示例测试 示例测试以Example开头&#xff0c;没有输入和返回参数&#xff0c;通常保存在example_test.go…

Go语言实现Redis分布式锁2

项目地址: https://github.com/liwook/Redislock 1.支持阻塞式等待获取锁 之前的是只尝试获取一次锁&#xff0c;要是获取失败就不再尝试了。现在修改为支持阻塞式等待获取锁。 添加LockOptions结构体 添加option.go文件。 在LockOptions中 isBlock表示是否是阻塞模式blo…

美团一面:说说synchronized的实现原理?问麻了。。。。

引言 在现代软件开发领域&#xff0c;多线程并发编程已经成为提高系统性能、提升用户体验的重要手段。然而&#xff0c;多线程环境下的数据同步与资源共享问题也随之而来&#xff0c;处理不当可能导致数据不一致、死锁等各种并发问题。为此&#xff0c;Java语言提供了一种内置…

Pots(DFS BFS)

//新生训练 #include <iostream> #include <algorithm> #include <cstring> #include <queue> using namespace std; typedef pair<int, int> PII; const int N 205; int n, m; int l; int A, B, C; int dis[N][N];struct node {int px, py, op…

谱重排变换和同步压缩变换的区别是什么?

谱重排方法能够得到非常高的时频分辨率&#xff0c;但是同样也存在一个问题&#xff0c;不能重构原始信号&#xff0c;2011 年 Daubechies 提出了一种基于相位的高分辨率时频分析方法—同步压缩小波变换&#xff0c;该方法也是一种谱重排的方法&#xff0c;能使非平稳非线性信号…

Mybatis报错:Unsupported conversion from LONG to java.sql.Timestamp

Mybatis在封装结果集的时候&#xff0c;如果方法返回的是对象&#xff0c;则会去调用这个对象的无参构造方法。 如果实体类标注了Builder注解&#xff0c;则此注解会把默认的构造方法全部改成私有的&#xff0c;则Mybatis在通过无参构造方法反射创建对象时&#xff0c;就会找不…

Redis中的集群(二)

节点 集群数据结构 redisClient结构和clusterLink结构的相同和不同之处 redisClient结构和clusterLink结构都有自己的套接字描述符和输入、输出缓冲区&#xff0c;这两个结构的区别在于&#xff0c;redisClient结构中的套接字和缓冲区是用于连接客户端的&#xff0c;而clust…