안드로이드 - 고유 한 Android 기기 ID가 있습니까?



android_id (20)

최종 업데이트 : 6/2/15

고유 ID, Google 개발자 블로그 및 Android 설명서를 만드는 방법에 대한 모든 스택 오버플로 게시물을 읽은 후 '의사 ID'가 가능한 최상의 옵션 인 것처럼 느낍니다.

주요 이슈 : 하드웨어 대 소프트웨어

하드웨어

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

소프트웨어

  • 사용자는 뿌리 인 경우 ROM을 지우거나 바꿀 수 있습니다.
  • 플랫폼 (iOS, Android, Windows 및 웹)에서 사용자를 추적 할 수 있습니다.
  • 개별 사용자동의를 얻는 가장 좋은 방법은 단순히 로그인하도록하는 것입니다 (OAuth를 사용하여이 작업을 원활하게 수행하십시오)

Android로 전체 고장

- API> = 9/10 (Android 기기의 99.5 %)에 대한 고유성 보증 (루팅 된 기기 포함)

- 추가 권한 없음

Psuedo code :

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

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

else

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

@stansult에게 (Stack Overflow 질문에서) 모든 옵션 을 게시 해 주셔서 감사합니다.

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

  • 사용자 이메일 - 소프트웨어

    • 사용자가 이메일을 변경할 수 있음 - 매우 드물다.
    • API 5+ <uses-permission android:name="android.permission.GET_ACCOUNTS" /> 또는
    • API 14+ <uses-permission android:name="android.permission.READ_PROFILE" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> ( 안드로이드 장치의 기본 전자 메일 주소를 얻는 방법 )
  • 사용자 전화 번호 - 소프트웨어

    • 사용자가 전화 번호를 변경할 수 있음 - 매우 드물다.
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • IMEI - 하드웨어 (전화 만 필요, android.permission.READ_PHONE_STATE 필요)

    • 대부분의 사용자는 허락에서 "전화 통화"라는 사실을 싫어합니다. 일부 사용자는 나쁜 평점을 주는데, 그 이유는 사용자가 단순히 기기 설치를 추적하기를 원할 때 개인 정보를 훔쳐 간다고 믿기 때문입니다. 데이터를 수집하는 것은 분명합니다.
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • Android ID - 하드웨어 (null 일 수 있음, 초기화시 변경 가능, 루팅 된 기기에서 변경 가능)

    • 'null'이 될 수 있기 때문에 'null'을 확인하고 값을 변경할 수 있지만 더 이상 고유하지 않습니다.
    • 초기화 장치가있는 사용자가있는 경우 루트 설치 장치에서 값이 변경되거나 변경되었을 수 있으므로 사용자 설치를 추적하는 경우 중복 항목이있을 수 있습니다.
  • WLAN MAC 주소 - 하드웨어 ( android.permission.ACCESS_WIFI_STATE 필요)

    • 이것은 두 번째로 좋은 옵션 일 수 있지만 사용자가 직접 제공하는 고유 한 식별자를 수집하고 저장하는 것입니다. 데이터를 수집하는 것은 명백합니다.
    • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
  • 블루투스 MAC 주소 - 하드웨어 (블루투스 장치, android.permission.BLUETOOTH 필요)

    • 시장에 나와있는 대부분의 응용 프로그램은 Bluetooth를 사용하지 않으므로 응용 프로그램에서 Bluetooth를 사용하지 않고 이것을 포함하면 사용자가 의심 스러울 수 있습니다.
    • <uses-permission android:name="android.permission.BLUETOOTH "/>
  • 유사 고유 ID - 소프트웨어 (모든 Android 기기 용)

    • 매우 가능하고 충돌을 포함 할 수 있습니다 - 아래에 게시 된 내 방식을보십시오!
    • 이렇게하면 사적인 내용을 모두 취하지 않고도 사용자가 '거의 고유하지 않은'ID를 가질 수 있습니다. 기기 정보에서 익명의 ID를 만들 수 있습니다.

