상세 컨텐츠

본문 제목

안드로이드 개발 유니크 아이디, 디바이스아이디 시리얼 넘버 관련 Is there a unique Android device ID?

스마트기기개발관련/안드로이드 개발

by AlrepondTech 2020. 9. 23. 02:43

본문

반응형

 

 

 

=======================

=======================

=======================

 

 

 

 

 

 

앱 인스톨시 사용자 디바이스의 Behaviour를 추적하기 위해서 디바이스 아아디를 생성하려고 합니다.

여러 방법들이 있을 꺼 같은데, 현재 보통 사용중인 Device Unique Key를 생성하는 방법을 코드로 가이드 부탁드립니다.

방법1

import android.provider.Settings.Secure;
private String android_id = Secure.getString(getContext().getContentResolver(),
                                                        Secure.ANDROID_ID); 

팩토리 리셋하면 번호가 바뀌는 등의 문제가 있었으나 안드로이드 최신버전으로 올수록 문제가 해결되서 위와 같이 하는걸 추천한다고 하네요.

방법2 Secure.ANDROID_ID를 쓰면 최신폰에서는 잘 동작하는데 안드로이드 버전이 낮은 폰에서 문제가 생길 수 있어서 오래된 버전도 지원해야 하는 경우 다음 방법을 추천한다고 하네요.

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

    final String tmDevice, tmSerial, androidId;
    tmDevice = "" + tm.getDeviceId(); //null 이 나올수도 있습니다. 
    tmSerial = "" + tm.getSimSerialNumber(); // uniq 를 보장하지 않아요. 
    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();

위와 같은 코드가 동작하려면 다음과 같은 퍼미션을 manifest파일에 추가해 주어야 합니다.

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

안드로이드 하드웨어에서 제공하는 값만으로는 고유한 값을 보장할 수 없기때문에 위처럼 만든후 어딘가에 저장해서 읽어오는 방식을 권합니다.

 

 

=======================

=======================

=======================

 

 

 

 

출처: http://zolasse.blogspot.kr/2012/05/blog-post.html

단말기 고유값 관련 참고사항

imei, imsi는 wifi 전용 기기에서는 null이 넘어온다.

mac address는 wifi를 끄고 재부팅하면 안 나온다.

android_id는 기기를 초기화하면 값이 바뀐다.




1. ANDROID_ID

android ID는 디바이스가 공장 초기화후 최초 부팅시에 생성이 된다. 또한 초기화 전까지는

삭제 되지 않고 저장되어 있어서 디바이스 식별에 유용한 값으로 보인다. 다만, 어플 사용자가 

디바이스를 초기화 할 경우 값이 변경되는 점과 안드로이드 2.2(프로요)이전 버전에서 이 값은

믿을만 한 값이 아니라고 하니 사용시 유의해야 할것 같다. 

String androID = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
//String 객체를 생성하여 다음과 같이 ANDROID_ID를 받아와 저장시킨다.



2. SERIAL Number 

SERIAL Number 는 android.os.Build.SERIAL 로 부터 값을 받아 올수 있다.

제약 사항이 있다면 위 방법은 안드로이드 2.3(진저브레드)부터 사용이 가능하다고 하며,

전화기능이 없는 디바이스의 경우 유일한 Constant 값을 반환하지만, 전화기능이 있는

디바이스의 경우 모든 디바이스가 해당되지는 않는다고 한다.
(이 방법의 경우 안드로이드 2.2에서 테스팅해 본 결과 런타임 에러가 난다.)

Build bd = new Build();
//Build객체를 생성한다.
final String serialNum = bd.SERIAL;

생성된 Build 객체를 이용하여 SERIAL값을 얻어와 String 객체에 저장한다.



3. Mac Address

Mac Address 는 대학교 네트워크 수업 시간에 지겹도록 들은 단어다.

Mac Address 도  각 디바이스를 구분 할 수 있는 값이지만, 모든 디바이스가

Mac Address를 가지고 있지 않으며 디바이스마다 디바이스가 꺼져 있는 경우 값을 

얻어오지 못한다는 문제점이 있다.

 

 

 

=======================

