본문 바로가기

자료

안드로이드 개별 디바이스를 구분하는 방법

Android Identifying App Installations

Posted by Tim Bray on 30 March 2011 at 1:08 PM

 안드로이드 개발팀은 종종 개별 디바이스를 구분 하는데 어려움을 겪는 개발자들의 불평을 듣곤합니다. 개발자들은 안정적이고 믿을만하고 그리고 유일한 디바이스 식별자 (Unique Device ID) 가 필요하다고 이야기합니다만, 사실 저희는 디바이스 식별자를 찾는것은 그다지 권장할만한 방법이 아니라고 생각합니다. 어플리케이션 개발자들의 일반적인 목적을 이루기 위해서라면, 디바이스 고유 식별자를 활용하는 것 보다 좋은 방법이 있기도 하구요. 바로 디바이스 자체를 구별하는 것이 아니라 설치된 어플리케이션을 구분하는 방식입니다.


Tracking Installations  - 설치된 어플리케이션을 추적하기 

 어플리케이션 개발자 입장에서, 사용자가 설치해 사용 중인 어플리케이션을 각각 구분하고 추척할 필요가 생길 수 있습니다. 예를 들어 '카카오톡' 과 같은 메신저 어플리케이션을 만든다고 하면, 한 단말에서 다른 단말로 메시지를 전달하기 위해서는 각각의 단말에 설치된 어플리케이션을 구분할 수 있어야겠지요. 이런일을 할 때 가장 간단하게 떠올릴 수 있는 방법은 바로 TelephonyManager.getDeviceId() 메서드를 사용하는 것 입니다. 리턴되는 값을 설치된 어플리케이션의 고유 식별자로 사용하는 것 이지요. 하지만, 이 방식에는 두 가지 문제점이 있습니다. 첫째로, 이 방법이 항상 통하는 것은 아닙니다. (아래에 보다 상세히 설명드리겠습니다.) 둘째, 이 값은 해당 단말이 '공장 초기화' 처럼 완전히 초기화되는 경우에도 계속 유지됩니다. 그러므로, 만일 여러분의 어플리케이션을 사용하던 사용자가 폰을 초기화한 후 해당 단말을 다른 사용자에게 넘겨버리는 경우에는 끔찍한 오류가 발생할 수도 있습니다. (예를 들어, 엉뚱한 사람에게 엉뚱한 메세지가 전달될 수 있겠지요.)

  따라서, 어플리케이션을 식별하기 위해서는 UUID 를 식별자로 사용하는 편이 더 편리합니다. 어플리케이션이 설치된 후, 최초 실행 시에 UUID 를 하나 만들어 두면 됩니다. 아래는 이러한 일을 하는데 필요한 메서드를 구현한  Installation 클래스의 간단한 예입니다. id 메서드가 호출되는 경우, 기존에 생성된 UUID 가 없는 경우 새롭게 하나를 만들어 이를 메모리에 저장해 두고, 기존에 만들어진 UUID 가 있는 경우 해당 값을 반환합니다.

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


Identifying Devices 디바이스 식별하기

 만일 여러분이 정말로 개별 디바이스를 식별할 필요가 있는 경우, 이는 생각보다 간단한 문제가 아닙니다.  과거, 모든 안드로이드 디바이스가 전화기였던 시절에는 일이 비교적 간단한 편 이었습니다. TelephonyManager.getDeviceId() 메서드가 호출되면 지원하는 폰 네트워크 기술에 따라서 IMEI,MEID,ESN 등의 값을 반환하도록 되어있었고, 각각의 값은 개별 디바이스마다 모두 유니크하도록 보장되어 있었지요.

 하지만 오늘날에는 이야기가 다릅니다.

  • 전화기가 아닌 안드로이드 단말: 와이파이만 지원하는 디바이스들은 전화 모뎀칩이 없으며, 따라서 IMEI,MEID,ESN 등의 값을 갖고 있지 않습니다.
  • 영속성: IMEI,MEID,ESN 등의 값은 디바이스가 완전히 공장 초기화되는 경우에도 동일하게 유지됩니다. 이런 경우에도 여러분의 어플리케이션은 해당 단말을 동일한 단말이라고 판단하게 됩니다. (이미 주인이 수십번 쯤 바뀐 후일 수도 있는데 말이지요.)
  • 권한: 이 메서드를 사용하기 위해서는 READ_PHONE_STATE 권한을 갖고 있어야 합니다. 만일 여러분이 폰 기능을 활용할 예정이 아니라면 좀 짜증나는 일이 되겠지요. 
  • 버그: 우리는 제품으로 출시된 몇몇 폰들에서 이 메서드의 결과값으로 0 이나 의미없는 문자열과 같은 쓰레게값이 반환되는 경우를 발견하기도 하였습니다.