사용 권한을 사용하지 않고 고유 한 ID를 얻는 '완벽한'방법이 없다는 것을 알고 있습니다. 그러나 때로는 장치 설치를 추적하기 만하면됩니다. 고유 한 ID를 만들 때 안드로이드 API가 여분의 권한을 사용하지 않고 우리에게 제공 한 정보만을 기반으로 '의사 고유 ID'를 생성 할 수 있습니다. 이렇게하면 사용자 존중을 보여줄 수 있고 좋은 사용자 경험을 제공 할 수 있습니다.

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

API> = 9 :

Android 기기가 API 9 이상인 경우 'Build.SERIAL'입력란 때문에 고유 한 것으로 보장됩니다.

API가 9 미만인 사용자의 약 0.5 % 만 기술적으로 누락 시킨 것 입니다. 그래서 나머지 부분에 집중할 수 있습니다 : 이것은 사용자의 99.5 %입니다!

API <9 :

사용자의 Android 기기가 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();
}

신규 (광고 및 Google Play 서비스가있는 앱의 경우) :

Google Play 개발자 콘솔에서

2014 년 8 월 1 일부터 Google Play 개발자 프로그램 정책에 따라 모든 새로운 앱 업로드 및 업데이트를 통해 광고 목적으로 다른 영구 식별자 대신 광고 ID를 사용해야합니다. 더 알아보기

구현 :

허가:

<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/identifier/AdvertisingIdClient.html

중대한:

Google Play 서비스를 사용할 수있을 때 광고 ID가 광고 목적을 위해 다른 식별자 (예 : Settings.Secure의 ANDROID_ID 사용)의 기존 사용을 완전히 대체하기위한 것입니다. Google Play 서비스를 사용할 수없는 경우 getAdvertisingIdInfo ()에 의해 throw되는 GooglePlayServicesNotAvailableException이 표시됩니다.

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

http://en.kioskea.net/faq/34732-android-reset-your-advertising-id

나는 정보를 얻은 모든 링크를 참조하려고 노력했다. 누락되어 포함될 필요가 있으면 의견을 말하십시오!

Google Player 서비스 InstanceID

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

https://rueisnom.com

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


Answer #1

문자열로 안드로이드 OS 장치의 고유 장치 ID를 사용 TelephonyManager하고 ANDROID_ID,에 의해 획득된다 :

String deviceId;
final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
if (mTelephony.getDeviceId() != null) {
    deviceId = mTelephony.getDeviceId();
}
else {
    deviceId = Secure.getString(
                   getApplicationContext().getContentResolver(),
                   Secure.ANDROID_ID);
}

그러나 Google에서 제안하는 방법을 강력히 권장합니다 . 앱 설치 확인을 참조 하십시오 .



Answer #3

또한 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


Answer #4

Settings.Secure#ANDROID_ID각 사용자 64 비트 16 진수 문자열에 대한 고유 한 Android ID를 반환합니다.

import android.provider.Settings.Secure;

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

Answer #5

Google I / O Reto Meier는 대부분의 개발자가 설치 과정에서 사용자를 추적해야하는 요구 사항을 충족 할 수있는 방법에 대한 확실한 답변을 발표했습니다. 안토니 놀란 (Anthony Nolan)은 그의 대답에서 방향을 보여 주었지만, 다른 사람들이 어떻게하는지 쉽게 알 수 있도록 전체 접근법을 써야한다고 생각했습니다. 세부 사항을 파악하는 데는 시간이 걸렸습니다.

이 방법을 사용하면 익명의 안전한 사용자 ID를 얻을 수 있습니다.이 사용자 ID는 다른 기기 (기본 Google 계정 기반) 및 설치 전반에 걸쳐 사용자에게 영구적입니다. 기본 접근법은 임의의 사용자 ID를 생성하고이를 앱의 공유 환경 설정에 저장하는 것입니다. 그런 다음 Google의 백업 에이전트를 사용하여 Google 계정에 링크 된 공유 환경 설정을 클라우드에 저장합니다.