=======================

=======================

 

 

 

 

출처: http://blog.daum.net/han24_2/3041614

# DeviceID : 유니크한 DeviceID를 가져오지만 전화기능이 없는 장치 ( 갤럭시 탭같은 탭장치나, 미디어플레이어용 장치등 )에서는 값을 받을수 없다.  ((TelephonyManager) activity.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();

# Mac Address (Wifi or Bluetooth ): Wife Mac Address 또는 Bluetooth 장치id 로 장치가 꺼져 있거나 등의 문제로 가져오지 못하는 경우가 있다.

 

Wifi Mac Address를 사용 예.

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

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> 필요

ANDROID 2.2하에서 테스트 해보면 WIFI + 3G를 완전히 끈 상태에서 스마트폰을 다시 부팅시 장비에 따라 조금 상태가 다른데

LG 옵티머스원 (제폰임 ㅠㅜ)의 경우에는 MacAddr을 가져오지 못합니다. 재부팅시 wifi를 키고 한번은 Connect가 된 이후에야

MacAddress를 가져오는 반면에 다른 KT 3G 기능 없는 탭 장비는 동일한 상황에서도 MacAddress를 가져옵니다.

갤럭시 탭은 지금 잠시 딴데 가 있는 관계로 테스트를 못해봤는데 대충 이런 현상이 있다는것 참고!


 

# Serial :  Android 2.3 이후로 가능 (android.Os.Build.Serial) 하다고 해서 테스트 불가!

 

# ANDROID_ID : 2.2에서 이상작동? 설명을 보니 2.2 제외한 버젼에서는 잘 된다는것 같긴한데,, 값이 변경되는 경우가 있는듯함.

 

# UUID : 프로그램 재 설치시 값이 달라진다.

1) 구현소스 http://android-developers.blogspot.com/2011/03/identifying-app-installations.html

2)

# ???? http://stackoverflow.com/questions/5088474/how-can-i-get-the-uuid-of-my-android-phone-in-an-application )

프로그램 소스상으로 재 실행시 값이 변경이 안되길래 괜찮을줄 알았더니 주석 보니깐 재설치시 값이 변경된다고 합니다. 이것도 안되겠네

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 static UUID uuid; 
    public static String getDeviceUuid(Context context) {
        UUID uuid = null;
        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();
                    }
                }
            }
        }

        return uuid.toString();
    }
    /** 
     * * 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. 
     * */
}

 

#. Pseudo-Unique ID  (http://www.pocketmagic.net/?p=1662)

이것은 확률적으로 같은 하드웨어와 같은 ROM IMAGE를 쓰지 않으면 동일 아이디가 발생 하지 않을 꺼라 하는데

쫌 찜찜하긴 하네요 ㅎ

return "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

PS. 결국 종합적으로 따져본 결과 저는 DEVICEID + PHONE NUMBER + MACADDRESS을 OR로 사용하기로 했습니다

 

 

 

=======================

=======================

=======================

 

 

 

 

 

출처: http://www.androidpub.com/2229976

장치마다 고유한 번호값을 얻어낼 수 있나요?

coste

http://www.androidpub.com/2229976

2012.07.12 15:28:56

지금 개발중인 프로젝트에서 번호값을 이용해서 사용자를 식별하는 방식으로 진행하려 합니다.

전화번호를 얻을 수 있을 것 같긴한데,, 테블릿의 경우도 있을 수 있으므로 다른 게 필요할거 같습니다.

도와주세요!~

엮인글 주소 : http://www.androidpub.com/index.php?document_srl=2229976&act=trackback&key=0be

 

2012.07.12 15:44:26

dingpong

고유값이란게 안드로이드에는 없습니다.

그러니까 그 값이 매우 중요한 값이라면 다른 방법을 생각하셔야 할꺼에요.

2012.07.12 16:48:26

리카엘

텔레폰매니저?라는 클래스에 디바이스 id 읽어 올수 있습니다 각 기기마다 적힌 고유번호 인걸로알고 다중 램점채팅도 이것을 이용하는걸로 알고 있습니다

2012.07.12 16:58:52

dingpong

