欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

Android模拟器最新检测方法详解,

来源: 开发者 投稿于  被查看 44371 次 评论:173

Android模拟器最新检测方法详解,


目录
  • 普遍检测方法
  • 推荐模拟器检测方法
    • 设备信息检测
    • 蓝牙检测方法
    • 光传感器检测方法
    • CPU检测方法
  • 总结

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

    普遍检测方法

    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系统的更新,模拟器的增多,我们需要具体研究对应的一些变动来更新上述代码。

    我们检测要注意一个问题,不一定能检测出所有的模拟器,但是一定不能误杀真机。

    总结

    建议 首先使用传感器进行可疑性判断

    蓝牙, wifi, 电池 可以作为 辅助数据进行监听。

    附加传感器类型代码

    public String getSensorTypeName(int type) {
            switch (type) {
                case Sensor.TYPE_ACCELEROMETER:
                    return "加速度传感器";
                case Sensor.TYPE_GYROSCOPE:
                    return "陀螺仪传感器";
                case Sensor.TYPE_LIGHT:
                    return "环境光线传感器";
                case Sensor.TYPE_MAGNETIC_FIELD:
                    return "电磁场传感器";
                case Sensor.TYPE_ORIENTATION:
                    return "方向传感器";
                case Sensor.TYPE_PRESSURE:
                    return "压力传感器";
                case Sensor.TYPE_PROXIMITY:
                    return "距离传感器";
                case Sensor.TYPE_TEMPERATURE:
                    return "温度传感器";
                case Sensor.TYPE_GRAVITY:
                    return "重场传感器";
                case Sensor.TYPE_LINEAR_ACCELERATION:
                    return "线性加速度传感器";
                case Sensor.TYPE_ROTATION_VECTOR:
                    return "旋转矢量传感器";
                case Sensor.TYPE_RELATIVE_HUMIDITY:
                    return "湿度传感器";
                case Sensor.TYPE_AMBIENT_TEMPERATURE:
                    return "温度传感器";
                case Sensor.TYPE_GAME_ROTATION_VECTOR:
                    return "游戏旋转矢量传感器";
                case Sensor.TYPE_STEP_COUNTER:
                    return "计步器";
                case Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR:
                    return "地磁旋转矢量传感器";
                case Sensor.TYPE_SIGNIFICANT_MOTION:
                    return "特殊动作触发传感器";
                default:
                    return "未知传感器";
            }
        }

    到此这篇关于Android模拟器最新检测方法详解的文章就介绍到这了,更多相关Android模拟器检测内容请搜索3672js教程以前的文章或继续浏览下面的相关文章希望大家以后多多支持3672js教程!

    您可能感兴趣的文章:
    • Android studio 三大模拟器比较(图文详解)
    • 解决Android studio模拟器启动失败的问题
    • 解决Android studio中关于模拟器的/data目录不能显示的问题
    • Android 判断真机和模拟器的方法
    • Android 模拟器的使用详细介绍

    用户评论