赞
踩
识别安卓模拟器的两种方案!
禁止通过模拟器进行刷量,防止作弊行为!
- 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)) {
- // 请求接口,收集并发送设备信息至服务端,并且通过接口返回数据,决定是否绿色放行
- // 弹窗对话框,询问用户是否需要反馈模拟器误判
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。