독특한 안드로이드 장치 ID가 있습니까?


질문

 

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


답변

 

SENTINGS.SECURE # ANDROID_ID 각 사용자 64 비트 HEX 문자열마다 고유 한 Android ID를 반환합니다.

import android.provider.Settings.Secure;

private String android_id = Secure.getString(getContext().getContentResolver(),
                                                        Secure.ANDROID_ID);

또한 고유 한 식별자에 대한 모범 사례를 읽으십시오 : https://developer.android.com/training/articles/user-data.ids



답변

업데이트 : 최근의 Android 버전에서 Android_ID의 많은 문제가 해결 되었으며이 접근 방식이 더 이상 필요하지 않습니다.Anthony의 답변을 살펴보십시오.

전체 공개 : 내 앱은 원래 아래의 접근 방식을 사용했지만 더 이상이 접근 방식을 사용하지 않으며, 이제 EMMBY의 응답 (즉, UUID # randomuuid ()을 생성하고 저장하고 저장합니다).


이 질문에 대한 많은 답변이 있으며, 대부분의 시간은 "어떤 시간"과 불행히도 충분하지 않습니다.

장치의 테스트 (모든 전화기, 적어도 하나는 활성화되지 않은 모든 전화)를 기반으로합니다.

  1. All devices tested returned a value for TelephonyManager.getDeviceId()
  2. All GSM devices (all tested with a SIM) returned a value for TelephonyManager.getSimSerialNumber()
  3. All CDMA devices returned null for getSimSerialNumber() (as expected)
  4. All devices with a Google account added returned a value for ANDROID_ID
  5. All CDMA devices returned the same value (or derivation of the same value) for both ANDROID_ID and TelephonyManager.getDeviceId() -- as long as a Google account has been added during setup.
  6. I did not yet have a chance to test GSM devices with no SIM, a GSM device with no Google account added, or any of the devices in airplane mode.

따라서 장치 자체에 고유 한 것을 원한다면 TM.GetDeviceID ()가 충분해야합니다.분명히 일부 사용자는 다른 사용자보다 더 많은 편집증이므로 이러한 식별자 중 1 개 이상을 해시하는 것이 유용 할 수 있으므로 문자열이 장치에 거의 고유하지만 사용자의 실제 장치를 명시 적으로 식별하지 않습니다.예를 들어, uuid와 결합 된 string.hashcode ()를 사용하여 다음을 수행하십시오.

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 android.content.Context;
import android.telephony.TelephonyManager;
import android.view.View;


답변

#last 업데이트 됨 : 6/2/15.


고유 ID, Google 개발자 블로그 및 Android 문서를 만드는 모든 스택 오버플로 게시물을 읽은 후에는 '의사 ID'가 최상의 옵션이라는 것처럼 느껴집니다.

주요 문제 : 하드웨어 대 소프트웨어

하드웨어

사용자는 하드웨어, Android 태블릿 또는 전화를 변경할 수 있으므로 하드웨어를 기반으로하는 고유 한 ID가 사용자를 추적하는 데 좋은 아이디어가 아닙니다. 하드웨어 추적을 위해 이것은 훌륭한 아이디어입니다

소프트웨어

사용자가 뿌리를 내리면 rom을 삭제 / 변경할 수 있습니다. 플랫폼간에 사용자를 추적 할 수 있습니다 (iOS, Android, Windows 및 Web) 동의를 가진 개별 사용자를 추적하고자하는 것이 가장 좋습니다.


# Android와의 모든 고장

### - API> = 9/10 (Android 기기의 99.5 %)에 대한 고유성 (뿌리 표시 장치 포함) ### - 추가 권한 없음

의사 코드 :

if API >= 9/10: (99.5% of devices)

return unique ID containing serial id (rooted devices may be different)

else

return the unique ID of build information (may overlap data - API < 9)

@stansult 덕분에 모든 옵션을 게시합니다 (이 스택 오버플로 질문에).

## 옵션 목록 - 이유 / 왜 사용하지 않는 이유 :

사용자 이메일 - 소프트웨어 사용자는 이메일을 변경할 수 있습니다 API 5 + <사용 권한 Android : name = "android.permission.get_accounts"/> 또는 API 14 + <사용 권한 Android : name = "android.permission.read_profile"/> <사용 권한 Android : name = "android.permission.read_contacts"/> (Android 기기의 기본 전자 메일 주소를 얻는 방법) 사용자 전화 번호 - 소프트웨어 사용자는 전화 번호를 변경할 수 있습니다 <사용 권한 Android : name = "android.permission.read_phone_state"/> IMEI - 하드웨어 (휴대폰 만 android.permission.read_phone_state가 필요함) 대부분의 사용자는 허가에서 "전화 통화"라는 사실을 싫어합니다. 일부 사용자는 실제로 수행하려는 모든 일이 실제로 원하는 모든 일이 실제로 수행 할 때 개인 정보를 훔치는 것이 좋습니다. 그것은 당신이 데이터를 수집하는 것이 분명합니다. <사용 권한 Android : name = "android.permission.read_phone_state"/> Android ID - 하드웨어 (NULL 일 수 있으며 공장 초기화시 변경할 수 있으며 루팅 된 장치에서 변경할 수 있습니다) 'null'일 수 있으므로 'null'을 확인하고 그 값을 변경할 수 있지만 더 이상 더 이상 고유하지는 않습니다. 팩토리 리셋 장치가있는 사용자가있는 경우 루팅 장치에서 값이 변경되거나 변경되었을 수 있으므로 사용자 설치를 추적하는 경우 항목이 복제됩니다. WLAN MAC 주소 - 하드웨어 (Android.permission.access_wifi_state 필요) 이는 두 번째로 가장 좋은 옵션 일 수 있지만 사용자에게 직접 제공되는 고유 식별자를 수집하고 저장하는 것입니다. 이것은 당신이 데이터를 수집하는 것이 분명합니다. <사용 권한 Android : name = "android.permission.access_wifi_state"/> 블루투스 MAC 주소 - 하드웨어 (블루투스가있는 장치, Android.Permission.Bluetooth가 필요함) 시장에서 대부분의 응용 프로그램은 Bluetooth를 사용하지 않으므로 응용 프로그램이 Bluetooth를 사용하지 않으면 사용자가 의심 스러울 수 있습니다. <사용 권한 Android : 이름 = "android.permission.bluetooth"/> 의사 고유 ID - 소프트웨어 (모든 Android 기기의 경우) 매우 가능합니다. 충돌이 포함될 수 있습니다 - 아래에 게시 된 내 방법을 참조하십시오! 이렇게하면 비공개 인 것을 취소하지 않고도 사용자에게 '거의 독특한'이드를 가질 수 있습니다. 장치 정보에서 자신의 익명의 ID를 만들 수 있습니다.


권한을 사용하지 않고 고유 한 ID를 얻는 '완벽한'방법이 없다는 것을 알고 있습니다.그러나 때로는 장치 설치를 추적 할 필요가 있습니다.고유 한 ID를 만드는 경우 Android API가 추가 사용 권한을 사용하지 않고도 우리에게 제공하는 정보에만 해당하는 '의사 고유 ID'를 만들 수 있습니다.이렇게하면 사용자 존경을 보여주고 좋은 사용자 경험을 제공 할 수 있습니다.

의사 고유 ID를 사용하면 비슷한 장치가 있음을 기반으로 중복이있을 수 있다는 사실에만 실제로 실행됩니다.결합 된 방법을 조정하여 더 독특하게 만들 수 있습니다.그러나 일부 개발자는 장치 설치를 추적해야하며 비슷한 장치를 기반으로 트릭이나 성능을 수행합니다.

## api> = 9 :

Android 기기가 API 9 이상인 경우 'build.serial'필드 때문에 고유하게 보장됩니다.

API <9가있는 사용자의 약 0.5 %의 사용자의 약 0.5 %가 거친 것을 기억하십시오. 이것은 나머지 부분에 집중할 수 있습니다. 이것은 사용자의 99.5 %입니다!

## API <9 :

사용자의 안드로이드 장치가 API 9보다 낮 으면;바라건대, 그들은 공장 재설정을하지 않았으며 'secure.android_id'가 보존되거나 'null'가 아닌가 아닙니다.(http://developer.android.com/about/dashboards/index.html 참조)

## 모두가 실패하면 :

모든 다른 모든 경우 사용자가 API 9보다 낮 으면 장치를 재설정하거나 'secure.android_id'가 'null'를 반환 한 다음 반환 된 ID가 Android 기기 정보를 기반으로합니다....에이것은 충돌이 일어날 수있는 곳입니다.

변경 사항 :

공장 재설정이 변경 될 수 있기 때문에 'android.secure_id'를 제거했습니다. API에서 변경하도록 코드를 편집했습니다 의사를 바꿨다

아래 방법을 살펴보십시오.

/**
 * Return pseudo unique ID
 * @return ID
 */
public static String getUniquePsuedoID() {
    // If all else fails, if the user does have lower than API 9 (lower
    // than Gingerbread), has reset their device or 'Secure.ANDROID_ID'
    // returns 'null', then simply the ID returned will be solely based
    // off their Android device information. This is where the collisions
    // can happen.
    // Thanks http://www.pocketmagic.net/?p=1662!
    // Try not to use DISPLAY, HOST or ID - these items could change.
    // If there are collisions, there will be overlapping data
    String m_szDevIDShort = "35" + (Build.BOARD.length() % 10) + (Build.BRAND.length() % 10) + (Build.CPU_ABI.length() % 10) + (Build.DEVICE.length() % 10) + (Build.MANUFACTURER.length() % 10) + (Build.MODEL.length() % 10) + (Build.PRODUCT.length() % 10);

    // Thanks to @Roman SL!
    // https://stackoverflow.com/a/4789483/950427
    // Only devices with API >= 9 have android.os.Build.SERIAL
    // http://developer.android.com/reference/android/os/Build.html#SERIAL
    // If a user upgrades software or roots their device, there will be a duplicate entry
    String serial = null;
    try {
        serial = android.os.Build.class.getField("SERIAL").get(null).toString();

        // Go ahead and return the serial for api => 9
        return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
    } catch (Exception exception) {
        // String needs to be initialized
        serial = "serial"; // some value
    }

    // Thanks @Joe!
    // https://stackoverflow.com/a/2853253/950427
    // Finally, combine the values we have found by using the UUID class to create a unique identifier
    return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
}

# New (광고 및 Google Play 서비스가있는 앱용) :

Google Play 개발자 콘솔에서 다음을 수행하십시오.

2014 년 8 월 1 일부터 Google Play 개발자 프로그램 정책 모든 새로운 앱 업로드 및 업데이트가 필요합니다. 어떤 광고 목적 으로든 다른 지속적인 식별자를 대신합니다. 더 알아보기

구현:

허가:

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

암호:

import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;
import com.google.android.gms.common.GooglePlayServicesAvailabilityException;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import java.io.IOException;
...

// Do not call this function from the main thread. Otherwise, 
// an IllegalStateException will be thrown.
public void getIdThread() {

  Info adInfo = null;
  try {
    adInfo = AdvertisingIdClient.getAdvertisingIdInfo(mContext);

  } catch (IOException exception) {
    // Unrecoverable error connecting to Google Play services (e.g.,
    // the old version of the service doesn't support getting AdvertisingId).
 
  } catch (GooglePlayServicesAvailabilityException exception) {
    // Encountered a recoverable error connecting to Google Play services. 

  } catch (GooglePlayServicesNotAvailableException exception) {
    // Google Play services is not available entirely.
  }
  final String id = adInfo.getId();
  final boolean isLAT = adInfo.isLimitAdTrackingEnabled();
}

소스 / 문서 :

http://developer.android.com/google/play-services/id.html. http://developer.android.com/reference/com/google/android/gms/ads/identifer/advertisingidclient.html.

##중요한:

그것은 광고 ID가 기존을 완전히 대체하는 것으로 의도된다. 광고 목적으로 다른 식별자의 사용 (예 : Android_ID 사용 Google Play 서비스를 사용할 수있는 경우 설정.사례 Google Play 서비스를 사용할 수없는 경우 GooglePlayServicesNotAvailableException이 던져진다 getAdvertisingInfo ().

## 경고, 사용자가 재설정 할 수 있습니다.

http://en.kioskea.net/faq/34732-Android-Reset-Your-advertiving-ID.

나는 내가 정보를 얻은 모든 링크를 참조하려고 노력했다.누락되고 포함되어야하는 경우에는 의견을 말해주십시오!

Google Player Services 인스트니다

https://developers.google.com/instance-id/



답변

Dave WebB가 언급하면서 Android 개발자 블로그에는이를 다루는 기사가 있습니다.선호되는 해결책은 장치가 아닌 앱 설치를 추적하고 대부분의 사용 사례에서는 잘 작동합니다.블로그 게시물은 그 일을하는 데 필요한 코드를 보여줄 것이고, 확인하는 것이 좋습니다.

그러나 앱 설치 식별자가 아닌 장치 식별자가 아닌 장치 식별자가 필요한 경우 블로그 게시물이 솔루션을 논의하기 위해 계속됩니다.나는 당신이 그렇게 해야하는 경우 몇 가지 항목에 대한 몇 가지 추가 설명을 얻으려면 Google에서 누군가와 이야기했습니다.다음은 앞서 언급 한 블로그 게시물에 언급되지 않은 장치 식별자에 대해 알았던 것입니다.

android_id가 기본 설정된 장치 식별자입니다.Android_ID는 Android 버전에서 완벽하게 신뢰할 수 있습니다 <= 2.1 또는> = 2.3.2.2만이 게시물에 언급 된 문제가 있습니다. 여러 제조업체의 여러 장치는 2.2의 Android_ID 버그의 영향을받습니다. 내가 결정할 수있는 한, 영향을받는 모든 장치는 9774D56D682E549C 인 Android_ID가 동일합니다.또한 에뮬레이터에 의해보고 된 동일한 장치 ID 인 BTW입니다. Google은 OEM이 많은 또는 대부분의 장치에 대한 문제를 패치 한 것으로 믿지만 2011 년 4 월 초반부터 Android_ID가 깨진 장치를 찾는 것은 여전히 쉽습니다.

Google의 권장 사항을 기반으로, 각 장치에 대한 고유 한 UUID를 생성하는 클래스를 구현하며, 적절한 위치에있는 씨앗으로 씨앗을 사용하여, 필요에 따라 씨앗을 뒤로 떨어지고, 그 경우 무작위로 생성 된 고유 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;
    }
}


답변

다음은 사용자에게 고유 한 ID를 얻으려면 올해 Google I / O 프레젠테이션에서 사용 된 Google I / O 프레젠테이션에서 사용 된 코드입니다.

private static String uniqueID = null;
private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";

public synchronized static String id(Context context) {
    if (uniqueID == null) {
        SharedPreferences sharedPrefs = context.getSharedPreferences(
                PREF_UNIQUE_ID, Context.MODE_PRIVATE);
        uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);
        if (uniqueID == null) {
            uniqueID = UUID.randomUUID().toString();
            Editor editor = sharedPrefs.edit();
            editor.putString(PREF_UNIQUE_ID, uniqueID);
            editor.commit();
        }
    }
    return uniqueID;
}

클라우드에 환경 설정을 보낼 백업 전략 으로이 작업을 수행하는 경우 (Retro의 Talk에서도 설명한 경우, 사용자가 묶어서 장치가 닦거나 교체 된 후에도 주위에 끼워지는 ID가 있어야합니다. 나는 이것을 사용할 계획이다.분석에서 앞으로 나아가는 (즉, 나는 아직 그것을하지 않았습니다 :).



답변

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

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

매니페스트에서 Android.Permission.access_wifi_state가 필요합니다.

Wi-Fi가 연결되어 있지 않아도 사용할 수 있도록보고됩니다.위의 대답에서 Joe 가이 하나의 많은 장치에서 시도해보십시오.

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

참고 : Android 6.x에서는 일관된 가짜 MAC 주소를 반환합니다. 02 : 00 : 00 : 00 : 00 : 00

출처:https://stackoverflow.com/questions/2785485/is-there-a-unique-android-device-id