Mac Address

 디바이스의 WiFi 장치나 블루투스 장치에 설정된 Mac 어드레스 값을 활용하는 방법도 생각해볼 수 있습니다. 하지만, 이는 권장되는 방법이 아닙니다. 모든 디바이스가 WiFi 를 갖고 있는 것도 아니며, 어떤 폰들은 WiFi 가 켜져 있지 않은 상황에서는 올바른 Mac 주소값을 리턴하지 않는 경우도 있기 때문입니다.

Serial Number

 안드로이드 2.3 진저브레드 버전부터는 android.os.Build.SERIAL 값을 활용 할 수도 있습니다. 전화기능이 없는 디바이스의 경우에는 해당 Constant 값으로 유니크한 디바이스 식별자를 반환 하도록 구현되어있습니다. 전화 기능을 갖춘 몇몇 디바이스들도 디바이스 식별자를 반환하기는 합니다. 하지만, 모든 디바이스가 다 그런 것은 아닙니다.
 

ANDROID_ID

 Settings.Secure.ANDROID_ID Constant 값을 활용할 수 있습니다. 이 값은 64bit 크기의 고유 값인데, 디바이스가 최초 부팅 될 때 생성되어 저장되며, 디바이스가 초기화 되는 경우에는 삭제됩니다. 개별 디바이스를 식별하기 위해서 ANDROID_ID 값을 활용하는 것이 가장 적절한 선택으로  생각됩니다. 단 몇가지 문제점이 있습니다. 프로요(안드로이드 2.2) 이전 버전의 단말의 경우 이 값이 그다지 믿을만 하지 않으며, 메이저 제조사에서 제작한 인기 단말에서 모든 단말의 ANDROID_ID 값이 모두 동일한 버그가 발견되기도 하였습니다. (주>설마 삼성인건 아니겠지요... ㄷㄷㄷ)

(nvu 님이 내용을 확인해 주셨습니다. 감사합니다^^ 얼마전까지 (아마 펌업 전이겠조?) 갤럭시 S 와 드로이드2에서 이런 버그가 있었다고 하네요. CTS (구글 호환성 테스트) 에서 해당 내용을 확인하지 않고 있었다고 하니 꼭 제조사를 탓할 문제는 아닌거 같습니다. 하여간에 아직까지 ANDROID_ID 값을 이용해서 디바이스를 식별하는 것은 상당히 위험할 것 같습니다.)


결론

 대부분의 경우, 개발자는 자신이 원하는 시나리오를 처리하기 위하여, 설치된 각각의 어플리케이션끼리 서로 구분할 필요가 있습니다. 앞서 예로 든 UUID 를 활용하는 방법등을 이용하면, 비교적 손쉽게 설치된 어플리케이션을 고유하게 식별할 수 있습니다.

 물리적인 디바이스 자체를 구분하는 것은 여러가지 이유로 권장되는 방법은 아닙니다만, 그럼에도 꼭 이런 일을 하실 필요가 있다면, ANDROID_ID 값을 활용하는 것이 가장 합리적으로 생각됩니다. 물론 이 경우에, 앞서 이야기한 여러가지 문제점과 기존의 레거시 디바이스는 어떻게 처리할 것인가에 관한 고려가 필요합니다.

출처 : http://blog.naver.com/PostView.nhn?blogId=huewu&logNo=110107222113&viewDate=&currentPage=1&listtype=0