디바이스 내의 연락처 앱을 사용하다보면, 여러가지 정보들을 포함시킬 수 있는 것을 확인할 수 있습니다.
프로필 사진, 전화번호, 생일, 메모, 연락처 이름 등 다양한 데이터가 존재하는데,
이 중에서 대표적으로 화면에 보여지고 있는 프로필 사진, 생일, 연락처 이름, 연락처 고유 ID 데이터를
우리가 직접 만든 앱으로 가져올 수 있도록 구현해보겠습니다.
<uses-permission android:name="android.permission.READ_CONTACTS"/>
먼저 디바이스 연락처 접근 권한을 얻기 위한 permission tag를 AndroidManifest.xml 파일에 추가해줍니다.
private fun getContacts() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_CONTACTS), 0)
}
Activity 코드에서는 getContacts() 라는 함수를 생성하여, 사용자에게 권한 허가를 받기 위한 권한 요청 코드를 기입합니다.
해당 함수를 호출하게 되면 제일 먼저 시스템 다이얼로그를 통해 사용자가 연락처 접근에 대한 수락 / 거절을 선택 가능하게 되겠지요.
val uri: Uri = ContactsContract.Data.CONTENT_URI
val projection = arrayOf(
ContactsContract.CommonDataKinds.Photo.PHOTO_URI,
ContactsContract.PhoneLookup.LOOKUP_KEY,
ContactsContract.PhoneLookup._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Event.START_DATE
)
val where = ContactsContract.Data.MIMETYPE + "= ? AND " +
ContactsContract.CommonDataKinds.Event.TYPE + "=" +
ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY
val selectionArgs = arrayOf(
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE
)
val cursur = contentResolver.query(uri, projection, where, selectionArgs, null)
계속 getContacts() 함수에서 작업이 이어집니다.
https://developer.android.com/guide/topics/providers/contacts-provider?hl=ko
안드로이드 공식문서에서 확인 할 수 있는 Uri 기반으로 연락처 데이터를 제공받을 수 있는 Cursor를 구합니다.
ContactsContract.Data.CONTENT_URI
projection array에는 우리가 필요로 하는 데이터 요소를 지정할 수 있습니다.
ContactsContract.Contacts.DISPLAY_NAME, //연락처 이름
ContactsContract.PhoneLookup.LOOKUP_KEY, //연락처 검색을 위한 Key 값
ContactsContract.CommonDataKinds.Photo.PHOTO_URI, //연락처 프로필
ContactsContract.CommonDataKinds.Event._ID, //해당 연락처 정보의 고유 ID
ContactsContract.CommonDataKinds.Event.START_DATE //기념일 또는 생일 날짜 값
where는 쿼리에 사용되는 조건절입니다.
우리가 원하는 데이터는 MIMETYPE이며, TYPE_BIRTHDAY와 동일한 TYPE으로 쿼리해야 생일 날짜 값을 받을 수 있습니다.
val where = ContactsContract.Data.MIMETYPE + "= ? AND " +
ContactsContract.CommonDataKinds.Event.TYPE + "=" +
ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY
selectionArgs는 where 절에 실제로 전달할 값입니다.
MIMETYPE 기반으로 데이터를 가져오기 때문에 CONTENT_ITEM_TYPE을 전달해줍니다.
val selectionArgs = arrayOf(
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE
)
이렇게 생성한 Cursor를 통해 각 컬럼에 해당하는 인덱스 값을 가져와 실제 인덱스에 해당하는 값들을 추출합니다.
val contactIdColumn = cursor?.getColumnIndex(ContactsContract.CommonDataKinds.Event._ID) ?: 0
val birthColumn = cursor?.getColumnIndex(ContactsContract.CommonDataKinds.Event.START_DATE) ?: 0
val contactNameColumn = cursor?.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME) ?: 0
val lookUpKeyColumn = cursor?.getColumnIndex(ContactsContract.PhoneLookup.LOOKUP_KEY) ?: 0
val photoUriColumn = cursor?.getColumnIndex(ContactsContract.CommonDataKinds.Photo.PHOTO_URI) ?: 0
if (cursor != null) {
while (cursor.moveToNext()) {
val id = cursor.getString(contactIdColumn)
val contactName = cursor.getString(contactNameColumn)
val birth = cursor.getString(birthColumn).convertToDateList() //custom func
val lookUpKey = cursor.getString(lookUpKeyColumn)
val photoUri = cursor.getString(photoUriColumn) ?: ""
}
}
최종적으로 로그를 찍어보면, 이렇게 데이터를 반환하는 것을 확인할 수 있습니다.
프로필 사진은 특별하게 지정된 것이 없다면 null로 수신받네요.
또한 생일 설정 시, 연도를 지정하지 않았다면 --11-22, 설정했다면 2022-11-22 형태로 수신 받습니다.
프로필 사진의 경우에는 수신 받은 포토 Uri를 그대로 Glide에 적용하여 사용 가능합니다.
Glide.with(context)
.load(photoUrl)
.into(holder.linkImg)
LookUpKey와 ID 같은 경우에는 다음과 같이 getLookupUri(id: Long, key: String)을 활용하여
사용자의 연락처 프로필로 바로 이동할 수 있는 Uri 생성이 가능합니다.
val contactUri = ContactsContract.Contacts.getLookupUri(contactId.toLong(), url)
val intent = Intent(Intent.ACTION_VIEW)
intent.data = contactUri
activity?.startActivity(intent)