主题:在手机开启热点网络的情况下,想要获取是哪个设备已经连接上了当前开启的热点。
实现思路: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博客