安卓判断是否是模拟器,适配主流雷电,MUMU,夜神,逍遥

前言

最近游戏项目组又有新的要求,对于数据上报和数据统计接口,尽可能的具体化,比如是否是模拟器,模拟器的型号,品牌等,都要求统计,后续模拟器玩家在活动发放,安全风控等方面也易于分析和把控。

实现

在网上搜了搜,大概思路是:

1:模拟器的cpu是x86,arm的,通过cpu信息判断

2:模拟器的传感器比较少,尤其没有光传感器等

3:模拟器没有蓝牙模块,可以通过蓝牙判断,这里没有考虑,毕竟需要动态权限

Manifest.permission.BLUETOOTH_CONNECT

在隐私合规的大环境下,还是尽量避免获取多的权限

4:通过部分特征参数,比如Build.FINGERPRINT、 Build.MODEL、Build.BRAND

5:通过模拟器特有文件检测

下面具体贴上工具类代码:

package com.xx.xx.myapplication;import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;public class EmutorUtils {private static final String TAG = "EmutorUtils";private static final String[] PKG_NAMES = {"com.mumu.launcher", "com.ami.duosupdater.ui", "com.ami.launchmetro","com.ami.syncduosservices", "com.bluestacks.home", "com.bluestacks.windowsfilemanager","com.bluestacks.settings", "com.bluestacks.bluestackslocationprovider", "com.bluestacks.appsettings","com.bluestacks.bstfolder", "com.bluestacks.BstCommandProcessor", "com.bluestacks.s2p", "com.bluestacks.setup","com.bluestacks.appmart", "com.kaopu001.tiantianserver", "com.kpzs.helpercenter", "com.kaopu001.tiantianime","com.android.development_settings", "com.android.development", "com.android.customlocale2", "com.genymotion.superuser","com.genymotion.clipboardproxy", "com.uc.xxzs.keyboard", "com.uc.xxzs", "com.blue.huang17.agent", "com.blue.huang17.launcher","com.blue.huang17.ime", "com.microvirt.guide", "com.microvirt.market", "com.microvirt.memuime", "cn.itools.vm.launcher","cn.itools.vm.proxy", "cn.itools.vm.softkeyboard", "cn.itools.avdmarket", "com.syd.IME", "com.bignox.app.store.hd","com.bignox.launcher", "com.bignox.app.phone", "com.bignox.app.noxservice", "com.android.noxpush", "com.haimawan.push","me.haima.helpcenter", "com.windroy.launcher", "com.windroy.superuser", "com.windroy.launcher", "com.windroy.ime","com.android.flysilkworm", "com.android.emu.inputservice", "com.tiantian.ime", "com.microvirt.launcher", "me.le8.androidassist","com.vphone.helper", "com.vphone.launcher", "com.duoyi.giftcenter.giftcenter"};private static final String[] FILES = {"/data/data/com.android.flysilkworm", "/data/data/com.bluestacks.filemanager"};public static String checkFeaturesByHardware(Context context) {String result = "";String hardware = getProperty("ro.hardware");if (null == hardware)return "unknown";String tempValue = hardware.toLowerCase();Log.d(TAG,tempValue);if(tempValue.startsWith("cancro")){result = "MUMU模拟器";}else if(tempValue.contains("nox")){result = "夜神模拟器";}else if(tempValue.equals("android_x86")){result= "雷电模拟器";}else{List pathList = getInstalledSimulatorPackages(context);result =  getSimulatorBrand(pathList);}return result;}private static String getProperty(String propName) {String value = null;Object roSecureObj;try {roSecureObj = Class.forName("android.os.SystemProperties").getMethod("get", String.class).invoke(null, propName);if (roSecureObj != null) value = (String) roSecureObj;} catch (Exception e) {value = null;} finally {return value;}}private static List getInstalledSimulatorPackages(Context context) {ArrayList localArrayList = new ArrayList();try {for (int i = 0; i < PKG_NAMES.length; i++)try {context.getPackageManager().getPackageInfo(PKG_NAMES[i], PackageManager.GET_ACTIVITIES);localArrayList.add(PKG_NAMES[i]);} catch (PackageManager.NameNotFoundException localNameNotFoundException) {}if (localArrayList.size() == 0) {for (int i = 0; i < FILES.length; i++) {if (new File(FILES[i]).exists())localArrayList.add(FILES[i]);}}} catch (Exception e) {e.printStackTrace();}return localArrayList;}private static String getSimulatorBrand(List<String> list) {if (list.size() == 0)return "";String pkgName = list.get(0);if (pkgName.contains("mumu")) {return "mumu";} else if (pkgName.contains("ami")) {return "AMIDuOS";} else if (pkgName.contains("bluestacks")) {return "蓝叠";} else if (pkgName.contains("kaopu001") || pkgName.contains("tiantian")) {return "天天";} else if (pkgName.contains("kpzs")) {return "靠谱助手";} else if (pkgName.contains("genymotion")) {if (Build.MODEL.contains("iTools")) {return "iTools";} else if ((Build.MODEL.contains("ChangWan"))) {return "畅玩";} else {return "genymotion";}} else if (pkgName.contains("uc")) {return "uc";} else if (pkgName.contains("blue")) {return "blue";} else if (pkgName.contains("microvirt")) {return "逍遥";} else if (pkgName.contains("itools")) {return "itools";} else if (pkgName.contains("syd")) {return "手游岛";} else if (pkgName.contains("bignox")) {return "夜神";} else if (pkgName.contains("haimawan")) {return "海马玩";} else if (pkgName.contains("windroy")) {return "windroy";} else if (pkgName.contains("flysilkworm")) {return "雷电";} else if (pkgName.contains("emu")) {return "emu";} else if (pkgName.contains("le8")) {return "le8";} else if (pkgName.contains("vphone")) {return "vphone";} else if (pkgName.contains("duoyi")) {return "多益";}return "";}public static boolean isEmulator(Context context){return notHasLightSensorManager(context)||isFeatures()||checkIsNotRealPhone()||checkPipes() ||isYeshenEmulator();}public static String getPhoneBrand(){return android.os.Build.BRAND;}public static String getPhoneModel(){return  android.os.Build.MODEL;}/**用途:判断蓝牙是否有效来判断是否为模拟器*返回:true 为模拟器*/
//    private static boolean notHasBlueTooth() {
//        BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter();
//        if (ba == null) {
//            return true;
//        } else {
//            // 如果有蓝牙不一定是有效的。获取蓝牙名称,若为null 则默认为模拟器
//            String name = ba.getName();
//            if (TextUtils.isEmpty(name)) {
//                return true;
//            } else {
//                return false;
//            }
//        }
//    }/**用途:依据是否存在光传感器来判断是否为模拟器*返回:true 为模拟器*/private static Boolean notHasLightSensorManager(Context context) {SensorManager sensorManager = (SensorManager) context.getSystemService(context.SENSOR_SERVICE);Sensor sensor8 = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); //光if (null == sensor8) {return true;} else {return false;}}/**用途:根据部分特征参数设备信息来判断是否为模拟器*返回:true 为模拟器*/private static boolean isFeatures() {return Build.FINGERPRINT.startsWith("generic")|| Build.FINGERPRINT.toLowerCase().contains("vbox")|| Build.FINGERPRINT.toLowerCase().contains("test-keys")|| Build.MODEL.contains("google_sdk")|| Build.MODEL.contains("Emulator")|| Build.MODEL.contains("Android SDK built for x86")|| Build.MANUFACTURER.contains("Genymotion")|| (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))|| "google_sdk".equals(Build.PRODUCT);}/**用途:根据CPU是否为电脑来判断是否为模拟器*返回:true 为模拟器*/private static boolean checkIsNotRealPhone() {String cpuInfo = readCpuInfo();if ((cpuInfo.contains("intel") || cpuInfo.contains("amd"))) {return true;}return false;}/**用途:根据CPU是否为电脑来判断是否为模拟器(子方法)*返回:String*/private static String readCpuInfo() {String result = "";try {String[] args = {"/system/bin/cat", "/proc/cpuinfo"};ProcessBuilder cmd = new ProcessBuilder(args);Process process = cmd.start();StringBuffer sb = new StringBuffer();String readLine = "";BufferedReader responseReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "utf-8"));while ((readLine = responseReader.readLine()) != null) {sb.append(readLine);}responseReader.close();result = sb.toString().toLowerCase();} catch (IOException ex) {}return result;}/**用途:检测模拟器的特有文件*返回:true 为模拟器*/private static String[] known_pipes = {"/dev/socket/qemud", "/dev/qemu_pipe"};private static boolean checkPipes() {for (int i = 0; i < known_pipes.length; i++) {String pipes = known_pipes[i];File qemu_socket = new File(pipes);if (qemu_socket.exists()) {Log.v("Result:", "Find pipes!");return true;}}Log.i("Result:", "Not Find pipes!");return false;}//****************适配夜神模拟器*******************//获取 cpu 信息private static String getCpuInfo() {String[] abis = new String[]{};if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {abis = Build.SUPPORTED_ABIS;} else {abis = new String[]{Build.CPU_ABI, Build.CPU_ABI2};}StringBuilder abiStr = new StringBuilder();for (String abi : abis) {abiStr.append(abi);abiStr.append(',');}return abiStr.toString();}// 通过cpu判断是否模拟器 ,适配夜神private static boolean isYeshenEmulator() {String abiStr = getCpuInfo();if (abiStr != null && abiStr.length() > 0) {boolean isSupportX86 = false;boolean isSupportArm = false;if (abiStr.contains("x86_64") || abiStr.contains("x86")) {isSupportX86 = true;}if (abiStr.contains("armeabi") || abiStr.contains("armeabi-v7a") || abiStr.contains("arm64-v8a")) {isSupportArm = true;}if (isSupportX86 && isSupportArm) {//同时拥有X86和arm的判断为模拟器。return true;}}return false;}}

使用

boolean flag = EmutorUtils.isEmulator(MainActivity.this);Toast.makeText(MainActivity.this,"是否是模拟器:"+flag,Toast.LENGTH_SHORT).show();button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String name = EmutorUtils.checkFeaturesByHardware(MainActivity.this);String brand = EmutorUtils.getPhoneBrand();String model = EmutorUtils.getPhoneModel();String result = "name:"+name+"brand:"+brand+"model:"+model;Toast.makeText(MainActivity.this,result,Toast.LENGTH_SHORT).show();}});

