Я хотел бы, чтобы мой код выполнялся немного иначе при работе на эмуляторе, чем при работе на устройстве. (Например, использование 10.0.2.2 вместо общедоступного URL-адреса для автоматического запуска на сервере разработки.) Как лучше всего определить, когда приложение Android выполняется в эмуляторе?
Как я могу определить, когда приложение Android запущено в эмуляторе?
Ответы (39)
Как насчет этого решения (реализация класса SystemProperties
доступна здесь):
private var sIsProbablyRunningOnEmulator: Boolean? = null
fun isProbablyRunningOnEmulator(): Boolean {
var result = sIsProbablyRunningOnEmulator
if (result != null)
return result
// Android SDK emulator
result = (Build.FINGERPRINT.startsWith("google/sdk_gphone_")
&& Build.FINGERPRINT.endsWith(":user/release-keys")
&& Build.MANUFACTURER == "Google" && Build.PRODUCT.startsWith("sdk_gphone_") && Build.BRAND == "google"
&& Build.MODEL.startsWith("sdk_gphone_"))
//
|| 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")
//bluestacks
|| "QC_Reference_Phone" == Build.BOARD && !"Xiaomi".equals(Build.MANUFACTURER, ignoreCase = true) //bluestacks
|| Build.MANUFACTURER.contains("Genymotion")
|| Build.HOST=="Build2" //MSI App Player
|| Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")
|| Build.PRODUCT == "google_sdk"
// another Android SDK emulator check
|| SystemProperties.getProp("ro.kernel.qemu") == "1"
sIsProbablyRunningOnEmulator = result
return result
}
Обратите внимание, что некоторые эмуляторы подделывают точные характеристики реальных устройств, поэтому их может быть невозможно обнаружить. Я добавил все, что мог, но не думаю, что есть 100% способ определить, действительно ли это эмулятор или нет.
Вот крошечный фрагмент, который вы можете сделать в APK, чтобы показать разные вещи о нем, чтобы вы могли добавить свои собственные правила:
textView.text = "FINGERPRINT:${Build.FINGERPRINT}\n" +
"MODEL:${Build.MODEL}\n" +
"MANUFACTURER:${Build.MANUFACTURER}\n" +
"BRAND:${Build.BRAND}\n" +
"DEVICE:${Build.DEVICE}\n" +
"BOARD:${Build.BOARD}\n" +
"HOST:${Build.HOST}\n" +
"PRODUCT:${Build.PRODUCT}\n"
Build
и решите, что лучше всего подходит для вашего случая. Я не могу просто протестировать все текущие приложения-эмуляторы на ПК и будущие и собрать их все. Это непрактично. Я только что получил некоторые из них.
- person android developer; 07.05.2019
Один общий может быть Build.FINGERPRINT.contains("generic")
FINGERPRINT
значение.
- person gnuf; 14.12.2015
Ну, Android id у меня не работает, сейчас я использую:
"google_sdk".equals( Build.PRODUCT );
sdk_x86
.
- person gdw2; 02.10.2013
Build
получить строку типа String product = "" + Build.PRODUCT;
, потому что она может быть нулевой, но contains
все равно можно использовать, а не equals
. Дополнительно используйте toLowercase
для сравнения без учета регистра.
- person Manuel; 20.05.2019
Google использует этот код в подключаемом модуле информации об устройстве от Flutter, чтобы определить, устройство является эмулятором:
private boolean isEmulator() {
return (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
|| Build.FINGERPRINT.startsWith("generic")
|| Build.FINGERPRINT.startsWith("unknown")
|| Build.HARDWARE.contains("goldfish")
|| Build.HARDWARE.contains("ranchu")
|| Build.MODEL.contains("google_sdk")
|| Build.MODEL.contains("Emulator")
|| Build.MODEL.contains("Android SDK built for x86")
|| Build.MANUFACTURER.contains("Genymotion")
|| Build.PRODUCT.contains("sdk_google")
|| Build.PRODUCT.contains("google_sdk")
|| Build.PRODUCT.contains("sdk")
|| Build.PRODUCT.contains("sdk_x86")
|| Build.PRODUCT.contains("vbox86p")
|| Build.PRODUCT.contains("emulator")
|| Build.PRODUCT.contains("simulator");
}
public static boolean isEmulator(Context context) { String androidId = Secure.getString(context.getContentResolver(), "android_id"); return "sdk".equals(Build.PRODUCT) || "google_sdk".equals(Build.PRODUCT) || androidId == null; }
- person Pepijn; 24.02.2021
Основываясь на подсказках из других ответов, это, вероятно, самый надежный способ:
isEmulator = "goldfish".equals(Build.HARDWARE)
isEmulator = Build.HARDWARE.contains("golfdish")
- person holmes; 02.10.2013
Как насчет чего-то вроде приведенного ниже кода, чтобы узнать, было ли ваше приложение подписано с помощью ключа отладки? он не определяет эмулятор, но он может работать для ваших целей?
public void onCreate Bundle b ) {
super.onCreate(savedInstanceState);
if ( signedWithDebugKey(this,this.getClass()) ) {
blah blah blah
}
blah
blah
blah
}
static final String DEBUGKEY =
"get the debug key from logcat after calling the function below once from the emulator";
public static boolean signedWithDebugKey(Context context, Class<?> cls)
{
boolean result = false;
try {
ComponentName comp = new ComponentName(context, cls);
PackageInfo pinfo = context.getPackageManager().getPackageInfo(comp.getPackageName(),PackageManager.GET_SIGNATURES);
Signature sigs[] = pinfo.signatures;
for ( int i = 0; i < sigs.length;i++)
Log.d(TAG,sigs[i].toCharsString());
if (DEBUGKEY.equals(sigs[0].toCharsString())) {
result = true;
Log.d(TAG,"package has been signed with the debug key");
} else {
Log.d(TAG,"package signed with a key other than the debug key");
}
} catch (android.content.pm.PackageManager.NameNotFoundException e) {
return false;
}
return result;
}
BuildConfig.DEBUG
.
- person Mygod; 15.05.2017
Этот код работает для меня
TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
String networkOperator = tm.getNetworkOperatorName();
if("Android".equals(networkOperator)) {
// Emulator
}
else {
// Device
}
Если на этом устройстве нет сим-карты, возвращается пустая строка: ""
Поскольку в эмуляторе Android всегда используется «Android» в качестве оператора сети, я использую приведенный выше код.
Я попробовал несколько техник, но остановился на слегка измененной версии проверки Build.PRODUCT, как показано ниже. Кажется, это немного отличается от эмулятора к эмулятору, поэтому у меня есть 3 проверки, которые у меня есть. Думаю, я мог бы просто проверить, есть ли product.contains ("sdk"), но подумал, что проверка ниже была немного безопаснее.
public static boolean isAndroidEmulator() {
String model = Build.MODEL;
Log.d(TAG, "model=" + model);
String product = Build.PRODUCT;
Log.d(TAG, "product=" + product);
boolean isEmulator = false;
if (product != null) {
isEmulator = product.equals("sdk") || product.contains("_sdk") || product.contains("sdk_");
}
Log.d(TAG, "isEmulator=" + isEmulator);
return isEmulator;
}
К вашему сведению - я обнаружил, что на моем Kindle Fire был Build.BRAND = "generic", а в некоторых эмуляторах не было "Android" для оператора сети.
Оба следующих параметра имеют значение "google_sdk":
Build.PRODUCT
Build.MODEL
Поэтому должно быть достаточно использовать одну из следующих строк.
"google_sdk".equals(Build.MODEL)
or
"google_sdk".equals(Build.PRODUCT)
sdk_x86
.
- person Edward Brey; 15.10.2013
Я просто ищу _sdk
, _sdk_
или sdk_
, или даже просто sdk
часть в Build.PRODUCT
:
if(Build.PRODUCT.matches(".*_?sdk_?.*")){
//-- emulator --
}else{
//-- other device --
}
contains("sdk")
? Единственное отличие (кроме скорости) состоит в том, что matches(".*_?sdk_?.*")
требует, чтобы если до или после sdk есть символ, он должен быть подчеркиванием '_', что не так важно для проверки.
- person Nulano; 28.01.2015
Я так и не нашел хорошего способа узнать, используете ли вы эмулятор.
но если вам просто нужно определить, находитесь ли вы в среде разработки, вы можете сделать это:
if(Debug.isDebuggerConnected() ) {
// Things to do in debug environment...
}
Надеюсь на эту помощь ....
используйте эту функцию:
public static final boolean isEmulator() {
int rating = 0;
if ((Build.PRODUCT.equals("sdk")) || (Build.PRODUCT.equals("google_sdk"))
|| (Build.PRODUCT.equals("sdk_x86")) || (Build.PRODUCT.equals("vbox86p"))) {
rating++;
}
if ((Build.MANUFACTURER.equals("unknown")) || (Build.MANUFACTURER.equals("Genymotion"))) {
rating++;
}
if ((Build.BRAND.equals("generic")) || (Build.BRAND.equals("generic_x86"))) {
rating++;
}
if ((Build.DEVICE.equals("generic")) || (Build.DEVICE.equals("generic_x86")) || (Build.DEVICE.equals("vbox86p"))) {
rating++;
}
if ((Build.MODEL.equals("sdk")) || (Build.MODEL.equals("google_sdk"))
|| (Build.MODEL.equals("Android SDK built for x86"))) {
rating++;
}
if ((Build.HARDWARE.equals("goldfish")) || (Build.HARDWARE.equals("vbox86"))) {
rating++;
}
if ((Build.FINGERPRINT.contains("generic/sdk/generic"))
|| (Build.FINGERPRINT.contains("generic_x86/sdk_x86/generic_x86"))
|| (Build.FINGERPRINT.contains("generic/google_sdk/generic"))
|| (Build.FINGERPRINT.contains("generic/vbox86p/vbox86p"))) {
rating++;
}
return rating > 4;
}
Не знаю, есть ли лучшие способы обнаружить эму, но у эмулятора будет файл init.goldfish.rc
в корневом каталоге.
Это сценарий запуска, специфичный для эмулятора, и его не должно быть в сборке без эмулятора.
Вот мое решение (оно работает, только если вы запускаете веб-сервер на своей отладочной машине): я создал фоновую задачу, которая запускается при запуске приложения. Он ищет http://10.0.2.2 и, если он существует, меняет глобальный параметр (IsDebug) на true. Это бесшумный способ узнать, куда вы бежите.
public class CheckDebugModeTask extends AsyncTask<String, Void, String> {
public static boolean IsDebug = false;
public CheckDebugModeTask()
{
}
@Override
protected String doInBackground(String... params) {
try {
HttpParams httpParameters = new BasicHttpParams();
int timeoutConnection = 1000;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
int timeoutSocket = 2000;
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
String url2 = "http://10.0.2.2";
HttpGet httpGet = new HttpGet(url2);
DefaultHttpClient client = new DefaultHttpClient(httpParameters);
HttpResponse response2 = client.execute(httpGet);
if (response2 == null || response2.getEntity() == null || response2.getEntity().getContent() == null)
return "";
return "Debug";
} catch (Exception e) {
return "";
}
}
@Override
protected void onPostExecute (String result)
{
if (result == "Debug")
{
CheckDebugModeTask.IsDebug = true;
}
}
из основного действия onCreate:
CheckDebugModeTask checkDebugMode = new CheckDebugModeTask();
checkDebugMode.execute("");
От Аккумулятора, эмулятора: Источником питания всегда является зарядное устройство переменного тока. Температура всегда 0.
И вы можете использовать Build.HOST
для записи значения хоста, разные эмуляторы имеют разные значения хоста.
Другой вариант - посмотреть на свойство ro.hardware и посмотреть, установлено ли для него значение goldfish. К сожалению, кажется, нет простого способа сделать это из Java, но тривиально из C, используя property_get ().
Нашел новый эмулятор Build.HARDWARE = "ranchu"
.
Ссылка: https://groups.google.com/forum/#!topic/android-emulator-dev/dltBnUW_HzU
А также я нашел официальный способ Android проверить, есть ли эмулятор или нет. Я думаю, что это хороший ориентир для нас.
Начиная с Android API уровня 23 [Android 6.0]
package com.android.internal.util;
/**
* @hide
*/
public class ScreenShapeHelper {
private static final boolean IS_EMULATOR = Build.HARDWARE.contains("goldfish");
}
У нас есть ScreenShapeHelper.IS_EMULATOR
, чтобы проверить, работает ли эмулятор.
Начиная с Android API уровня 24 [Android 7.0]
package android.os;
/**
* Information about the current build, extracted from system properties.
*/
public class Build {
/**
* Whether this build was for an emulator device.
* @hide
*/
public static final boolean IS_EMULATOR = getString("ro.kernel.qemu").equals("1");
}
У нас есть Build.IS_EMULATOR
, чтобы проверить, работает ли эмулятор.
Способ официальной проверки, не является ли эмулятор новым, а также, может быть, недостаточно, ответы выше также упоминались.
Но это может показать нам, что официальное лицо предоставит официальную возможность проверить, является ли эмулятор эмулятором или нет.
Используя все вышеупомянутые способы, прямо сейчас мы также можем использовать два способа, чтобы проверить, есть ли файл emulator.
Как получить доступ к пакету com.android.internal
и @hide
и дождитесь официального открытия SDK.
Выше предложенное решение для проверки ANDROID_ID
работало для меня, пока я не обновился сегодня до последних инструментов SDK, выпущенных с Android 2.2.
Поэтому в настоящее время я переключился на следующее решение, которое пока работает с тем недостатком, что вам необходимо установить разрешение на чтение PHONE_STATE (<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
)
private void checkForDebugMode() {
ISDEBUGMODE = false; //(Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID) == null);
TelephonyManager man = (TelephonyManager) getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
if(man != null){
String devId = man.getDeviceSoftwareVersion();
ISDEBUGMODE = (devId == null);
}
}
Все ответы одним методом
static boolean checkEmulator()
{
try
{
String buildDetails = (Build.FINGERPRINT + Build.DEVICE + Build.MODEL + Build.BRAND + Build.PRODUCT + Build.MANUFACTURER + Build.HARDWARE).toLowerCase();
if (buildDetails.contains("generic")
|| buildDetails.contains("unknown")
|| buildDetails.contains("emulator")
|| buildDetails.contains("sdk")
|| buildDetails.contains("genymotion")
|| buildDetails.contains("x86") // this includes vbox86
|| buildDetails.contains("goldfish")
|| buildDetails.contains("test-keys"))
return true;
}
catch (Throwable t) {Logger.catchedError(t);}
try
{
TelephonyManager tm = (TelephonyManager) App.context.getSystemService(Context.TELEPHONY_SERVICE);
String non = tm.getNetworkOperatorName().toLowerCase();
if (non.equals("android"))
return true;
}
catch (Throwable t) {Logger.catchedError(t);}
try
{
if (new File ("/init.goldfish.rc").exists())
return true;
}
catch (Throwable t) {Logger.catchedError(t);}
return false;
}
init.goldfish.rc
существует только в эмуляторах; это также хорошая проверка в будущем в дополнение к деталям сборки.
- person sud007; 25.05.2016
Моя рекомендация:
попробуйте это с github.
Легко обнаружить эмулятор Android
- Проверено на реальных устройствах в Device Farm (https://aws.amazon.com/device-farm/ < / а>)
- BlueStacks
- Genymotion
- Эмулятор Android
- Энди 46.2.207.0
- MEmu играть
- Nox App Player
- Koplayer
- .....
Как использовать с примером:
EmulatorDetector.with(this)
.setCheckTelephony(true)
.addPackageName("com.bluestacks")
.setDebug(true)
.detect(new EmulatorDetector.OnEmulatorDetectorListener() {
@Override
public void onResult(boolean isEmulator) {
if(isEmulator){
// Do your work
}
else{
// Not emulator and do your work
}
}
});
Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")
Это должно вернуть истину, если приложение работает на эмуляторе.
Мы должны быть осторожны, так это не обнаруживать все эмуляторы, потому что существует только несколько разных эмуляторов. Проверить это несложно. Мы должны убедиться, что реальные устройства не распознаются как эмуляторы.
Я использовал приложение под названием "Android Device Info Share ", чтобы проверить это.
В этом приложении вы можете видеть различную информацию о многих устройствах (вероятно, о большинстве устройств в мире; если устройство, которое вы используете, отсутствует в списке, оно будет добавлено автоматически).
Проверяю ответы, ни один из них не работал при использовании эмуляторов LeapDroid, Droid4x или Andy,
Во всех случаях работает следующее:
private static String getSystemProperty(String name) throws Exception {
Class systemPropertyClazz = Class.forName("android.os.SystemProperties");
return (String) systemPropertyClazz.getMethod("get", new Class[]{String.class}).invoke(systemPropertyClazz, new Object[]{name});
}
public boolean isEmulator() {
boolean goldfish = getSystemProperty("ro.hardware").contains("goldfish");
boolean emu = getSystemProperty("ro.kernel.qemu").length() > 0;
boolean sdk = getSystemProperty("ro.product.model").equals("sdk");
return goldfish || emu || sdk;
}
вы можете проверить IMEI #, http://developer.android.com/reference/android/telephony/TelephonyManager.html#getDeviceId%28%29
если я напомню на эмуляторе это возвращение 0. Однако я не могу найти никакой документации, которая бы это гарантировала. хотя эмулятор не всегда может возвращать 0, кажется довольно безопасным, что зарегистрированный телефон не вернет 0. что произойдет на устройстве Android, не являющемся телефоном, или на устройстве без установленной SIM-карты, или на устройстве, которое в настоящее время не зарегистрировано на сеть?
похоже, что это было бы плохой идеей, полагаться на это.
это также означает, что вам нужно будет запросить разрешение на чтение состояния телефона, что плохо, если вам это еще не требуется для чего-то другого.
если не это, то всегда нужно что-то переворачивать, прежде чем вы наконец сгенерируете свое подписанное приложение.
0
на планшете Android или на телефоне без SIM-карты.
- person Paul Lammertsma; 11.03.2011
Фактически, ANDROID_ID в 2.2 всегда равен 9774D56D682E549C (согласно эта ветка + мои собственные эксперименты).
Итак, вы можете проверить что-то вроде этого:
String androidID = ...;
if(androidID == null || androidID.equals("9774D56D682E549C"))
do stuff;
Не самый красивый, но работает.
Это работает для меня
public boolean isEmulator() {
return Build.MANUFACTURER.equals("unknown");
}
Поместите файл в файловую систему эмулятора; поскольку файл не существует на реальном устройстве, он должен быть стабильным, надежным и легко исправляемым в случае поломки.
Я собрал все ответы на этот вопрос и придумал функцию, чтобы определить, работает ли Android на виртуальной машине / эмуляторе:
public boolean isvm(){
StringBuilder deviceInfo = new StringBuilder();
deviceInfo.append("Build.PRODUCT " +Build.PRODUCT +"\n");
deviceInfo.append("Build.FINGERPRINT " +Build.FINGERPRINT+"\n");
deviceInfo.append("Build.MANUFACTURER " +Build.MANUFACTURER+"\n");
deviceInfo.append("Build.MODEL " +Build.MODEL+"\n");
deviceInfo.append("Build.BRAND " +Build.BRAND+"\n");
deviceInfo.append("Build.DEVICE " +Build.DEVICE+"\n");
String info = deviceInfo.toString();
Log.i("LOB", info);
Boolean isvm = false;
if(
"google_sdk".equals(Build.PRODUCT) ||
"sdk_google_phone_x86".equals(Build.PRODUCT) ||
"sdk".equals(Build.PRODUCT) ||
"sdk_x86".equals(Build.PRODUCT) ||
"vbox86p".equals(Build.PRODUCT) ||
Build.FINGERPRINT.contains("generic") ||
Build.MANUFACTURER.contains("Genymotion") ||
Build.MODEL.contains("Emulator") ||
Build.MODEL.contains("Android SDK built for x86")
){
isvm = true;
}
if(Build.BRAND.contains("generic")&&Build.DEVICE.contains("generic")){
isvm = true;
}
return isvm;
}
Протестировано на эмуляторе, Genymotion и Bluestacks (1 октября 2015 г.).
Какой бы код вы ни использовали для обнаружения эмулятора, я настоятельно рекомендую писать модульные тесты, чтобы охватить все значения Build.FINGERPRINT
, Build.HARDWARE
и Build.MANUFACTURER
, от которых вы зависите. Вот несколько примеров тестов:
@Test
public void testIsEmulatorGenymotion() throws Exception {
assertThat(
DeviceUtils.isRunningOnEmulator(
"generic/vbox86p/vbox86p:4.1.1/JRO03S/eng.buildbot.20150217.102902:userdebug/test-keys",
"vbox86", "Genymotion")).isTrue();
assertThat(
DeviceUtils.isRunningOnEmulator(
"generic/vbox86p/vbox86p:5.1/LMY47D/buildbot06092001:userdebug/test-keys", "vbox86",
"Genymotion")).isTrue();
}
@Test
public void testIsEmulatorDefaultAndroidEmulator() throws Exception {
assertThat(
DeviceUtils.isRunningOnEmulator(
"generic_x86/sdk_google_phone_x86/generic_x86:5.0.2/LSY66H/1960483:eng/test-keys", "goldfish",
"unknown")).isTrue();
assertThat(
DeviceUtils.isRunningOnEmulator(
"Android/sdk_google_phone_x86_64/generic_x86_64:6.0/MASTER/2469028:userdebug/test-keys",
"ranchu", "unknown")).isTrue();
}
@Test
public void testIsEmulatorRealNexus5() throws Exception {
assertThat(
DeviceUtils.isRunningOnEmulator("google/hammerhead/hammerhead:6.0.1/MMB29K/2419427:user/release-keys",
"hammerhead", "LGE")).isFalse();
}
... и вот наш код (журналы отладки и комментарии удалены для краткости):
public static boolean isRunningOnEmulator() {
if (sIsRunningEmulator == null) {
sIsRunningEmulator = isRunningOnEmulator(Build.FINGERPRINT, Build.HARDWARE, Build.MANUFACTURER);
}
return sIsRunningEmulator;
}
static boolean isRunningOnEmulator(String fingerprint, String hardware, String manufacturer) {
boolean isEmulatorFingerprint = fingerprint.endsWith("test-keys");
boolean isEmulatorManufacturer = manufacturer.equals("Genymotion")
|| manufacturer.equals("unknown");
if (isEmulatorFingerprint && isEmulatorManufacturer) {
return true;
} else {
return false;
}
}
Другой вариант - проверить, находитесь ли вы в режиме отладки или в рабочем режиме:
if (BuildConfig.DEBUG) { Log.i(TAG, "I am in debug mode"); }
простой и надежный.
Не совсем ответ на вопрос, но в большинстве случаев вы можете захотеть различать сеансы отладки / тестирования и жизненные сеансы вашей пользовательской базы.
В моем случае я установил для Google Analytics dryRun () в режиме отладки, поэтому этот подход мне подходит.
Для более продвинутых пользователей есть еще один вариант. Варианты сборки gradle:
в файле Gradle вашего приложения добавьте новый вариант:
buildTypes {
release {
// some already existing commands
}
debug {
// some already existing commands
}
// the following is new
test {
}
}
В вашем коде проверьте тип сборки:
if ("test".equals(BuildConfig.BUILD_TYPE)) { Log.i(TAG, "I am in Test build type"); }
else if ("debug".equals(BuildConfig.BUILD_TYPE)) { Log.i(TAG, "I am in Debug build type"); }
Теперь у вас есть возможность создать 3 разных типа вашего приложения.
Поскольку основным механизмом эмуляции для Genymotion является VirtualBox, и это не изменится в ближайшее время, я нашел следующий код наиболее надежным:
public static boolean isGenymotion() {
return Build.PRODUCT != null && Build.PRODUCT.contains("vbox");
}
if (Build.BRAND.equalsIgnoreCase("generic")) {
// Is the emulator
}
Все ссылки на BUILD являются значениями build.prop, поэтому вы должны учитывать, что если вы собираетесь поместить это в код выпуска, у вас могут быть некоторые пользователи с правами root, которые изменили свои по какой-либо причине. Практически нет модификаций, требующих использования в качестве бренда generic, если специально не пытаться имитировать эмулятор.
Отпечаток пальца - это подпись компиляции сборки и компиляции ядра. Существуют сборки, использующие общие, обычно получаемые напрямую от Google.
На устройстве, которое было модифицировано, IMEI также может быть обнулен, так что это ненадежно, если вы не блокируете модифицированные устройства полностью.
Goldfish - это базовая сборка Android, от которой расширены все остальные устройства. На КАЖДОМ устройстве Android есть файл init.goldfish.rc, если его не взломали и не удалили по неизвестным причинам.
Это сработало для меня вместо startsWith
: Build.FINGERPRINT.contains("generic")
Для получения дополнительной информации перейдите по этой ссылке: https://gist.github.com/espinchi/168abf054425893d86d1
попробуйте эту ссылку с github.
https://github.com/mofneko/EmulatorDetector
Этот модуль поможет вам эмулировать обнаружение вашего Android-проекта, поддерживающего Unity.
Базовая проверка
- BlueStacks
- Genymotion
- Эмулятор Android
- Nox App Player
- Koplayer
- .....
Рекомендуется проверить, установлены ли на устройстве следующие пакеты:
mListPackageName.add("com.google.android.launcher.layouts.genymotion");
mListPackageName.add("com.bluestacks");
mListPackageName.add("com.vphone.launcher");
mListPackageName.add("com.bignox.app");
А затем просто сверяйтесь с менеджером пакетов, пока он не найдет его.
private static boolean isEmulByPackage(Context context) {
final PackageManager pm = context.getPackageManager();
for (final String pkgName : mListPackageName) {
return isPackageInstalled(pkgName, pm);
}
return false;
}
private static boolean isPackageInstalled(final String packageName, final PackageManager packageManager) {
try {
packageManager.getPackageInfo(packageName, 0);
return true;
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
Вот как Firebase Crashlytics подходит к этому:
public static boolean isEmulator(Context context) {
final String androidId = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID);
return Build.PRODUCT.contains(SDK)
|| Build.HARDWARE.contains(GOLDFISH)
|| Build.HARDWARE.contains(RANCHU)
|| androidId == null;
}
Чаще всего используется метод сопоставления значений бренда, названия ... и т. Д. Но этот метод является статическим и предназначен для ограниченных версий эмуляторов. Что, если существует более 1000 производителей виртуальных машин? тогда вам нужно будет написать код для сопоставления 1000+ виртуальных машин?
Но его время зря. Даже через некоторое время будут запущены новые другие виртуальные машины, и ваш сценарий будет потрачен впустую.
Итак, основываясь на моих тестах, я узнал, что getRadioVersion()
возвращает пустое значение на виртуальной машине и возвращает номер версии на реальном устройстве Android.
public Boolean IsVM()
{
return android.os.Build.getRadioVersion().length() == 0;
}
//return true if VM
//return false if real
Хотя это работает, но у меня нет официального объяснения этому.
Код: http://github.com/Back-X/anti-vm/blob/main/android/anti-vm.b4a
Выпуск: http://github.com/Back-X/anti-vm/releases/download/1/anti-vm.apk
этот метод работает для меня
public static boolean isRunningOnEmulator(String fingerprint, String hardware, String manufacturer) {
boolean isEmulatorFingerprint = fingerprint.endsWith("test-keys");
boolean isHardware = hardware.toLowerCase().contains("intel") || hardware.toLowerCase().contains("vbox");
boolean isEmulatorManufacturer = manufacturer.equals("Genymotion")
|| manufacturer.equals("unknown");
if (isHardware || isEmulatorFingerprint && isEmulatorManufacturer) {
return true;
} else {
return false;
}
}
Попробуйте воспользоваться этим методом.
Проверено на эмуляторах Google и Genymotion.
public Boolean IsVM() {
String radioVersion = android.os.Build.getRadioVersion();
return radioVersion == null || radioVersion.isEmpty() || radioVersion.equals("1.0.0.0");
}
Вы можете проверить, является ли deviceId (IMEI) «000000000000000» (15 нулей)
android.os.Build
. - person yanchenko   schedule 10.05.2010