Новости о продуктах
Contact Picker: Обмен контактами с соблюдением принципов конфиденциальности.
4 минуты чтения

Конфиденциальность и контроль со стороны пользователя остаются в основе работы с Android. Так же, как функция выбора фотографий сделала обмен медиафайлами безопасным и простым, теперь мы обеспечиваем тот же уровень конфиденциальности, простоты и удобства использования для выбора контактов.
Новый стандарт конфиденциальности контактной информации
Исторически сложилось так, что приложения, которым требовался доступ к контактам конкретного пользователя, полагались на широкое разрешение READ_CONTACTS . Хотя такой подход был функциональным, он часто предоставлял приложениям больше данных, чем необходимо. Новый инструмент выбора контактов Android, представленный в Android 17, меняет эту ситуацию, предоставляя стандартизированный, безопасный и удобный для поиска интерфейс для выбора контактов.
Эта функция позволяет пользователям предоставлять приложениям доступ только к выбранным ими контактам, что соответствует стремлению Android к прозрачности данных и минимизации объема необходимых разрешений.


Как это работает
Разработчики могут интегрировать средство выбора контактов, используя интент Intent.ACTION_PICK_CONTACTS . Этот обновленный API предлагает ряд мощных возможностей:
- Запросы с подробным указанием данных: приложения могут точно указывать, какие поля им необходимы, например, номера телефонов или адреса электронной почты, вместо того, чтобы получать всю контактную информацию целиком.
- Поддержка множественного выбора: средство выбора поддерживает как выбор одного, так и нескольких контактов, что предоставляет разработчикам большую гибкость при реализации таких функций, как групповые приглашения.
- Ограничения на выбор: Разработчики могут устанавливать пользовательские ограничения на количество контактов, которые пользователь может выбрать одновременно.
- Временный доступ: После выбора система возвращает URI сессии, предоставляющий временный доступ для чтения к запрошенным данным, гарантируя, что доступ не будет сохраняться дольше, чем это необходимо.
- Доступ к другим профилям: При использовании этого нового интента интерфейс позволит пользователям выбирать содержимое из других пользовательских профилей, таких как рабочий профиль, клонированный профиль или личное пространство.
- Оптимизированная производительность: средство выбора контактов возвращает один URI, что позволяет выполнять запросы к результатам в совокупности, устраняя необходимость запрашивать каждый URI контакта отдельно, как это требуется для
ACTION_PICK. Эта эффективность дополнительно снижает системные накладные расходы за счет использования одной транзакцииBinder.
Обратная совместимость и реализация
Для устройств под управлением Android 17 и выше система автоматически обновляет устаревшие интенты ACTION_PICK , указывающие типы данных контактов, до нового, более безопасного интерфейса. Однако, чтобы в полной мере воспользоваться расширенными функциями, такими как множественный выбор, разработчикам рекомендуется обновить свой код реализации и использовать ContentResolver для запроса возвращаемого URI сессии.
Интеграция средства выбора контактов. Для интеграции средства выбора контактов разработчики используют интент ACTION_PICK_CONTACTS . Ниже приведен пример кода, демонстрирующий, как запустить средство выбора и запросить определенные поля данных, такие как адрес электронной почты и номера телефонов.
// 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)
После того, как пользователь сделает выбор, приложение обрабатывает результат, запрашивая возвращенный URI сессии для извлечения запрошенной контактной информации.
// 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 }
Полную документацию можно посмотреть здесь .
Рекомендации для разработчиков
Для обеспечения наилучшего пользовательского опыта и поддержания высоких стандартов безопасности мы рекомендуем следующее:
- Минимизация данных: запрашивайте только те поля данных (например, электронную почту), которые необходимы вашему приложению.
- Мгновенное сохранение: выбранные данные сохраняются немедленно, поскольку доступ по URI сессии носит временный характер.
Продолжить чтение

Новости о продуктах
Встроенный инструмент выбора фотографий: более удобный способ конфиденциального запроса фотографий и видео в вашем приложении.
Roxanna Aliabadi Walker , Yacine Rezgui • Чтение 8 минут

Новости о продуктах
Android Studio Panda 4 теперь стабильна и готова к использованию в продакшене. В этом релизе появились режим планирования, прогнозирование следующего изменения и многое другое, что делает создание высококачественных Android-приложений проще, чем когда-либо.
Matt Dyor • 5 мин чтения

Новости о продуктах
Если вы — разработчик Android-приложений, стремящийся внедрить в них инновационные функции искусственного интеллекта, то недавно мы выпустили новые мощные обновления.
Thomas Ezan • 3 мин чтения
Будьте в курсе событий
Получайте еженедельно самые свежие новости о разработке Android прямо на свою электронную почту.