완전한 접근 방식을 시도해 봅시다. 먼저 Android Backup Service를 사용하여 SharedPreferences의 백업을 만들어야합니다. http://developer.android.com/google/backup/signup.html 통해 앱을 등록 http://developer.android.com/google/backup/signup.html .

Google은 매니페스트에 추가해야하는 백업 서비스 키를 제공합니다. 또한 다음과 같이 BackupAgent를 사용하도록 응용 프로그램에 지시해야합니다.

<application android:label="MyApplication"
         android:backupAgent="MyBackupAgent">
    ...
    <meta-data android:name="com.google.android.backup.api_key"
        android:value="your_backup_service_key" />
</application>

그런 다음 백업 에이전트를 생성하고 sharedpreferences에 도우미 에이전트를 사용하도록 지시해야합니다.

public class MyBackupAgent extends BackupAgentHelper {
    // The name of the SharedPreferences file
    static final String PREFS = "user_preferences";

    // A key to uniquely identify the set of backup data
    static final String PREFS_BACKUP_KEY = "prefs";

    // Allocate a helper and add it to the backup agent
    @Override
    public void onCreate() {
        SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this,          PREFS);
        addHelper(PREFS_BACKUP_KEY, helper);
    }
}

백업을 완료하려면 주 활동에서 BackupManager의 인스턴스를 만들어야합니다.

BackupManager backupManager = new BackupManager(context);

마지막으로 아직 존재하지 않는 사용자 ID를 작성하여 SharedPreferences에 저장하십시오.

  public static String getUserID(Context context) {
            private static String uniqueID = null;
        private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";
    if (uniqueID == null) {
        SharedPreferences sharedPrefs = context.getSharedPreferences(
                MyBackupAgent.PREFS, 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();

            //backup the changes
            BackupManager mBackupManager = new BackupManager(context);
            mBackupManager.dataChanged();
        }
    }

    return uniqueID;
}

이 User_ID는 사용자가 장치를 이동하는 경우에도 설치 전반에서 영구적으로 유지됩니다.

이 방법에 대한 자세한 정보는 talk 참조하십시오 .

백업 에이전트를 구현하는 방법에 대한 자세한 내용은 데이터 백업을 참조하십시오 . 백업이 즉시 발생하지 않으므로 백업을 강제해야한다는 테스트를 위해 특히 하단의 섹션을 사용하는 것이 좋습니다.


Answer #6

Google 인스턴스 ID

I / O 2015에서 출시되었습니다. Android에서 Play 서비스가 필요합니다. 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

Google은이 ID를 사용하여 Android, Chrome 및 iOS의 설치를 식별합니다.

그것은 장치가 아닌 설치를 식별하지만, 다시 한번 ANDROID_ID (허용 된 응답)는 더 이상 장치를 식별하지 않습니다. ARC 런타임 에서이 새로운 인스턴스 ID처럼 모든 설치 ( 새로운 세부 사항 )에 대해 새로운 ANDROID_ID가 생성됩니다 . 또한, 나는 장치 (장치가 아닌)를 확인하는 것이 우리 중 대부분이 실제로 찾고있는 것이라고 생각합니다.

인스턴스 ID의 장점

구글이이를 목적으로 사용하고 (설치를 식별하는), 플랫폼을 넘어서고, 다른 많은 목적으로 사용될 수 있다고 생각합니다. (위 링크 참조)

GCM을 사용하는 경우 GCM 토큰 (이전 GCM 등록 ID를 대체)을 얻기 위해 필요하기 때문에 결국이 인스턴스 ID를 사용해야합니다.

단점 / 문제점