效果图

mumu

雷电

逍遥

夜神

官方AVD(用这个玩游戏基本没有)

参考 

http://dxtdbj.com/article.php?id=268
https://cloud.tencent.com/developer/article/2019963 

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

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

相关文章

自研一个简易版本的OkHTTP

一,背景 为了彻底搞明白okhttp原理&#xff0c;仿照okhttp自研一个 二&#xff0c;思路 业务上没发出一个request&#xff0c;使用AsyncCall包装起来&#xff0c;然后在网络分发器的作用下&#xff0c;执行具体的每一个Call,这些具体的Call会经过层层的拦截器&#xff0c;最终…

【JavaEE】多线程案例-阻塞队列

1. 前言 阻塞队列&#xff08;BlockingQueue&#xff09;是一个支持两个附加操作的队列。这两个附加的操作是&#xff1a; 在队列为空时&#xff0c;获取元素的线程会等待队列变为非空当队列满时&#xff0c;存储元素的线程会等待队列可用 阻塞队列常用于生产者和消费者的场…

精益求精:Android应用体积优化的终极指南

精益求精&#xff1a;Android应用体积优化的终极指南 1. 介绍 在当今移动应用生态系统中&#xff0c;Android应用的体积优化是开发者需要高度重视的关键方面之一。一个庞大的应用体积不仅会对用户体验造成负面影响&#xff0c;还会导致以下问题&#xff1a; 下载速度延迟&am…

