android识别模拟器

转载请注明出处: https://blog.csdn.net/u011038298/article/details/87976225

识别安卓模拟器的两种方案!

禁止通过模拟器进行刷量,防止作弊行为!

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.telephony.TelephonyManager;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;

public class EmulatorCheckUtil {

    /**
     * 方案一:通过检测设备信息来判断设备是否为模拟器
     *
     * @param context
     * @return
     */
    public static boolean isEmulator(Context context) {
        if (context == null) {
            return false;
        }
        String url = "tel:" + "123456";
        Intent intent = new Intent();
        intent.setData(Uri.parse(url));
        intent.setAction(Intent.ACTION_DIAL);
        // 是否可以处理跳转到拨号的 Intent
        boolean canResolverIntent = intent.resolveActivity(context.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) context.getSystemService(Context.TELEPHONY_SERVICE)).getNetworkOperatorName().toLowerCase().equals("android")
                || !canResolverIntent;
    }

    /**
     * 方案二:通过一系列的研究,得出一个嫌疑指数,综合判断是否运行在模拟器中
     * 在AS模拟器上判断失准,可以与方案一相结合使用
     *
     * @return
     */
    public static boolean checkIsRunningInEmulator() {
        int suspectCount = 0;
        // 读基带信息
        String baseBandVersion = getProperty("gsm.version.baseband");
        if (baseBandVersion == null | "".equals(baseBandVersion)) {
            ++suspectCount;
        }

        // 读渠道信息,针对一些基于vBox的模拟器
        String buildFlavor = getProperty("ro.build.flavor");
        if (buildFlavor == null | "".equals(buildFlavor) | (buildFlavor != null && buildFlavor.contains("vbox"))) {
            ++suspectCount;
        }

        // 读处理器信息,这里经常会被处理
        String productBoard = getProperty("ro.product.board");
        if (productBoard == null | "".equals(productBoard)) {
            ++suspectCount;
        }

        // 读处理器平台,这里不常会处理
        String boardPlatform = getProperty("ro.board.platform");
        if (boardPlatform == null | "".equals(boardPlatform)) {
            ++suspectCount;
        }

        // 高通的cpu两者信息一般是一致的
        if (productBoard != null && boardPlatform != null && !productBoard.equals(boardPlatform)) {
            ++suspectCount;
        }

        // 一些模拟器读取不到进程租信息
        String filter = exec("cat /proc/self/cgroup");
        if (filter == null || filter.length() == 0) {
            ++suspectCount;
        }
        return suspectCount > 2;
    }

    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 String exec(String command) {
        BufferedOutputStream bufferedOutputStream = null;
        BufferedInputStream bufferedInputStream = null;
        Process process = null;
        try {
            process = Runtime.getRuntime().exec("sh");
            bufferedOutputStream = new BufferedOutputStream(process.getOutputStream());

            bufferedInputStream = new BufferedInputStream(process.getInputStream());
            bufferedOutputStream.write(command.getBytes());
            bufferedOutputStream.write('\n');
            bufferedOutputStream.flush();
            bufferedOutputStream.close();

            process.waitFor();

            String outputStr = getStrFromBufferInputSteam(bufferedInputStream);
            return outputStr;
        } catch (Exception e) {
            return null;
        } finally {
            if (bufferedOutputStream != null) {
                try {
                    bufferedOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bufferedInputStream != null) {
                try {
                    bufferedInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (process != null) {
                process.destroy();
            }
        }
    }

    private static String getStrFromBufferInputSteam(BufferedInputStream bufferedInputStream) {
        if (null == bufferedInputStream) {
            return "";
        }
        int BUFFER_SIZE = 512;
        byte[] buffer = new byte[BUFFER_SIZE];
        StringBuilder result = new StringBuilder();
        try {
            while (true) {
                int read = bufferedInputStream.read(buffer);
                if (read > 0) {
                    result.append(new String(buffer, 0, read));
                }
                if (read < BUFFER_SIZE) {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result.toString();
    }

}

如果担心会误判,把真正的用户档在门外,可以做一个接口收集设备信息,通过设备信息进行审核,如果确实不是模拟器,然后再放行。

if (EmulatorCheckUtil.isEmulator(this)) {
    // 请求接口,收集并发送设备信息至服务端,并且通过接口返回数据,决定是否绿色放行
    // 弹窗对话框,询问用户是否需要反馈模拟器误判
}

猜你喜欢

转载自blog.csdn.net/u011038298/article/details/87976225