현재 구현 (GPS 7.5)에서는 앱이 요청할 때 인스턴스 ID가 서버에서 검색됩니다. 위의 호출이 차단 호출 인 것을 의미합니다. 비 과학적 테스트에서 장치가 온라인 상태 인 경우 1-3 초, 오프라인 상태 인 경우 0.5 - 1.0 초가 걸릴 것입니다 (아마도 이것은 포기하기 전에 기다리는 시간 일 것입니다). 임의의 ID). 북미 지역에서는 Android 5.1.1 및 GPS 7.5가 설치된 Nexus 5에서 테스트되었습니다.

자신이 의도 한 목적으로 ID를 사용하면 - 예. 앱 인증, 앱 식별, GCM -이 1-3 초가 귀찮은 일이라고 생각합니다 (물론 앱에 따라 다름).


Answer #7

TelephonyManger.getDeviceId () 고유 한 장치 ID를 반환합니다 ( 예 : GSM 용 IMEI 및 CDMA 전화 용 MEID 또는 ESN).

final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);            
String myAndroidDeviceId = mTelephony.getDeviceId(); 

그러나 나는 다음을 사용하는 것이 좋습니다.

Settings.Secure.ANDROID_ID 는 Android ID를 고유 한 64 비트 16 진수 문자열로 반환합니다.

    String   myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 

경우에 따라 TelephonyManger.getDeviceId () 는 null을 반환하므로 고유 한 ID를 보장하기 위해이 메서드를 사용합니다.

public String getUniqueID(){    
    String myAndroidDeviceId = "";
    TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    if (mTelephony.getDeviceId() != null){
        myAndroidDeviceId = mTelephony.getDeviceId(); 
    }else{
         myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 
    }
    return myAndroidDeviceId;
}

Answer #8

고유 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;
}

Answer #9

나는 이것이 유일한 ID를위한 해골을 만드는 불의 확실한 방법이라고 생각한다. .. 그것을 조사해라.

모든 Android 기기에서 작동하는 가짜 고유 ID 일부 기기에는 휴대 전화 (예 : 태블릿)가 없거나 어떤 이유로 든 READ_PHONE_STATE 권한을 포함하고 싶지 않습니다. ROM 버전, 제조업체 이름, CPU 유형 및 기타 하드웨어 세부 정보와 같은 세부 정보는 계속 읽을 수 있습니다.이 키는 직렬 키 확인 또는 다른 일반적인 용도로 ID를 사용하려는 경우에 적합합니다. 이 방법으로 계산 된 ID는 고유하지 않습니다. 동일한 하드웨어 및 ROM 이미지를 기반으로 동일한 ID로 두 개의 장치를 찾을 수는 있지만 실제 응용 프로그램의 변경 사항은 무시할 수 있습니다. 이를 위해 Build 클래스를 사용할 수 있습니다.

String m_szDevIDShort = "35" + //we make this look like a valid IMEI
            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 ; //13 digits

Build 멤버의 대부분은 문자열입니다. 여기에서 우리가하는 일은 길이를 가져 와서 모듈로 모듈로 변환하는 것입니다. 우리는 13 자리 숫자를 가지고 있으며 IMEI (15 자리)와 동일한 크기의 ID를 갖기 위해 두 개 더 앞에 추가합니다 (35). 여기에는 다른 가능성이 있습니다.이 문자열을 살펴보십시오. 같은 것을 반환합니다 355715565309247. 특별한 허가가 필요하지 않으므로이 방법이 매우 편리합니다.

(추가 정보 : 위에 제공된 기술은 here 의 기사에서 복사했습니다 .)


Answer #10

아래 코드를 사용하여 Android OS 장치의 고유 한 장치 ID를 문자열로 가져올 수 있습니다.

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

Answer #11

아래 클래스 파일에 코드 추가 :

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);

AndroidManifest.xml에 추가 :

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

Answer #12

특정 Android 기기의 하드웨어 인식을 위해 MAC 주소를 확인할 수 있습니다.

