Ürün Haberleri

Kişi Seçici: Gizliliğe Öncelik Veren Kişi Paylaşımı

Okuma süresi: 4 dakika
Roxanna Aliabadi Walker
Ürün Yöneticisi

Gizlilik ve kullanıcı kontrolü, Android deneyiminin merkezinde yer almaya devam ediyor. Fotoğraf seçici, medya paylaşımını güvenli ve kolay hale getirmişti. Şimdi de aynı düzeyde gizlilik, basitlik ve mükemmel kullanıcı deneyimini kişi seçimine getiriyoruz.

Kişi Gizliliği İçin Yeni Bir Standart

Geçmişte, belirli bir kullanıcının kişilerine erişim gerektiren uygulamalar geniş kapsamlı READ_CONTACTS iznini kullanıyordu. Bu yaklaşım işlevsel olsa da genellikle uygulamalara gerekenden daha fazla veri erişimi veriyordu. Android 17'de kullanıma sunulan yeni Android Kişi Seçici, kişi seçimi için standartlaştırılmış, güvenli ve aranabilir bir arayüz sağlayarak bu durumu değiştiriyor.

Bu özellik, kullanıcıların uygulamalara yalnızca seçtikleri belirli kişilere erişim izni vermesine olanak tanıyarak Android'in veri şeffaflığı ve izin ayak izlerinin en aza indirilmesi konusundaki taahhüdüyle uyumlu hale geliyor.

picker.png
selection.png

İşleyiş Şekli

Geliştiriciler, Intent.ACTION_PICK_CONTACTS intent'ini kullanarak Kişi Seçici'yi entegre edebilir. Bu güncellenmiş API, çeşitli güçlü özellikler sunar:

  • Ayrıntılı Veri İstekleri: Uygulamalar, tüm kişi kaydını almak yerine tam olarak hangi alanlara (ör. telefon numaraları veya e-posta adresleri) ihtiyaç duyduklarını belirtebilir.
  • Çoklu Seçim Desteği: Seçici, hem tek hem de birden fazla kişi seçimini destekleyerek geliştiricilere grup davetleri gibi özellikler için daha fazla esneklik sunar.
  • Seçim sınırları: Geliştiriciler, kullanıcının tek seferde seçebileceği kişi sayısına özel sınırlar belirleyebilir.
  • Geçici Erişim: Seçim yapıldığında sistem, istenen verilere geçici okuma erişimi sağlayan bir oturum URI'si döndürür. Böylece erişimin gerekenden uzun sürmemesi sağlanır.
  • Diğer profillere erişim:  Bu yeni amaç kullanıldığında arayüz, kullanıcıların iş profili, klonlanmış profil veya özel alan gibi diğer kullanıcı profillerindeki içerikleri seçmesine olanak tanır.
  • Optimize Edilmiş Performans: Kişi Seçici, toplu sonuç sorgulamasına olanak tanıyan tek bir Uri döndürür. Bu sayede, ACTION_PICK tarafından gerekli olduğu şekilde ayrı ayrı kişi Uri'lerini sorgulama ihtiyacı ortadan kalkar. Bu verimlilik, tek bir Binder işlemi kullanılarak sistem yükünü daha da azaltır.

Geriye Dönük Uyumluluk ve Uygulama

Android 17 veya sonraki sürümlerin yüklü olduğu cihazlarda sistem, kişi verisi türlerini belirten eski ACTION_PICK intent'lerini yeni ve daha güvenli arayüze otomatik olarak yükseltir. Ancak çoklu seçim gibi ileri seviye özelliklerden tam olarak yararlanmak için geliştiricilerin uygulama kodlarını güncellemeleri ve döndürülen oturum URI'sini sorgulamak için ContentResolver kullanmaları önerilir.


Kişi seçiciyi entegre etmeKişi seçiciyi entegre etmek için geliştiriciler ACTION_PICK_CONTACTS intent'ini kullanır. Aşağıda, seçiciyi başlatmanın ve e-posta ve telefon numaraları gibi belirli veri alanlarını istemenin nasıl yapılacağını gösteren bir kod örneği verilmiştir.

