最近有项目需要设备模拟器,此贴用来记录我识别模拟器的方法:
目前还没有发现安卓8.0以上的模拟器,所以可以通过判断设备安卓版本号,过滤>=8.0的设备(默认为真机)
可以从安卓8.0 以下,通过以下几个方面判断:
//Android 8.0 版本以上,不做模拟器判断 if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){ }
1、通过能否打电话来判断模拟器:
String url = "tel:" + "10086";
Intent intent = new Intent();
intent.setData(Uri.parse(url));
intent.setAction(Intent.ACTION_DIAL);
// 隐示意图跳转到打电话界面 Intent (检查是否存在)
boolean canResolverIntent = intent.resolveActivity(context.getPackageManager()) != null;
canResolverIntent ==true,可以打电话,判断为真机。
目前主流模拟器都没有打电话这个功能:
这个来判断基本可以ban掉很多模拟器了
2、通过cpu来判断:
基本x86可以判定为模拟器
Build.MODEL.contains("x86")
android.os.Build.CPU_ABI.contains("x86")
3、第三通传感器来判断:例如:光传感器,方向传感器。
/** * 判断是否存在光传感器来判断是否为模拟器 部分真机也不存在温度和压力传感器。其余传感器模拟器也存在。 * * @return true 为模拟器 */ public int notHasLightSensorManager(Context context) { SensorManager sensorManager = (SensorManager) context .getSystemService(Context.SENSOR_SERVICE); Sensor sensor8 = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); // 光 if (null == sensor8) { Log.i("", "光传感器判定为false"); return 0; } else { Log.i("", "光传感器判定为true"); return 1; } }
写在最后:
手机是否安装QQ、微信、支付宝、淘宝、抖音、快手 等常用APP,也可以作为一个筛选条件。
已经root 的机器,再过滤一遍。
模拟器识别与判断,判定结果最好在服务端实现。
附上代码
package com.sdk.inner.utils;
import android.bluetooth.BluetoothAdapter;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import com.sdk.inner.log.LogUtil;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
public class EmulatorUtils {
public static boolean isEmulator = false;
/**
* 判断是否存在光传感器来判断是否为模拟器 部分真机也不存在温度和压力传感器。其余传感器模拟器也存在。
*
* @return true 为模拟器
*/
public static boolean hasLightSensorManager(Context context) {
SensorManager sensorManager = (SensorManager) context
.getSystemService(Context.SENSOR_SERVICE);
Sensor sensor8 = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); // 光
if (null == sensor8) {
Log.i("", "光传感器判定为false");
LogUtil.d("is_emulator:hasLightSensorManager = "+false);
return false;
} else {
Log.i("", "光传感器判定为true");
LogUtil.d("is_emulator:hasLightSensorManager = "+true);
return true;
}
}
/**
* 是否模拟器、
*
* @return true 为模拟器
*/
public static void checkSimulator(Context context) {
boolean isX86 = Build.MODEL.contains("x86");
boolean isX86_1 = android.os.Build.CPU_ABI.contains("x86");
//Android 8.0 版本以上,不做模拟器判断
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
LogUtil.d("is_emulator:SDK_INT = "+Build.VERSION.SDK_INT);
isEmulator=false;
}else {
if(isX86 || isX86_1){
LogUtil.d("is_emulator:isX86 = "+isX86+" isX86_1="+isX86_1);
isEmulator = true;
}
//安卓8以下,检查root
else if(isRoot()){
isEmulator = true;
}
else if(!hasLightSensorManager(context)){
isEmulator = true;
}else if(!canCallPhone(context)){
isEmulator = true;
}
else if(ifFeatures()){
LogUtil.d("is_emulator:ifFeatures = "+true);
isEmulator = true;
}
//安卓8以下,检查app安装
else if(!checkInstallNeedApk(context)){
isEmulator = true;
}
else {
isEmulator = false;
}
}
// Toast.makeText(context,"is_emulator=:"+isEmulator,Toast.LENGTH_SHORT).show();
LogUtil.d("is_emulator=:"+isEmulator);
}
public static boolean canCallPhone(Context context){
String url = "tel:" + "10086";
Intent intent = new Intent();
intent.setData(Uri.parse(url));
intent.setAction(Intent.ACTION_DIAL);
// 隐示意图跳转到打电话界面 Intent (检查是否存在)
boolean canResolverIntent = intent.resolveActivity(context.getPackageManager()) != null;
LogUtil.d("is_emulator:canCallPhone = "+canResolverIntent);
return canResolverIntent;
}
/**
* 根据部分特征参数设备信息来判断是否为模拟器
* @return
*/
private static boolean ifFeatures(){
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);
}
public static boolean checkInstallNeedApk(Context context){
LogUtil.d("Build.VERSION.SDK_INT = "+Build.VERSION.SDK_INT+"支付宝:"+isAliPayInstalled(context) +" 微信:"+isWeixinAvilible(context)+" qq:"+isQQClientAvailable(context));
return isAliPayInstalled(context)||isWeixinAvilible(context)||isQQClientAvailable(context);
}
/**
* 检测是否安装支付宝
* @param context
* @return
*/
public static boolean isAliPayInstalled(Context context) {
Uri uri = Uri.parse("alipays://platformapi/startApp");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
ComponentName componentName = intent.resolveActivity(context.getPackageManager());
return componentName != null;
}
/**
* 检测是否安装微信
* @param context
* @return
*/
public static boolean isWeixinAvilible(Context context) {
final PackageManager packageManager = context.getPackageManager();// 获取packagemanager
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);// 获取所有已安装程序的包信息
if (pinfo != null) {
for (int i = 0; i < pinfo.size(); i++) {
String pn = pinfo.get(i).packageName;
if (pn.equals("com.tencent.mm")) {
return true;
}
}
}
return false;
}
/**
* 判断是否安装了QQ
*
* @param context
* @return
*/
public static boolean isQQClientAvailable(Context context) {
final PackageManager packageManager = context.getPackageManager();
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
if (pinfo != null) {
for (int i = 0; i < pinfo.size(); i++) {
String pn = pinfo.get(i).packageName;
if (pn.equals("com.tencent.mobileqq")) {
return true;
}
}
}
return false;
}
//是否root
public static boolean isRoot() {
boolean root = false;
if (new File("/system/bin/su").exists() && isCanExecute("/system/bin/su")) {
root = true;
}
if (new File("/system/xbin/su").exists() && isCanExecute("/system/xbin/su")) {
root = true;
}
LogUtil.d("is_emulator:是否root = "+root);
return root;
}
private static boolean isCanExecute(String filePath) {
Process process = null;
try {
process = Runtime.getRuntime().exec("ls -l " + filePath);
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String str = in.readLine();
if (str != null && str.length() >= 4) {
char flag = str.charAt(3);
if (flag == 's' || flag == 'x')
return true;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (process != null) {
process.destroy();
}
}
return false;
}
}