당신은 그렇게 할 수 있습니다.

AndroidManifest.xml의

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

이제 코드에서 :

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

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

모든 안드로이드 장치에서 적어도 "wlan0"인터페이스 마녀는 WI-FI 칩입니다. 이 코드는 WI-FI가 켜져 있지 않은 경우에도 작동합니다.

추신 : 그들은 MACS를 포함하는 목록에서 얻을 것이다 다른 인터페이스의 무리입니다 그러나 이것은 전화 사이에 변경할 수 있습니다.


Answer #13

Serial 필드는 추가 된 BuildAPI 레벨 9 (- 진저 브레드 안드로이드 2.3)에서 클래스입니다. 설명서에 하드웨어 일련 번호가 표시되어 있습니다. 따라서 장치에 존재하는 경우에는 고유해야합니다.

API 레벨> = 9 인 모든 기기에서 실제로 지원되는지 (null이 아닌지) 알 수 없습니다.


Answer #14

Google에는 이제 광고 ID가 있습니다.
이것도 사용할 수 있지만 다음 사항에주의하십시오.

광고 ID는 사용자 고유의 재설정 가능 ID입니다.

사용자가 Google Play 앱 내에서 식별자를 재설정하거나 관심 기반 광고를 선택 해제 할 수 있습니다.

이 이드가 바뀌지 만, 곧 이드의 목적에 따라 선택의 여지가없는 것 같습니다 .

http://developer.android.com/google/play-services/id.html

여기에 복사 - 붙여 넣기 코드

HTH


Answer #15

내 두 센트 -주의 안드로이드 개발자의 블로그 에서 논의 된 설치되지 않은 장치 ID (잘못된) 고유 ID 입니다.

SharedPreferences가 여러 프로세스에서 동기화되지 않으므로 @emmby가 제공 하는 solution 은 응용 프로그램 ID에서 제외됩니다 ( here 및 here 참조 ). 그래서 나는이 모든 것을 피했다.

대신 열거 형에 (장치) ID를 가져 오는 다양한 전략을 캡슐화했습니다. 열거 형 상수의 순서를 변경하면 ID를 가져 오는 다양한 방법의 우선 순위가 영향을받습니다. 첫 번째 null이 아닌 ID가 반환되거나 예외가 throw됩니다 (null을 의미하지 않는 Java 사용법에 따라). 그래서 예를 들어 TELEPHONY가 먼저 있습니다.하지만 좋은 기본 선택은 ANDROID_ID 베타입니다.

import android.Manifest.permission;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.wifi.WifiManager;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;
import android.util.Log;

// TODO : hash
public final class DeviceIdentifier {

    private DeviceIdentifier() {}

    /** @see http://code.google.com/p/android/issues/detail?id=10603 */
    private static final String ANDROID_ID_BUG_MSG = "The device suffers from "
        + "the Android ID bug - its ID is the emulator ID : "
        + IDs.BUGGY_ANDROID_ID;
    private static volatile String uuid; // volatile needed - see EJ item 71
    // need lazy initialization to get a context

    /**
     * Returns a unique identifier for this device. The first (in the order the
     * enums constants as defined in the IDs enum) non null identifier is
     * returned or a DeviceIDException is thrown. A DeviceIDException is also
     * thrown if ignoreBuggyAndroidID is false and the device has the Android ID
     * bug
     *
     * @param ctx
     *            an Android constant (to retrieve system services)
     * @param ignoreBuggyAndroidID
     *            if false, on a device with the android ID bug, the buggy
     *            android ID is not returned instead a DeviceIDException is
     *            thrown
     * @return a *device* ID - null is never returned, instead a
     *         DeviceIDException is thrown
     * @throws DeviceIDException
     *             if none of the enum methods manages to return a device ID
     */
    public static String getDeviceIdentifier(Context ctx,
            boolean ignoreBuggyAndroidID) throws DeviceIDException {
        String result = uuid;
        if (result == null) {
            synchronized (DeviceIdentifier.class) {
                result = uuid;
                if (result == null) {
                    for (IDs id : IDs.values()) {
                        try {
                            result = uuid = id.getId(ctx);
                        } catch (DeviceIDNotUniqueException e) {
                            if (!ignoreBuggyAndroidID)
                                throw new DeviceIDException(e);
                        }
                        if (result != null) return result;
                    }
                    throw new DeviceIDException();
                }
            }
        }
        return result;
    }

