概要
ContactsContract.Contacts.CONTENT_VCARD_URI
を使って連絡先をvCard形式で取得します。
詳細
Androidには、連絡先からvCard形式のデータを取得するContent URIがあるので、それを利用して連絡先をvCardにして取得を行います。
利用するには READ_CONTACTS
のパーミッションが必要になるので適宜取得してください。
vCardを取得したい連絡先を選択
まずはvCard形式で取得したい連絡先を選択します。おそらく最も手軽であろう連絡先読み込みIntentで連絡先をリストから選択して、その結果を受け取るようにします。
val pickContact = registerForActivityResult(ActivityResultContracts.PickContact()) {
}
pickContact.launch()
このコードで、連絡先アクティビティが開き、連絡先を指定したらregisterForActivityResultのコールバックにURIが戻ってきます。
連絡先からLOOKUP_KEYを取得
次に、連絡先から、vCardの取得に必要なLOOKUP_KEYを取得します。
取得したURI(it)でLOOKUP_KEY取得用のCursorを作り、Cursorから目的の連絡先のLOOKUP_KEYを取得します。
val pickContact = registerForActivityResult(ActivityResultContracts.PickContact()) {
val projection = arrayOf(
ContactsContract.Contacts.LOOKUP_KEY,
)
val cursorForLookupKey = contentResolver.query(
it!!,
projection,
null,
null,
null
)
var lookupKey: String = ""
cursorForLookupKey?.apply {
val index: Int = getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)
while (moveToNext()) {
lookupKey = getString(index)
}
}
cursorForLookupKey?.close()
}
pickContact.launch()
vCard URIからvCardを読み込み
そして、取得したLOOKUP_KEYと合わせてvCard取得用のURIを作成します。
この作成には Uri#withAppendedPath(Uri, String)
を使います。
vCard用のURIが作成できたら、ContentResolver#openAssetFileDescriptor(Uri, String)
でassetFileDescriptorを取得し、FileInputStreamをassetFileDescriptorで作成して読み込みます。
assetFileDescriptorのlengthは UNKNOWN_LENGTH
になっている場合があるので、FileInputStreamを1バイトずつ読み込みます。
以下、vCard取得する処理の全体像になります。
val pickContact = registerForActivityResult(ActivityResultContracts.PickContact()) {
val projection = arrayOf(
ContactsContract.Contacts.LOOKUP_KEY,
)
val cursorForLookupKey = contentResolver.query(
it!!,
projection,
null,
null,
null
)
var lookupKey: String = ""
cursorForLookupKey?.apply {
val index: Int = getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)
while (moveToNext()) {
lookupKey = getString(index)
}
}
cursorForLookupKey?.close()
// 追加
val vcardUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI,
lookupKey)
val assetFileDescriptor = contentResolver.openAssetFileDescriptor(vcardUri,"r")
val fileDescriptor = assetFileDescriptor?.fileDescriptor
val input = FileInputStream(fileDescriptor)
var bytes = byteArrayOf()
var nextByte = 0
while (true) {
nextByte = input.read()
if (nextByte == -1) {
break
}
bytes += nextByte.toByte()
}
val vCard = String(bytes)
Log.d(TAG,"vCard ${vCard}")
assetFileDescriptor?.close()
}
pickContact.launch()
vCardのデータについて
出力されたvCardはこんな感じになります。QUOTED-PRINTABLEでエンコードされている点に注意しましょう。
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E7=B9=94=E7=94=B0;=E4=BF=A1=E9=95=B7;;;
FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E7=B9=94=E7=94=B0=E4=BF=A1=E9=95=B7
X-PHONETIC-FIRST-NAME;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E3=81=AE=E3=81=B6=E3=81=AA=E3=81=8C
X-PHONETIC-LAST-NAME;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E3=81=8A=E3=81=A0
TEL;WORK:090-222-xxxxx
EMAIL;WORK:nobu@example.com
ORG:
PHOTO;ENCODING=BASE64;JPEG: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
END:VCARD
vCard文字列に関する公式のAPIは存在しないと思うので、ex-vcardなどで確認するのが簡単だと思います。