고유 한 Android 기기 ID가 있습니까?


14 Answers

업데이트 : Android 최신 버전에서 ANDROID_ID 와 관련된 많은 문제가 해결되었으며 더 이상이 방법이 필요하지 않다고 생각합니다. 앤서니의 대답 을 한번 보세요.

전체 공개 : 내 앱은 원래 아래 접근 방식을 사용했지만 더 이상이 접근 방식을 사용하지 않으며 이제 emmby의 답변 링크 (즉, UUID#randomUUID() 생성 및 저장)가있는 android-developers.blogspot.com/2011/03/… 항목에 설명 된 접근 방식을 사용합니다.

이 질문에 대한 많은 대답이 있습니다. 대부분은 시간의 "일부"에서만 작동 할 것이며, 불행히도 충분하지 않습니다.

내 장치 테스트 (모든 전화 중 하나 이상이 활성화되지 않음)를 기반으로합니다.

  1. 테스트 된 모든 장치는 TelephonyManager.getDeviceId() 대한 값을 반환했습니다.
  2. 모든 GSM 장치 (모두 SIM으로 테스트 됨)는 TelephonyManager.getSimSerialNumber() 대한 값을 반환했습니다.
  3. 모든 CDMA 장치가 getSimSerialNumber() 대해 null을 반환 getSimSerialNumber() 예상대로).
  4. 추가 된 Google 계정이있는 모든 기기에서 ANDROID_ID 대한 값이 반환되었습니다.
  5. 모든 CDMA 기기는 ANDROID_IDTelephonyManager.getDeviceId() 대해 동일한 값 (또는 동일한 값의 파생 값)을 반환했습니다. 설치하는 동안 Google 계정이 추가 된 경우입니다.
  6. 아직 SIM이없는 GSM 장치, Google 계정이 추가되지 않은 GSM 장치 또는 비행기 모드의 장치를 테스트 할 기회가 없었습니다.

따라서 장치 자체에 고유 한 것이 있으면 TM.getDeviceId() 로 충분 해야 합니다. 분명히 일부 사용자는 다른 사용자보다 편집증 적입니다. 따라서이 식별자 중 하나 이상을 해시하는 것이 유용 할 수 있습니다. 따라서 문자열은 기기에서 거의 고유하지만 사용자의 실제 기기를 명시 적으로 식별하지는 않습니다. 예를 들어, String.hashCode() 를 사용하여 UUID와 결합하면 다음과 같습니다.

final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);

final String tmDevice, tmSerial, androidId;
tmDevice = "" + tm.getDeviceId();
tmSerial = "" + tm.getSimSerialNumber();
androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);

UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());
String deviceId = deviceUuid.toString();

다음과 같이 표시 될 수 있습니다. 00000000-54b3-e7c7-0000-000046bffd97

그것은 나를 위해 충분히 잘 작동합니다.

Richard가 아래에서 언급했듯이 TelephonyManager 속성을 읽을 수있는 권한이 필요하다는 것을 잊지 마세요. 따라서 매니페스트에 추가하십시오.

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

import libs

import android.content.Context;
import android.telephony.TelephonyManager;
import android.view.View;
Question

Android 기기에는 고유 한 ID가 있습니까? 그렇다면 Java를 사용하여 액세스하는 간단한 방법은 무엇입니까?




For hardware recognition of a specific Android device you could check the MAC Addresses.

you can do it that way:

in AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />

now in your code:

List<NetworkInterface> interfacesList = Collections.list(NetworkInterface.getNetworkInterfaces());

for (NetworkInterface interface : interfacesList) {
   // This will give you the interface MAC ADDRESS
   interface.getHardwareAddress();
}

In every Android device their is at least a "wlan0" Interface witch is the WI-FI chip. This code works even when WI-FI is not turned on.

PS Their are a bunch of other Interfaces you will get from the list containing MACS But this can change between phones.




Dave Webb가 언급 하듯이 Android Developer Blog에는 이 문제를 다루는 기사 가 있습니다. 가장 선호하는 솔루션은 기기가 아닌 앱 설치를 추적하는 것이며 대부분의 사용 사례에서 잘 작동합니다. 블로그 게시물은 그 작업을하기 위해 필요한 코드를 보여줄 것이고, 나는 그것을 체크 아웃 할 것을 권한다.