Re-Learn Linux Part1

1. Linux的目录结构 在Linux文件系统中有两个特殊的目录&#xff1a; 一个用户所在的工作目录&#xff0c;也叫当前目录&#xff0c;可以使用一个点 . 来表示&#xff1b;另一个是当前目录的上一级目录&#xff0c;也叫父目录&#xff0c;可以使用两个点 .. 来表示。 . &#…

Linux 忘记root密码解决方法(CentOS7.9)

忘记Linux系统的root密码&#xff0c;可以不用重新安装系统&#xff0c;进入单用户模式重新更改一下root密码即可。 步骤如下&#xff1a; 首先&#xff0c;启动Linux系统&#xff0c;进入开机界面&#xff0c;在界面中按"e"进入编辑界面&#xff0c;动作要快。按&q…

P2P协议的传输艺术

TP 采用两个 TCP 连接来传输一个文件。 控制连接&#xff1a;服务器以被动的方式&#xff0c;打开众所周知用于 FTP 的端口 21&#xff0c;客户端则主动发起连接。该连接将命令从客户端传给服务器&#xff0c;并传回服务器的应答。常用的命令有&#xff1a;list——获取文件目…

如何在 Excel 中进行加,减,乘,除

在本教程中&#xff0c;我们将执行基本的算术运算&#xff0c;即加法&#xff0c;减法&#xff0c;除法和乘法。 下表显示了我们将使用的数据以及预期的结果。 | **S / N** | **算术运算符** | **第一个号码** | **第二个号码** | **结果** | | 1 | 加法&#xff08;&#xff…