    private static enum IDs {
        TELEPHONY_ID {

            @Override
            String getId(Context ctx) {
                // TODO : add a SIM based mechanism ? tm.getSimSerialNumber();
                final TelephonyManager tm = (TelephonyManager) ctx
                        .getSystemService(Context.TELEPHONY_SERVICE);
                if (tm == null) {
                    w("Telephony Manager not available");
                    return null;
                }
                assertPermission(ctx, permission.READ_PHONE_STATE);
                return tm.getDeviceId();
            }
        },
        ANDROID_ID {

            @Override
            String getId(Context ctx) throws DeviceIDException {
                // no permission needed !
                final String andoidId = Secure.getString(
                    ctx.getContentResolver(),
                    android.provider.Settings.Secure.ANDROID_ID);
                if (BUGGY_ANDROID_ID.equals(andoidId)) {
                    e(ANDROID_ID_BUG_MSG);
                    throw new DeviceIDNotUniqueException();
                }
                return andoidId;
            }
        },
        WIFI_MAC {

            @Override
            String getId(Context ctx) {
                WifiManager wm = (WifiManager) ctx
                        .getSystemService(Context.WIFI_SERVICE);
                if (wm == null) {
                    w("Wifi Manager not available");
                    return null;
                }
                assertPermission(ctx, permission.ACCESS_WIFI_STATE); // I guess
                // getMacAddress() has no java doc !!!
                return wm.getConnectionInfo().getMacAddress();
            }
        },
        BLUETOOTH_MAC {

            @Override
            String getId(Context ctx) {
                BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter();
                if (ba == null) {
                    w("Bluetooth Adapter not available");
                    return null;
                }
                assertPermission(ctx, permission.BLUETOOTH);
                return ba.getAddress();
            }
        }
        // TODO PSEUDO_ID
        // http://www.pocketmagic.net/2011/02/android-unique-device-id/
        ;

        static final String BUGGY_ANDROID_ID = "9774d56d682e549c";
        private final static String TAG = IDs.class.getSimpleName();

        abstract String getId(Context ctx) throws DeviceIDException;

        private static void w(String msg) {
            Log.w(TAG, msg);
        }

        private static void e(String msg) {
            Log.e(TAG, msg);
        }
    }

    private static void assertPermission(Context ctx, String perm) {
        final int checkPermission = ctx.getPackageManager().checkPermission(
            perm, ctx.getPackageName());
        if (checkPermission != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("Permission " + perm + " is required");
        }
    }

    // =========================================================================
    // Exceptions
    // =========================================================================
    public static class DeviceIDException extends Exception {

        private static final long serialVersionUID = -8083699995384519417L;
        private static final String NO_ANDROID_ID = "Could not retrieve a "
            + "device ID";

        public DeviceIDException(Throwable throwable) {
            super(NO_ANDROID_ID, throwable);
        }

        public DeviceIDException(String detailMessage) {
            super(detailMessage);
        }

        public DeviceIDException() {
            super(NO_ANDROID_ID);
        }
    }

    public static final class DeviceIDNotUniqueException extends
            DeviceIDException {

        private static final long serialVersionUID = -8940090896069484955L;

        public DeviceIDNotUniqueException() {
            super(ANDROID_ID_BUG_MSG);
        }
    }
}

Answer #16

다음 코드를 IMEI사용하여 Secure를 사용하거나 Secure를 사용합니다. ANDROID_ID휴대 전화 기능이없는 기기의 경우