그건 정확한 정보가 아닐겁니다.;;

개통된 폰에서는 IMEI 를 얻어올 수는 있지만 안된 폰에서는 대책없습니다;

그리고 심 바꿔끼면 또 달라지니까요.

 

2012.07.12 17:21:35

Gooss

맥 어드레스는 어떤가요?

 

2012.07.12 17:22:53

dingpong

제가 알기로 wifi 가 잡힐때만 얻을 수 있다고 알고 있습니다.

그리고 이조차 안되는 기기도 있구요.-ㅁ-;

 

2012.07.12 17:42:40

박카쓰

흠... 날짜와 시간, 그리고 랜덤한 숫자를 조합하면 되지 않을까요? 'ㅅ'

 

2012.07.12 19:12:17

리카엘

심 바꿔봐도 디바이수 아이디는 동일한거 확인했어 말하는것이라

 

2012.07.12 22:24:55

즐거운인생

deviceId 쓰는 방식이 아니라면, 다음을 참고해보세요.

 

사용예)

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

 

ANDROID_ID

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.

 

2012.07.12 23:19:37

슈퍼클래스

이것 또한 펌웨어 업그레이드 하면 바뀌지 않나요?

 

2012.07.13 13:40:28

즐거운인생

네 맞습니다. 위에 적혀 있듯이 완벽한 솔루션이 될 수는 없습니다.

 

2012.07.12 23:51:52

dingpong

android unique id 관련해서 구글 찾아보면 이미 자료가 많으니까요. 

 

2012.07.13 14:20:08

bluemist

IMEI 값은 폰마다 고유한 값이지만, 이 값을 별도로 저장하려면 우리나라 정보통신법상 사용자에게 고지를 해야합니다.

또한 갤럭시 플레이어 같이 3G, LTE 통신을 하지 않는 단말들도 있기 때문에, IMEI 값이 모든 안드로이드 기기를 커버할 수 있는 것은 아닙니다.

그래서, 보통 WIFI MAC 주소를 고유한 값으로 체크하는 경우가 일반적입니다.

 

 

 

=======================

=======================

=======================

 

 

 

반응형

 

 

728x90

 

 

 

 

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

Is there a unique Android device ID?

do Android devices have a unique id, and if so, what is a simple way to access it via Java?

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Settings.Secure#ANDROID_ID returns the Android ID as an unique 64-bit hex string

import android.provider.Settings.Secure;

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

 

>It's known to be null sometimes, it's documented as "can change upon factory reset". Use at your own risk, and it can be easily changed on a rooted phone.

>I think we need to be careful about using ANDROID_ID in hash in first answer about because it may not be set when app is first run, may be set later, or may even change in theory, hence unique ID may change

>ANDROID_ID no longer uniquely identifies a device (as of 4.2): stackoverflow.com/a/13465373/150016

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

there are many answers to this question, most of which will only work "some" of the time, and unfortunately that's not good enough.

Based on my tests of devices (all phones, at least one of which is not activated):

  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_IDand 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.

So if you want something unique to the device itself, TM.getDeviceId() should be sufficient. Obviously some users are more paranoid than others, so it might be useful to hash 1 or more of these identifiers, so that the string is still virtually unique to the device, but does not explicitly identify the user's actual device. For example, using String.hashCode(), combined with a 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();

might result in something like: 00000000-54b3-e7c7-0000-000046bffd97

It works well enough for me.

As Richard mentions below, don't forget that you need permission to read the TelephonyManagerproperties, so add this to your manifest:

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

>Telephony-based ID won't be there on tablet devices, neh?

>Hence why I said most won't work all the time :) I've yet to see any answer to this question that is reliable for all devices, all device types, and all hardware configurations. That's why this question is here to begin with. It's pretty clear that there is no end-all-be-all solution to this. Individual device manufacturers may have device serial numbers, but those are not exposed for us to use, and it is not a requirement. Thus we're left with what is available to us.

>The code sample works great. Remember to add <uses-permission android:name="android.permission.READ_PHONE_STATE" /> to the manifest file. If storing in a database, the returned string is 36 characters long

