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

安卓判断是否是模拟器,适配主流雷电,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 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() {

@Override

public 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

🌸 相关推荐 🌸

10 年美国 2024 个最省钱的电子科技网站
365bet足球论坛

10 年美国 2024 个最省钱的电子科技网站

📅 09-24 👀 1987
九游帐号发布规则
外勤365下载安装版本

九游帐号发布规则

📅 07-08 👀 3945
阴茎的标准长度怎么测量
bt365体育在线官网

阴茎的标准长度怎么测量

📅 10-18 👀 478