그러나 앱 설치 식별자가 아닌 기기 식별자가 필요한 경우 블로그 게시물을 통해 해결책을 논의합니다. 나는 당신이 그렇게해야 할 이벤트에서 몇 가지 항목에 대한 몇 가지 추가 설명을 얻기 위해 구글의 누군가와 이야기했다. 앞서 언급 한 블로그 게시물에 언급되지 않은 기기 식별자에 대해 알아 낸 내용은 다음과 같습니다.

  • ANDROID_ID는 선호되는 장치 식별자입니다. ANDROID_ID는 Android 버전 2.1 이상 또는 2.3 이상에서 완벽하게 신뢰할 수 있습니다. 이 게시물에 언급 된 문제는 2.2 개뿐입니다.
  • 여러 제조업체의 여러 장치는 2.2의 ANDROID_ID 버그의 영향을받습니다.
  • 내가 결정할 수있는 한 모든 영향을받는 기기 의 ANDROID_ID9774d56d682e549c . 또한 에뮬레이터에서보고 한 것과 동일한 장치 ID 인 btw입니다.
  • Google은 OEM이 대부분의 기기 또는 대부분의 기기에서 문제를 패치 한 것으로 판단하지만 적어도 2011 년 4 월 초부터 ANDROID_ID가 깨진 기기를 쉽게 찾을 수 있음을 확인할 수있었습니다.

Google의 권장 사항에 따라 필요한 경우 시드로 ANDROID_ID를 사용하여 각 장치에 대한 고유 한 UUID를 생성하는 클래스를 구현했습니다. 필요에 따라 TelephonyManager.getDeviceId ()를 사용하여 실패한 경우 무작위로 생성 된 고유 한 UUID 앱 재시작시에도 지속됩니다 (앱 재 설치가 아님).

기기 ID에서 폴백해야하는 기기의 경우 고유 ID는 초기화시에도 계속 유지됩니다. 이것은 알고 있어야 할 것입니다. 초기화를 통해 고유 ID가 재설정되어야하는 경우 기기 ID 대신 임의의 UUID로 직접 전환하는 것이 좋습니다.

다시 말하지만이 코드는 앱 설치 ID가 아닌 기기 ID 용입니다. 대부분의 상황에서 앱 설치 ID는 아마도 당신이 찾고있는 것일 것입니다. 하지만 장치 ID가 필요하다면 다음 코드가 도움이 될 것입니다.

import android.content.Context;
import android.content.SharedPreferences;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;

import java.io.UnsupportedEncodingException;
import java.util.UUID;

public class DeviceUuidFactory {

    protected static final String PREFS_FILE = "device_id.xml";
    protected static final String PREFS_DEVICE_ID = "device_id";
    protected volatile static UUID uuid;

    public DeviceUuidFactory(Context context) {
        if (uuid == null) {
            synchronized (DeviceUuidFactory.class) {
                if (uuid == null) {
                    final SharedPreferences prefs = context
                            .getSharedPreferences(PREFS_FILE, 0);
                    final String id = prefs.getString(PREFS_DEVICE_ID, null);
                    if (id != null) {
                        // Use the ids previously computed and stored in the
                        // prefs file
                        uuid = UUID.fromString(id);
                    } else {
                        final String androidId = Secure.getString(
                            context.getContentResolver(), Secure.ANDROID_ID);
                        // Use the Android ID unless it's broken, in which case
                        // fallback on deviceId,
                        // unless it's not available, then fallback on a random
                        // number which we store to a prefs file
                        try {
                            if (!"9774d56d682e549c".equals(androidId)) {
                                uuid = UUID.nameUUIDFromBytes(androidId
                                        .getBytes("utf8"));
                            } else {
                                final String deviceId = (
                                    (TelephonyManager) context
                                    .getSystemService(Context.TELEPHONY_SERVICE))
                                    .getDeviceId();
                                uuid = deviceId != null ? UUID
                                    .nameUUIDFromBytes(deviceId
                                            .getBytes("utf8")) : UUID
                                    .randomUUID();
                            }
                        } catch (UnsupportedEncodingException e) {
                            throw new RuntimeException(e);
                        }
                        // Write the value out to the prefs file
                        prefs.edit()
                                .putString(PREFS_DEVICE_ID, uuid.toString())
                                .commit();
                    }
                }
            }
        }
    }