探索Redis速度之谜

Redis&#xff0c;作为一款高性能的内存数据库&#xff0c;一直以来都因其出色的速度而闻名。然而&#xff0c;Redis的速度之快究竟源自何处&#xff0c;其中隐藏着怎样的奥秘&#xff1f;在这篇博客中&#xff0c;我们将深入探索Redis速度之谜&#xff0c;揭开其快速性能背后的…

华为云云耀云服务器L实例评测|使用宝塔10分钟部署一个围猫猫小游戏

目录 前言一、选择华为云云耀云服务器L实例的原因二、华为云云耀云服务器的优势三、快速部署一个小游戏&#xff08;1&#xff09;终端部署1、使用Termius工具连接终端2、安装Nginx3、上传打包文件 &#xff08;2&#xff09;宝塔可视化面板部署1、进入宝塔2、宝塔菜单3、上传代…

千兆以太网网络层 ARP 协议的原理与 FPGA 实现

文章目录 前言一、ARP 帧的应用场景和存在目的二、ARP 帧工作原理三、以太网 ARP 帧发包实例设计四、以太网 CRC校验代码五、以太网 ARP 帧发包测试---GMII1.模拟数据发送2.仿真模块3.仿真波形六、以太网 ARP 帧发包测试---RGMII1.顶层文件2 .仿真代码七、上板测试(RGMII)前言…

Java的序列化

写在前面 本文看下序列化和反序列化相关的内容。 源码 。 1&#xff1a;为什么&#xff0c;什么是序列化和反序列化 Java对象是在jvm的堆中的&#xff0c;而堆其实就是一块内存&#xff0c;如果jvm重启数据将会丢失&#xff0c;当我们希望jvm重启也不要丢失某些对象&#xff…

css自学框架之图片懒加载

首先解释一下什么叫图片懒加载。图片懒加载是一种在页面加载时&#xff0c;延迟加载图片资源的技术&#xff0c;也就是说图片资源在需要的时候才会加载&#xff0c;就是在屏幕显示范围内加载图片&#xff0c;屏幕显示范围外图片不加载。 一、关键函数 用到的关键函数&#xf…