エミュレーターで実行するときと、デバイスで実行するときとで、コードの実行を少しずつ変えたいと思います。 (たとえば、パブリックURLの代わりに10.0.2.2を使用して開発サーバーに対して自動的に実行されます。)Androidアプリケーションが実行されていることを検出する最良の方法は何ですかエミュレータ?
このソリューションはどうですか:
public static boolean isEmulator() {
return 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);
}
1つの一般的なものはBuild.FINGERPRINT.contains("generic")
のようです
まあAndroid idは私のために動作しません、私は現在使用しています:
"google_sdk".equals( Build.PRODUCT );
他の回答からのヒントに基づいて、これはおそらく最も堅牢な方法です。
isEmulator = "goldfish".equals(Build.HARDWARE)
アプリがデバッグキーで署名されているかどうかを確認するには、次のコードのようなものはどうですか?エミュレーターを検出していませんが、目的に合っているかもしれません。
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;
}
このコードは私のために働く
TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
String networkOperator = tm.getNetworkOperatorName();
if("Android".equals(networkOperator)) {
// Emulator
}
else {
// Device
}
デバイスにsimカードがない場合、空の文字列を再チューニングします: ""
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)
または
"google_sdk".equals(Build.PRODUCT)
_sdk
、_sdk_
、sdk_
、またはBuild.PRODUCT
のsdk
部分だけを探します。
if(Build.PRODUCT.matches(".*_?sdk_?.*")){
//-- emulator --
}else{
//-- other device --
}
エミュレータにいるかどうかを判断する良い方法を見つけられませんでした。
しかし、開発環境にいる場合に検出する必要がある場合、これを行うことができます:
if(Debug.isDebuggerConnected() ) {
// Things to do in debug environment...
}
この助けを願って....
ここに私のソリューションがあります(デバッグマシンでWebサーバーを実行している場合にのみ機能します)。アプリケーションの起動時に開始するバックグラウンドタスクを作成しました。 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("");
Emuを検出するより良い方法があるかどうかはわかりませんが、エミュレータのルートディレクトリにはinit.goldfish.rc
ファイルがあります。
これはエミュレーター固有の起動スクリプトであり、エミュレーター以外のビルドには存在しないはずです。
この関数を使用します:
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;
}
バッテリーから、エミュレーター:電源は常にAC充電器です。温度は常に0です。
また、Build.Host
を使用してホスト値を記録できます。エミュレータごとにホスト値が異なります。
1つの方法ですべての回答
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;
}
別のオプションは、ro.hardwareプロパティを調べて、そのプロパティが金魚に設定されているかどうかを確認することです。残念ながら、これをJavaから簡単に行う方法はないようですが、Cでは property_get() を使用して簡単に実行できます。
新しいエミュレータBuild.HARDWARE = "ranchu"
を見つけました。
リファレンス: https://groups.google.com/forum/#!topic/Android-emulator-dev/dltBnUW_Hz
また、エミュレータの有無を確認するための公式の方法である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
があります。
エミュレータが新しくないかどうかをチェックする方法、またおそらく十分ではない、上記の答えも述べました。
しかし、これはおそらく、オフィシャルがエミュレータかどうかをチェックするオフィシャルの方法を提供することを示しているかもしれません。
上記のすべての方法を使用して、今はエミュレーターかどうかを確認する2つの方法も使用できます.
com.Android.internal
パッケージと@hide
へのアクセス方法
公式のオープンSDKを待ちます。
私の推奨事項:
githubから this を試してください。
Androidエミュレーターを簡単に検出
- デバイスファームの実際のデバイスでチェック済み( https://aws.Amazon.com/device-farm/ )
- BlueStacks
- ジェニーモーション
- Androidエミュレーター
- アンディ46.2.207.0
- めむプレイ
- Noxアプリプレーヤー
- コプレイヤー
- .....
例で使用する方法:
EmulatorDetector.with(this)
.setCheckTelephony(true)
.addPackageName("com.bluestacks")
.setDebug(true)
.detect(new EmulatorDetector.OnEmulatorDetectorListener() {
@Override
public void onResult(boolean isEmulator) {
}
});
Googleは、Flutterの device-infoプラグイン でこのコードを使用して、デバイスがエミュレーターかどうかを判断します。
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");
}
Android 2.2でリリースされた最新のSDKツールに本日更新するまで、Android_ID
を確認する上記の推奨ソリューションが機能しました。
したがって、私は現在、次のソリューションに切り替えましたが、これはこれまでのところ動作しますが、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);
}
}
iMEI番号を確認できます、 http://developer.Android.com/reference/Android/telephony/TelephonyManager.html#getDeviceId%28%29
エミュレータでリコールした場合、これは0を返します。ただし、それを保証するドキュメントはありません。エミュレータは常に0を返すとは限りませんが、登録済みの電話が0を返さないことはかなり安全なようです。電話以外のAndroidデバイス、SIMカードがインストールされていないデバイス、現在ネットワークに登録されていますか?
それに依存するのは悪い考えだと思われる。
また、電話の状態を読み取るための許可を求める必要があることを意味します。これは、何か他のもののためにそれをまだ必要としない場合は悪いことです。
そうでない場合は、署名済みアプリを最終的に生成する前に、常にどこかで少し反転します。
Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")
アプリがエミュレータで実行されている場合、これはtrueを返す必要があります。
いくつかの異なるエミュレーターしかないため、注意が必要なのはすべてのエミュレーターを検出することではありません。確認は簡単です。実際のデバイスがエミュレーターとして検出されないようにする必要があります。
これを確認するために、「 Android Device Info Share 」というアプリを使用しました。
このアプリでは、多くのデバイスのさまざまな種類の情報を見ることができます(おそらく世界のほとんどのデバイス。使用しているデバイスがリストにない場合、自動的に追加されます)。
この質問に関するすべての回答を収集し、Androidがvm/emulatorで実行されているかどうかを検出する機能を思い付きました。
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でテスト済み(2015年10月1日)。
これは私のために働く
public boolean isEmulator() {
return Build.MANUFACTURER.equals("unknown");
}
エミュレーターのファイルシステムにファイルを配置します。ファイルは実際のデバイスには存在しないため、これは安定しており、信頼性が高く、壊れたときに簡単に修正できるはずです。
実際、2.2のAndroid_IDは常に9774D56D682E549C( このスレッド +私自身の実験による)と等しくなります。
したがって、次のようなものを確認できます。
String androidID = ...;
if(androidID == null || androidID.equals("9774D56D682E549C"))
do stuff;
最もきれいではないが、それは仕事をする。
答えを確認すると、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;
}
Genymotionの基礎となるエミュレーションエンジンはVirtualBoxであり、これはすぐには変更されないため、次のコードが最も信頼性が高いことがわかりました。
public static boolean isGenymotion() {
return Build.PRODUCT != null && Build.PRODUCT.contains("vbox");
}
どのコードを使用してエミュレーターの検出を行う場合でも、依存関係にある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アナリティクスを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種類のアプリを作成できます。
if ("sdk".equals( Build.PRODUCT )) {
// Then you are running the app on the emulator.
Log.w("MyAPP", "\n\n Emulator \n\n");
}
if (Build.BRAND.equalsIgnoreCase("generic")) {
// Is the emulator
}
すべてのBUILD参照はbuild.prop値であるため、これをリリースコードに含める場合、何らかの理由でルートを変更したユーザーがいる可能性があることを考慮する必要があります。エミュレータを特にエミュレートしようとしない限り、ジェネリックをブランドとして使用する必要がある変更は事実上ありません。
指紋は、ビルドコンパイルおよびカーネルコンパイルのシグネチャです。一般的にGoogleから直接提供される汎用を使用するビルドがあります。
変更されたデバイスでは、IMEIがゼロにリセットされる可能性があるため、変更されたデバイスを完全にブロックしない限り、これは信頼できません。
Goldfishは、他のすべてのデバイスが拡張されるベースAndroidビルドです。不明な理由でハッキングされて削除されない限り、すべてのAndroidデバイスにはinit.goldfish.rcがあります。
これはstartsWith
の代わりに私のために働いた:Build.FINGERPRINT.contains("generic")
詳細については、このリンクを確認してください: https://Gist.github.com/espinchi/168abf054425893d86d1