    /**
     * Returns a unique UUID for the current android device. As with all UUIDs,
     * this unique ID is "very highly likely" to be unique across all Android
     * devices. Much more so than ANDROID_ID is.
     * 
     * The UUID is generated by using ANDROID_ID as the base key if appropriate,
     * falling back on TelephonyManager.getDeviceID() if ANDROID_ID is known to
     * be incorrect, and finally falling back on a random UUID that's persisted
     * to SharedPreferences if getDeviceID() does not return a usable value.
     * 
     * In some rare circumstances, this ID may change. In particular, if the
     * device is factory reset a new device ID may be generated. In addition, if
     * a user upgrades their phone from certain buggy implementations of Android
     * 2.2 to a newer, non-buggy version of Android, the device ID may change.
     * Or, if a user uninstalls your app on a device that has neither a proper
     * Android ID nor a Device ID, this ID may change on reinstallation.
     * 
     * Note that if the code falls back on using TelephonyManager.getDeviceId(),
     * the resulting ID will NOT change after a factory reset. Something to be
     * aware of.
     * 
     * Works around a bug in Android 2.2 for many devices when using ANDROID_ID
     * directly.
     * 
     * @see http://code.google.com/p/android/issues/detail?id=10603
     * 
     * @return a UUID that may be used to uniquely identify your device for most
     *         purposes.
     */
    public UUID getDeviceUuid() {
        return uuid;
    }
}



There are 30+ answers here and some are same and some are unique. This answer is based on few of those answers. One of them being @Lenn Dolling's answer.

It combines 3 IDs and creates a 32-digit hex string. It has worked very well for me.

3 IDs are:
Pseudo-ID - It is generated based on physical device specifications
ANDROID_ID - Settings.Secure.ANDROID_ID
Bluetooth Address - Bluetooth adapter address

It will return something like this: 551F27C060712A72730B0A0F734064B1

Note: You can always add more IDs to the longId string. For example, Serial #. wifi adapter address. IMEI. This way you are making it more unique per device.

@SuppressWarnings("deprecation")
@SuppressLint("HardwareIds")
public static String generateDeviceIdentifier(Context context) {

        String pseudoId = "35" +
                Build.BOARD.length() % 10 +
                Build.BRAND.length() % 10 +
                Build.CPU_ABI.length() % 10 +
                Build.DEVICE.length() % 10 +
                Build.DISPLAY.length() % 10 +
                Build.HOST.length() % 10 +
                Build.ID.length() % 10 +
                Build.MANUFACTURER.length() % 10 +
                Build.MODEL.length() % 10 +
                Build.PRODUCT.length() % 10 +
                Build.TAGS.length() % 10 +
                Build.TYPE.length() % 10 +
                Build.USER.length() % 10;

        String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);

        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        String btId = "";

        if (bluetoothAdapter != null) {
            btId = bluetoothAdapter.getAddress();
        }

        String longId = pseudoId + androidId + btId;

        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.update(longId.getBytes(), 0, longId.length());

            // get md5 bytes
            byte md5Bytes[] = messageDigest.digest();

            // creating a hex string
            String identifier = "";

            for (byte md5Byte : md5Bytes) {
                int b = (0xFF & md5Byte);

                // if it is a single digit, make sure it have 0 in front (proper padding)
                if (b <= 0xF) {
                    identifier += "0";
                }

                // add number to string
                identifier += Integer.toHexString(b);
            }

            // hex string to uppercase
            identifier = identifier.toUpperCase();
            return identifier;
        } catch (Exception e) {
            Log.e("TAG", e.toString());
        }
        return "";
}



Here is how I am generating the unique id:

public static String getDeviceId(Context ctx)
{
    TelephonyManager tm = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);

    String tmDevice = tm.getDeviceId();
    String androidId = Secure.getString(ctx.getContentResolver(), Secure.ANDROID_ID);
    String serial = null;
    if(Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO) serial = Build.SERIAL;

    if(tmDevice != null) return "01" + tmDevice;
    if(androidId != null) return "02" + androidId;
    if(serial != null) return "03" + serial;
    // other alternatives (i.e. Wi-Fi MAC, Bluetooth MAC, etc.)

    return null;
}



Google Instance ID

Released at I/O 2015; on Android requires play services 7.5.

https://developers.google.com/instance-id/
https://developers.google.com/instance-id/guides/android-implementation

InstanceID iid = InstanceID.getInstance( context );   // Google docs are wrong - this requires context
String id = iid.getId();  // blocking call

It seems that Google intends for this ID to be used to identify installations across Android, Chrome, and iOS.

It identifies an installation rather then a device, but then again, ANDROID_ID (which is the accepted answer) now no longer identifies devices either. With the ARC runtime a new ANDROID_ID is generated for every installation ( details here ), just like this new instance ID. Also, I think that identifying installations (not devices) is what most of us are actually looking for.

The advantages of instance ID

It appears to me that Google intends for it to be used for this purpose (identifying your installations), it is cross-platform, and can be used for a number of other purposes (see the links above).

If you use GCM, then you will eventually need to use this instance ID because you need it in order to get the GCM token (which replaces the old GCM registration ID).

