Selektor kontaktów: udostępnianie kontaktów z zachowaniem prywatności
4 minuty czytania
Prywatność i ustawienia dostępne dla użytkownika nadal są najważniejszymi elementami Androida. Podobnie jak selektor zdjęć, który sprawił, że udostępnianie multimediów stało się bezpieczne i łatwe do wdrożenia, teraz wprowadzamy ten sam poziom prywatności, prostoty i wygody w przypadku wybierania kontaktów.
Nowy standard prywatności kontaktów
W przeszłości aplikacje wymagające dostępu do kontaktów konkretnego użytkownika korzystały z szerokiego uprawnienia READ_CONTACTS. Chociaż to podejście było funkcjonalne, często przyznawało aplikacjom więcej danych niż było to konieczne. Nowy selektor kontaktów na Androidzie, wprowadzony w Androidzie 17, zmienia tę sytuację, udostępniając standardowy, bezpieczny i umożliwiający wyszukiwanie interfejs do wybierania kontaktów.
Dzięki tej funkcji użytkownicy mogą przyznawać aplikacjom dostęp tylko do wybranych przez siebie kontaktów, co jest zgodne z zobowiązaniem Androida do zapewnienia przejrzystości danych i minimalizacji zakresu uprawnień.
Jak to działa
Deweloperzy mogą zintegrować selektor kontaktów za pomocą intencji Intent.ACTION_PICK_CONTACTS. Ten zaktualizowany interfejs API oferuje kilka zaawansowanych funkcji:
- Szczegółowe żądania danych: aplikacje mogą określać dokładnie, które pola są im potrzebne, np. numery telefonów lub adresy e-mail, zamiast otrzymywać cały rekord kontaktu.
- Obsługa wielokrotnego wyboru: selektor obsługuje wybieranie pojedynczych i wielu kontaktów, co daje deweloperom większą elastyczność w przypadku funkcji takich jak zaproszenia grupowe.
- Limity wyboru: deweloperzy mogą ustawiać niestandardowe limity liczby kontaktów, które użytkownik może wybrać jednocześnie.
- Dostęp tymczasowy: po wybraniu systemu zwraca identyfikator URI sesji, który zapewnia tymczasowy dostęp do odczytu żądanych danych, dzięki czemu dostęp nie trwa dłużej niż to konieczne.
- Dostęp do innych profili: w przypadku używania tej nowej intencji interfejs umożliwi użytkownikom wybieranie treści z innych profili użytkowników, takich jak profil służbowy, sklonowany profil lub przestrzeń prywatna.
- Zoptymalizowana wydajność: selektor kontaktów zwraca pojedynczy identyfikator URI, który umożliwia zbiorcze wysyłanie zapytań o wyniki, co eliminuje konieczność wysyłania zapytań o poszczególne identyfikatory URI kontaktów oddzielnie, jak to jest wymagane w przypadku
ACTION_PICK. Ta wydajność dodatkowo zmniejsza obciążenie systemu dzięki wykorzystaniu pojedynczej transakcjiBinder.
Zgodność wsteczna i implementacja
W przypadku urządzeń z Androidem 17 lub nowszym system automatycznie uaktualnia starsze intencje ACTION_PICK, które określają typy danych kontaktowych, do nowego, bezpieczniejszego interfejsu. Aby jednak w pełni wykorzystać funkcje zaawansowane, takie jak wielokrotny wybór, deweloperzy powinni zaktualizować kod implementacji i użyć ContentResolver do wysyłania zapytań o zwrócony identyfikator URI sesji.
Integracja selektora kontaktówAby zintegrować selektor kontaktów, deweloperzy używają intencji ACTION_PICK_CONTACTS. Poniżej znajdziesz przykład kodu, który pokazuje, jak uruchomić selektor i poprosić o konkretne pola danych, takie jak adres e-mail i numer telefonu.
// 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)
Gdy użytkownik dokona wyboru, aplikacja przetwarza wynik, wysyłając zapytanie o zwrócony identyfikator URI sesji, aby wyodrębnić żądane informacje kontaktowe.
// 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 }
Pełną dokumentację znajdziesz tutaj.
Sprawdzone metody dla deweloperów
Aby zapewnić użytkownikom jak najlepsze wrażenia i utrzymać wysokie standardy bezpieczeństwa, zalecamy:
- Minimalizacja danych: proś tylko o te pola danych (np. adres e-mail), których potrzebuje Twoja aplikacja.
- Natychmiastowe utrwalanie: utrwalaj wybrane dane natychmiast, ponieważ dostęp do identyfikatora URI sesji jest tymczasowy.
-
r.r.
Nowości dotyczące usługSelektor zdjęć wbudowany w aplikację: wygodniejszy sposób na prywatne żądanie zdjęć i filmów w aplikacji.
Roxanna Aliabadi Walker, Yacine Rezgui • 8 minut czytania -
Nowości dotyczące usługZapewnienie bezpiecznego środowiska online i ochrona użytkowników przed szkodliwymi treściami to dla nas w Google Play priorytet.
Paul Feng • 2 minuty czytania -
Nowości dotyczące usługDziś oficjalnie obchodzimy 5. rocznicę premiery Jetpack Compose 1.0. Od wersji 1.0, ogłoszonej 28 lipca 2021 r., do najnowszej wersji 1.11 interfejsy API znacznie się rozwinęły, dlatego chcemy to uczcić.
Rebecca Franks, Nick Butcher, Loryn Hairston • 5 minut czytania
Otrzymuj co tydzień najnowsze informacje o tworzeniu aplikacji na Androida na swoją skrzynkę odbiorczą.