>I believe what you're referring to is the Android Developer Blog that emmby already linked to, which explains what you are trying to say, so perhaps you should have simply upvoted his comment instead. Either way, as emmby mentions in his answer, there are still problems even with the blog info. The question asks for a unique DEVICE identifier (not installation identifier), so I disagree with your statement. The blog is making an assumption that what you want is not necessarily to track the device, whereas the question asks for just that. I agree with the blog otherwise. 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

as Dave Webb mentions, the Android Developer Blog has an article that covers this. Their preferred solution is to track app installs rather than devices, and that will work well for most use cases. The blog post will show you the necessary code to make that work, and I recommend you check it out.

However, the blog post goes on to discuss solutions if you need a device identifier rather than an app installation identifier. I spoke with someone at Google to get some additional clarification on a few items in the event that you need to do so. Here's what I discovered about device identifiers that's NOT mentioned in the aforementioned blog post:

  • ANDROID_ID is the preferred device identifier. ANDROID_ID is perfectly reliable on versions of Android <=2.1 or >=2.3. Only 2.2 has the problems mentioned in the post.
  • Several devices by several manufacturers are affected by the ANDROID_ID bug in 2.2.
  • As far as I've been able to determine, all affected devices have the same ANDROID_ID, which is9774d56d682e549c. Which is also the same device id reported by the emulator, btw.
  • Google believes that OEMs have patched the issue for many or most of their devices, but I was able to verify that as of the beginning of April 2011, at least, it's still quite easy to find devices that have the broken ANDROID_ID.

Based on Google's recommendations, I implemented a class that will generate a unique UUID for each device, using ANDROID_ID as the seed where appropriate, falling back on TelephonyManager.getDeviceId() as necessary, and if that fails, resorting to a randomly generated unique UUID that is persisted across app restarts (but not app re-installations).

Note that for devices that have to fallback on the device ID, the unique ID WILL persist across factory resets. This is something to be aware of. If you need to ensure that a factory reset will reset your unique ID, you may want to consider falling back directly to the random UUID instead of the device ID.

Again, this code is for a device ID, not an app installation ID. For most situations, an app installation ID is probably what you're looking for. But if you do need a device ID, then the following code will probably work for you.

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

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Here is the code that Reto Meier used in the Google I/O presentation this year to get a unique id for the user:

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

