转载请注明出处: 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)) {
// 请求接口,收集并发送设备信息至服务端,并且通过接口返回数据,决定是否绿色放行
// 弹窗对话框,询问用户是否需要反馈模拟器误判
}