The disadvantages/issues

In the current implementation (GPS 7.5) the instance ID is retrieved from a server when your app requests it. This means that the call above is a blocking call - in my unscientific testing it takes 1-3 seconds if the device is online, and 0.5 - 1.0 seconds if off-line (presumably this is how long it waits before giving up and generating a random ID). This was tested in North America on Nexus 5 with Android 5.1.1 and GPS 7.5.

If you use the ID for the purposes they intend - eg. app authentication, app identification, GCM - I think this 1-3 seconds could be a nuisance (depending on your app, of course).




How about the IMEI . That is unique for Android or other mobile devices.







Using the code below, you can get the unique device ID of an Android OS device as a string.

deviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 



One thing I'll add - I have one of those unique situations.

사용 :

deviceId = Secure.getString(this.getContext().getContentResolver(), Secure.ANDROID_ID);

Turns out that even though my Viewsonic G Tablet reports a DeviceID that is not Null, every single G Tablet reports the same number.

Makes it interesting playing "Pocket Empires" which gives you instant access to someone's account based on the "unique" DeviceID.

My device does not have a cell radio.







The following code returns the device serial number using a hidden Android API. But, this code don't works on Samsung Galaxy Tab because "ro.serialno" isn't set on this device.

String serial = null;

try {
    Class<?> c = Class.forName("android.os.SystemProperties");
    Method get = c.getMethod("get", String.class);
    serial = (String) get.invoke(c, "ro.serialno");
}
catch (Exception ignored) {

}



Add Below code in class file:

final TelephonyManager tm = (TelephonyManager) getBaseContext()
            .getSystemService(SplashActivity.TELEPHONY_SERVICE);
    final String tmDevice, tmSerial, androidId;
    tmDevice = "" + tm.getDeviceId();
    Log.v("DeviceIMEI", "" + tmDevice);
    tmSerial = "" + tm.getSimSerialNumber();
    Log.v("GSM devices Serial Number[simcard] ", "" + tmSerial);
    androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(),
            android.provider.Settings.Secure.ANDROID_ID);
    Log.v("androidId CDMA devices", "" + androidId);
    UUID deviceUuid = new UUID(androidId.hashCode(),
            ((long) tmDevice.hashCode() << 32) | tmSerial.hashCode());
    String deviceId = deviceUuid.toString();
    Log.v("deviceIdUUID universally unique identifier", "" + deviceId);
    String deviceModelName = android.os.Build.MODEL;
    Log.v("Model Name", "" + deviceModelName);
    String deviceUSER = android.os.Build.USER;
    Log.v("Name USER", "" + deviceUSER);
    String devicePRODUCT = android.os.Build.PRODUCT;
    Log.v("PRODUCT", "" + devicePRODUCT);
    String deviceHARDWARE = android.os.Build.HARDWARE;
    Log.v("HARDWARE", "" + deviceHARDWARE);
    String deviceBRAND = android.os.Build.BRAND;
    Log.v("BRAND", "" + deviceBRAND);
    String myVersion = android.os.Build.VERSION.RELEASE;
    Log.v("VERSION.RELEASE", "" + myVersion);
    int sdkVersion = android.os.Build.VERSION.SDK_INT;
    Log.v("VERSION.SDK_INT", "" + sdkVersion);

Add in AndroidManifest.xml:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />



또한 Wi-Fi 어댑터의 MAC 주소를 고려할 수도 있습니다. suchly 검색된 :

WifiManager wm = (WifiManager)Ctxt.getSystemService(Context.WIFI_SERVICE);
return wm.getConnectionInfo().getMacAddress();

매니페스트에 android.permission.ACCESS_WIFI_STATE 권한이 필요합니다.

Wi-Fi가 연결되어 있지 않은 경우에도 사용할 수 있다고보고되었습니다. Joe가 위의 대답에서이 장치를 여러 장치에서 시험해 보면 좋을 것입니다.

일부 기기에서는 Wi-Fi가 꺼져있을 때 사용할 수 없습니다.

참고 : 안드로이드 6.x에서 일관된 가짜 mac 주소를 반환합니다 : 02:00:00:00:00:00




More specifically, Settings.Secure.ANDROID_ID . This is a 64-bit quantity that is generated and stored when the device first boots. It is reset when the device is wiped.

ANDROID_ID seems a good choice for a unique device identifier. There are downsides: First, it is not 100% reliable on releases of Android prior to 2.2 (“Froyo”). Also, there has been at least one widely-observed bug in a popular handset from a major manufacturer, where every instance has the same ANDROID_ID.



Related