Android 模拟器检测

Android 模拟器检测,第1张


最近看到某客户端有一个检测模拟器的方法,我正常手机结果被判断是模拟器了,很好奇,于是找了一下原因。

普遍检测代码如下:

public boolean isEmulator() { String url = "tel:" + "123456"; Intent intent = new Intent(); intent.setData(Uri.parse(url)); intent.setAction(Intent.ACTION_DIAL); // 是否可以处理跳转到拨号的 Intent boolean canResolveIntent = intent.resolveActivity(mContext.getPackageManager()) != null; 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.SERIAL.equalsIgnoreCase("unknown") || Build.SERIAL.equalsIgnoreCase("android") || 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) || ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE)) .getNetworkOperatorName().toLowerCase().equals("android") || !canResolverIntent; }

这个代码检测模拟器有两个问题:

1、拨号检测,Android10.0及以上均为false

2、Build.SERIAL,Android8.0以上均为unknown

这导致8.0以上系统均会被误判

推荐模拟器检测方法:

设备信息检测代码:

private static final String[] known_numbers = {"15555215554", "15555215556", "15555215558", "15555215560", "15555215562", "15555215564", "15555215566", "15555215568", "15555215570", "15555215572", "15555215574", "15555215576", "15555215578", "15555215580", "15555215582", "15555215584",};private boolean detectEmulator() { if (Build.FINGERPRINT.startsWith("generic") || Build.FINGERPRINT.startsWith("unknown") || 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)) { return true; } if (Build.PRODUCT.equals("sdk") || Build.PRODUCT.equals("sdk_x86") || Build.PRODUCT.equals("vbox86p") || Build.PRODUCT.equals("emulator")) { return true; } if (Build.BOARD == null) { return true; } if (Build.BOARD.equals("unknown") || Build.BOARD.contains("android") || Build.BOARD.contains("droid")) { return true; } if (Build.DEVICE == null) { return true; } if (Build.DEVICE.equals("unknown") || Build.DEVICE.contains("android") || Build.DEVICE.contains("droid")) { return true; } if (Build.HARDWARE == null) { return true; } if (Build.HARDWARE.equals("goldfish") || Build.HARDWARE.equals("ranchu") || Build.HARDWARE.contains("ranchu")) { return true; } if (Build.BRAND == null) { return true; } if (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) { return true; } if (Build.MANUFACTURER.equals("unknown")) { return true; } if (Build.MANUFACTURER.equals("Genymotion")) { return true; } if ((Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) || "google_sdk".equals(Build.PRODUCT)) { return true; } if (Build.PRODUCT == null) { return true; } if (Build.PRODUCT.equals("sdk") || Build.PRODUCT.equals("sdk_x86") || Build.PRODUCT.equals("vbox86p") || Build.PRODUCT.equals("emulator")) { return true; } if (Build.HARDWARE.equals("goldfish") || Build.HARDWARE.equals("ranchu")) { return true; } if (Build.FINGERPRINT.startsWith("generic") || Build.FINGERPRINT.startsWith("unknown") || 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)) { return true; } if (Build.PRODUCT == null) { return true; } if (Build.PRODUCT.equals("sdk") || Build.PRODUCT.equals("sdk_x86") || Build.PRODUCT.equals("vbox86p") || Build.PRODUCT.equals("emulator")) { return true; } if (Build.HARDWARE.equals("goldfish") || Build.HARDWARE.equals("ranchu")) { return true; } if (new File("/dev/socket/qemud").exists() || new File("/dev/qemu_pipe").exists()) { return true; } try { TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); if (telephonyManager != null) { String deviceId = telephonyManager.getDeviceId(); List<String> knownNumbers = Arrays.asList(known_numbers); if (knownNumbers.contains(deviceId)) { return true; } } } catch (Exception e) { } return false; }

上述代码使用了多种方法来检测设备是否为模拟器,这些方法包括:

  • 检测 Build.FINGERPRINT 是否以 “generic” 或 “unknown” 开头
  • 检测 Build.MODEL 是否包含 “google_sdk”、“Emulator” 或 “Android SDK built for x86”
  • 检测 Build.MANUFACTURER 是否为 “Genymotion”
  • 检测 Build.PRODUCT 是否为 “sdk”、“sdk_x86”、“vbox86p” 或 “emulator”
  • 检测 Build.BOARD 是否为 “unknown” 或包含 “android” 或 “droid”
  • 检测 Build.DEVICE 是否为 “unknown” 或包含 “android” 或 “droid”
  • 检测 Build.HARDWARE 是否为 “goldfish”、“ranchu” 或包含 “ranchu”
  • 检测 Build.BRAND 是否以 “generic” 开头,且 Build.DEVICE 以 “generic” 开头
  • 检测 Build.PRODUCT 是否为 “google_sdk”
  • 检测是否存在文件 “/dev/socket/qemud” 或 “/dev/qemu_pipe”
  • 检测设备的电话号码是否为已知的模拟器电话号码

上述方法都是基于固件信息的判断,通过测试发现很多模拟器都失效,参考网上的教程,还有蓝牙、光线传感器、cpu检测,配合上面的固件信息,基本可以搞定大部分模拟器。

蓝牙检测代码:

public 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; } } }

光传感器检测代码:

public static Boolean notHasLightSensorManager(Context context) { SensorManager sensorManager = (SensorManager) context.getSystemService(SENSOR_SERVICE); Sensor sensor8 = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); //光 if (null == sensor8) { return true; } else { return false; } }

CPU检测代码:

public static boolean checkIsNotRealPhone() { String cpuInfo = readCpuInfo(); if ((cpuInfo.contains("intel") || cpuInfo.contains("amd"))) { return true; } return false; }public 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; }

以上检测方法也不是完全可行,随着Android系统的更新,模拟器的增多,我们需要具体研究对应的一些变动来更新上述代码。

我们检测要注意一个问题,不一定能检测出所有的模拟器,但是一定不能误杀真机。
Android 模拟器检测,在这里插入图片描述,第2张

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/13518187.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2024-01-07
下一篇 2024-01-14

发表评论

登录后才能评论

评论列表(0条)

保存