String identifier = null;
TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE));
if (tm != null)
      identifier = tm.getDeviceId();
if (identifier == null || identifier .length() == 0)
      identifier = Secure.getString(activity.getContentResolver(),Secure.ANDROID_ID);

Answer #17

더 구체적으로, Settings.Secure.ANDROID_ID. 이것은 장치가 처음 부팅 할 때 생성되어 저장되는 64 비트 수량입니다. 장치를 지울 때 재설정됩니다.

ANDROID_ID고유 한 장치 식별자에 대한 좋은 선택 인 것 같습니다. 단점은 다음과 같습니다. 첫째, 2.2 이전의 Android 릴리스에서 100 % 신뢰할 수 없습니다. (“Froyo”).또한 모든 인스턴스의 ANDROID_ID가 동일한 주요 제조업체의 널리 사용되는 단말기에 적어도 하나의 널리 관찰 된 버그가있었습니다.


Answer #18

여기에 30 개 이상의 답변이 있으며 일부는 동일하고 일부는 고유합니다. 이 답변은 몇 가지 답변을 기반으로합니다. 그들 중 하나는 @ Lenn Dolling의 대답입니다.

3 개의 ID를 결합하고 32 자리 16 진수 문자열을 만듭니다. 그것은 저를 위해 아주 잘 작동했습니다.

3 ID :
Pseudo-ID - 물리적 장치 사양에 따라 생성됩니다.
ANDROID_ID - Settings.Secure.ANDROID_ID
Bluetooth 주소 - Bluetooth 어댑터 주소

다음과 같이 반환 할 것입니다 : 551F27C060712A72730B0A0F734064B1

참고 : longId문자열에 ID를 더 추가 할 수 있습니다 . 예 : 일련 번호. 와이파이 어댑터 주소. IMEI. 이렇게하면 기기별로 더욱 독특 해집니다.

@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 "";
}

Answer #19

응용 프로그램이 설치된 각 Android 장치에 대한 고유 식별자를 얻는 방법에 대한 자세한 내용은 공식 Android 개발자 블로그 게시물 android-developers.blogspot.com/2011/03/… 참조하십시오 .

가장 좋은 방법은 설치시 자신을 생성하고 응용 프로그램을 다시 시작할 때 읽는 것입니다.

나는 개인적으로 이것을 받아 들일 수는 있지만 이상적이지는 않다. Android에서 제공하는 식별자는 대부분 휴대 전화의 무선 상태 (Wi-Fi 켜기 / 끄기, 휴대 전화 켜기 / 끄기, 블루투스 켜기 / 끄기)에 의존하므로 모든 경우에 작동합니다. 다른 것들은 Settings.Secure.ANDROID_ID제조업체가 구현해야하며 독특 할 수 있습니다.

다음은 응용 프로그램이 로컬로 저장하는 다른 데이터와 함께 저장 될 설치 파일에 데이터를 쓰는 예제입니다 .

public class Installation {
    private static String sID = null;
    private static final String INSTALLATION = "INSTALLATION";

    public synchronized static String id(Context context) {
        if (sID == null) {
            File installation = new File(context.getFilesDir(), INSTALLATION);
            try {
                if (!installation.exists())
                    writeInstallationFile(installation);
                sID = readInstallationFile(installation);
            } 
            catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return sID;
    }

    private static String readInstallationFile(File installation) throws IOException {
        RandomAccessFile f = new RandomAccessFile(installation, "r");
        byte[] bytes = new byte[(int) f.length()];
        f.readFully(bytes);
        f.close();
        return new String(bytes);
    }

    private static void writeInstallationFile(File installation) throws IOException {
        FileOutputStream out = new FileOutputStream(installation);
        String id = UUID.randomUUID().toString();
        out.write(id.getBytes());
        out.close();
    }
}




uniqueidentifier