If you couple this with a backup strategy to send preferences to the cloud (also described in Reto's talk, you should have an id that ties to a user and sticks around after the device has been wiped, or even replaced. I plan to use this in analytics going forward (in other words, I have not done that bit yet :).

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Last Updated: 7/27/14

After reading every Stack Overflow post about creating a unique ID, the Google developer blog and Android documentation, I feel as if the 'Pseudo ID' is the best possible option.

Overall breakdown

- Guarantee uniqueness (except rooted devices) for API => 9 (98.4% of Android devices)

- No extra permissions

Psuedo code:

if API => 9: (98.4% of devices) return unique ID containing serial id (rooted phones may be different) else return unique ID of build information (may overlap data - API < 9)

Thanks to @stansult for posting all of our options (in this Stack Overflow question).

List of options - reasons why not to use them:

  • IMEI (only for Android devices with phone use; needs android.permission.READ_PHONE_STATE)
    • Most users hate the fact that it says "Phone Calls" in the permission. Some users give bad ratings, because they believe you are simply stealing their personal information, when all you really want to do is track device installs. It is obvious that you are collecting data.
    • An extra permission
  • Android ID (can be null, can change upon factory reset, can be altered on a rooted phone)
    • Since it can be 'null', we can check for 'null' and change its value, but this means it will no longer be unique.
    • If you have a user with a factory reset phone, the value may have changed or altered on the rooted phone so there may be duplicates entries if you are tracking user installs.
  • WLAN MAC Address string (needs android.permission.ACCESS_WIFI_STATE)
    • This could be the second best option, but you are still collecting and storing a unique identifier that comes directly from a user. This is obvious that you are collecting data.
    • Once again, this is another permission
  • Bluetooth MAC Address string (devices with Bluetooth, needs android.permission.BLUETOOTH)
    • Most applications on the market do not use Bluetooth, and so if your application doesn't use Bluetooth and you are including this, the user could become suspicious.
    • Once again, this is another permission
  • Pseudo-Unique ID (for all Android devices)
    • Very possible, may contain collisions - See my method posted below!
    • This allows you to have an 'almost unique' ID from the user without taking anything that is private. You can create you own unanimous ID from device information.

I know there isn't any 'perfect' way of getting a unique ID without using permissions; however, sometimes we only really need to do is track the device installation. When it comes to creating a unique ID, we can create a 'pseudo unique id' based solely off of information that the Android API gives us without using extra permissions. This way, we can show the user respect and try to offer a good user experience as well.

With a pseudo-unique id, you really only run into the fact that there may be duplicates based on the fact that there are similar devices. You can tweak the combined method to make it more unique; however, some developers need to track device installs and this will do the trick or performance based on similar devices.

API => 9:

If their Android device is API 9 or over, this is guaranteed to be unique because of the 'Build.SERIAL' field.

REMEMBER, you are technically only missing out on around 1.6% of users who have API < 9. So you can focus on the rest: This is 98.4% of the users!

API < 9:

If the user's Android device is lower than API 9; hopefully, they have not done a factory reset and their 'Secure.ANDROID_ID' will be preserved or not 'null'. (seehttp://developer.android.com/about/dashboards/index.html)

If all else fails:

If all else fails, if the user does have lower than API 9 (lower than Gingerbread), has reset their phone 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.

Changes:

  • Removed 'Android.SECURE_ID' because of factory resets could cause the value to change
  • Edited the code to change on API
  • Changed the Pseudo

Please take a look at the method below:

/**
 * 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 phone 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!
    // http://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 phone, 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 e)
    {
        // String needs to be initialized
        serial = "serial"; // some value
    }

    // Thanks @Joe!
    // http://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(for apps with ads AND Google Play Services):

From the Google Play Developer's console:

Beginning August 1st, 2014, the Google Play Developer Program Policy requires all new app uploads and updates to use the advertising ID in lieu of any other persistent identifiers for any advertising purposes. Learn more

Implementation:

Permission:

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

Code:

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 e) {
    // Unrecoverable error connecting to Google Play services (e.g.,
    // the old version of the service doesn't support getting AdvertisingId).

  } catch (GooglePlayServicesAvailabilityException e) {
    // Encountered a recoverable error connecting to Google Play services. 

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

Source/Docs:

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

 

http://developer.android.com/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.html

 

 

 

Important:

It is intended that the advertising ID completely replace existing usage of other identifiers for ads purposes (such as use of ANDROID_ID in Settings.Secure) when Google Play Services is available. Cases where Google Play Services is unavailable are indicated by a GooglePlayServicesNotAvailableException being thrown by getAdvertisingIdInfo().

Warning: User can reset:

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

I have tried to reference every link that I took information from. If you are missing and need to be included, please comment!

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Also you might consider the Wi-Fi adapter's MAC address. Retrieved thusly:

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

Requires permission android.permission.ACCESS_WIFI_STATE in the manifest.

Reported to be available even when Wi-Fi is not connected. If Joe from the answer above gives this one a try on his many devices, that'd be nice.

On some devices, it's not available when Wi-Fi is turned off.

 

 

 

=======================

=======================

=======================

 

 

 

 

출처: http://stunstun.tistory.com/184

Android 디바이스의 고유 번호 (Identifier) 획득 시 고려 해야 할 점

2014/01/03 20:38

Posted in Android by 스턴스턴(chujinnoon)

 

 

안드로이드 개발 시에 디바이스 정보를 획득 하는 일들이 있는데, 그 중 에서도 디바이스의 고유한 번호를 획득 하는 일은 빈번 하게 발생 한다. 예를 들면 고유한 디바이스의 정보를 저장 해 어플리케이션의 설치 상태를 확인 한다 던가

다양한 인증 서비스를 제공 할 때 보다 쉽게 서비스를 이용 할 수 있도록 게스트 로그인 같은 기능을 제공 할 때 디바이스에 대한 식별이 필요 할 때가 있다.

 

하지만 Android SDK 는 API Level 이 업데이트 되면서 이에 대한 정보를 획득 하는 데에 대한 이슈가 있는데, 간단 하게 나마 정리 해보고자 한다.

 

TelephonyManager

 

지난 시간 동안 일반적인 경우에는 Hardware 단위로 제공 하는 identifier 를 통해 디바이스의 고유 번호를 획득 하고는 했다. TelephonyManager 클래스를 통해 Phone의 IMEI, MEID 또는 ESN 값을 획득 한다.

예를 들면 아래와 같다.

TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
manager.getDeviceId();

하지만 TelephonyManager  를 통한 방법은 아래와 같은  이슈가 있다.

 

| Non - Phone : 핸드폰 번호를 갖고 있지 않는 태블릿 이나 Wifi 만을 제공 하는 디바이스는 TelephonyManager 를 통한 디바이스 번호를 획득 하지 못 할 수도 있다.

| Persistence : 한번 생성된 번호에 대한 지속 여부를 보장 할 수 가 없다. 디바이스가 공장 초기화 될 경우를 예로 들 수 있다. 뿐만 아니라, 현재 까지 몇몇 버그들이 report 되어 왔다. 안드로이드 디바이스는 제조사 마다 다양하게 커스터마이징 하기 때문에 000000000000000 같이 의미 없는 값이나 null 이 반환 되기도 한다.

| Privilege : 디바이스에 접근 하기 위해  READ_PHONE_STATE  권한 설정이 필요 하다.



Mac address

Wifi 나 blue-tooth 를 사용 하는 디바이스에서 획득 가능 하다. 하지만 디바이스의 고유 번호를 획득 하기 위한 용도로는 추천 되지 않는다. Wifi 가 항상 켜져 있다고 보장 할 수 없을 뿐만 아니라 모든 기기가 고유번호를 반환 하는 것이 아니기 때문이다.

 

 

Serial Number

안드로이드의 API Level 9 (진저브레드 2.3) 이후 부터 제공 하는 고유 번호 로서 TelephonyManager 클래스를 통한 획득 보다는 안전 하다고 할 수 있지만 2.3 미만의 Version 에서는 문제가 발생 할 수 가 있다.

API Level 9 부터 제공 하기 때문에 @SuppressLint("NewApi") 를 추가 해야 되기 때문에 아래와 같이 Java reflection을 통해 획득 하는 것이 좋다.

private static String getDeviceSerialNumber() {
 try {
   return (String) Build.class.getField("SERIAL").get(null);
 } catch (Exception ignored) {
   return null;
 }
}



ANDROID_ID

가장 명확한 방법이며, 디바이스가 최초 Boot 될때 생성 되는 64-bit 값이다. ANDROID_ID는 디바이스의 고유한 번호를 획득 하기 위해 가장 좋은 선택이 될 수 있다.

Settings.Secure.ANDROID_ID

하지만 ANDROID_ID 또한 단점이 있는데, Proyo 2.2 이전 Version 에는 100% 디바이스 고유 번호를 획득 한다고는 보장 할 수 없으며, 몇몇 Vendor 에서 출하된 디바이스에 동일한 고유 번호가 획득 된다는 버그가 report 됐다는 것이다.

 

 

결론

지금 까지 안드로이드 플랫폼에서 디바이스를 구별하기 위한 고유한 번호를 획득 하는 방법을 알아 보았는데, 물리적으로 100% 보장 할 수 없다는 것이고, 이로 인해 결코 쉽지 않은 일이라는 것을 알 수 있었다. 가장 좋은 방법은 ANDROID_ID를 통해 획득 하는 방법이며, 다른 해결책을 혼용 해 사용하는 것도 좋을 방법 일 것이다. 여기에 위에 나열된 예상 되는 이슈 들과 같은 만일의 사태에 대한 대비책을 만들어 놓는 것도 좋을 것 이다.

 

참조 : http://android-developers.blogspot.kr/2011/03/identifying-app-installations.html#uds-search-results

 

 

 

 

=======================

=======================

=======================

 

 

 

 

 

반응형


관련글 더보기

댓글 영역