// State to hold the list of selected contacts
var contacts by remember { mutableStateOf<List>(emptyList()) }
// Launcher for the Contact Picker intent
val pickContact = rememberLauncherForActivityResult(StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) {
val resultUri = it.data?.data ?: return@rememberLauncherForActivityResult
    // Process the result URI in a background thread
    coroutine.launch {
        contacts = processContactPickerResultUri(resultUri, context)
    }
}
}
// Define the specific contact data fields you need
val requestedFields = arrayListOf(
Email.CONTENT_ITEM_TYPE,
Phone.CONTENT_ITEM_TYPE,
)
// Set up the intent for the Contact Picker
val pickContactIntent = Intent(ACTION_PICK_CONTACTS).apply {
putExtra(EXTRA_PICK_CONTACTS_SELECTION_LIMIT, 5)
putStringArrayListExtra(
EXTRA_PICK_CONTACTS_REQUESTED_DATA_FIELDS,
requestedFields
)
putExtra(EXTRA_PICK_CONTACTS_MATCH_ALL_DATA_FIELDS, false)
}
// Launch the picker
pickContact.launch(pickContactIntent)

Kullanıcı bir seçim yaptıktan sonra uygulama, istenen iletişim bilgilerini ayıklamak için döndürülen oturum URI'sini sorgulayarak sonucu işler.

// Data class representing a parsed Contact with selected details
data class Contact(val id: String, val name: String, val email: String?, val phone: String?)

// Helper function to query the content resolver with the URI returned by the Contact Picker.
// Parses the cursor to extract contact details such as name, email, and phone number
private suspend fun processContactPickerResultUri(
    sessionUri: Uri,
    context: Context
): List<Contact> = withContext(Dispatchers.IO) {
    // Define the columns we want to retrieve from the ContactPicker ContentProvider
    val projection = arrayOf(
        ContactsContract.Contacts._ID,
        ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
        ContactsContract.Data.MIMETYPE, // Type of data (e.g., email or phone)
        ContactsContract.Data.DATA1, // The actual data (Phone number / Email string)
    )

    val results = mutableListOf<Contact>()

    // Note: The Contact Picker Session Uri doesn't support custom selection & selectionArgs.
    context.contentResolver.query(sessionUri, projection, null, null, null)?.use { cursor ->
        // Get the column indices for our requested projection
        val contactIdIdx = cursor.getColumnIndex(ContactsContract.Contacts._ID)
        val mimeTypeIdx = cursor.getColumnIndex(ContactsContract.Data.MIMETYPE)
        val nameIdx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)
        val data1Idx = cursor.getColumnIndex(ContactsContract.Data.DATA1)

        while (cursor.moveToNext()) {
            val contactId = cursor.getString(contactIdIdx)
            val mimeType = cursor.getString(mimeTypeIdx)
            val name = cursor.getString(nameIdx) ?: ""
            val data1 = cursor.getString(data1Idx) ?: ""

            // Determine if the current row represents an email or a phone number
            val email = if (mimeType == Email.CONTENT_ITEM_TYPE) data1 else null
            val phone = if (mimeType == Phone.CONTENT_ITEM_TYPE) data1 else null

            // Add the parsed contact to our results list
            results.add(Contact(contactId, name, email, phone))
        }
    }

    return@withContext results
}

Belgelerin tamamını buradan inceleyebilirsiniz.

Geliştiriciler için En İyi Uygulamalar

En iyi kullanıcı deneyimini sunmak ve yüksek güvenlik standartlarını korumak için aşağıdakileri yapmanızı öneririz:

  • Veri Azaltma: Yalnızca uygulamanızın ihtiyaç duyduğu belirli veri alanlarını (ör. e-posta) isteyin.
  • Anında Kalıcılık: Oturum URI'sine erişim geçici olduğundan seçilen verileri hemen kalıcı hale getirin.

Okumaya devam edin