隱私權和使用者控制選項仍是 Android 體驗的核心。相片挑選工具讓媒體分享功能安全又容易實作,現在我們也將同等程度的隱私權、簡便性和優質使用者體驗帶入聯絡人選取功能。
聯絡人隱私權的新標準
過去,需要存取特定使用者聯絡人的應用程式會依賴廣泛的READ_CONTACTS權限。雖然這種做法可行,但通常會授予應用程式超出必要的資料存取權。Android 17 推出的全新 Android 聯絡人選擇工具改變了這種情況,為聯絡人選取作業提供標準化、安全且可搜尋的介面。
這項功能可讓使用者只授予應用程式存取所選聯絡人的權限,符合 Android 對資料透明度和盡量減少權限足跡的承諾。
運作方式
開發人員可以使用 Intent.ACTION_PICK_CONTACTS 意圖整合聯絡人選擇工具。這項更新版 API 提供多項強大功能:
- 精細資料要求:應用程式可以指定需要的確切欄位,例如電話號碼或電子郵件地址,不必接收整個聯絡人記錄。
- 支援多重選取:選擇工具支援單一和多個聯絡人選取作業,讓開發人員能更靈活地運用這項功能,例如邀請群組成員。
- 選取限制:開發人員可以自訂使用者一次可選取的聯絡人數上限。
- 暫時存取權:選取後,系統會傳回工作階段 URI,提供所要求資料的暫時讀取權限,確保存取權不會持續超過必要時間。
- 存取其他設定檔: 使用這項新意圖時,介面會允許使用者從其他使用者設定檔 (例如工作資料夾、複製的設定檔或私人空間) 選取內容。
- 效能最佳化: 聯絡人選擇工具會傳回單一 Uri,可供查詢集合結果,因此不必像
ACTION_PICK一樣分別查詢個別聯絡人 Uri。這項效率可利用單一Binder交易,進一步減少系統負荷。
回溯相容性和實作
如果裝置搭載 Android 17 以上版本,系統會自動將指定聯絡人資料類型的舊版 ACTION_PICK 意圖升級為新的安全介面。不過,如要充分運用多選等進階功能,建議開發人員更新實作程式碼,並使用 ContentResolver 查詢傳回的 Session 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 XR 生態系統正在迅速擴展,Samsung Galaxy XR 也已於今天上市。
Stevan Silva, Vinny DaSilva • 3 分鐘可讀完
-
產品新訊
每年 Google I/O 大會都會發布生態系統和產品的最新消息與資源,包括 Android 開發。隨著開發工作轉向 AI 和代理程式輔助工具,我們也擴大產品陣容,無論您決定如何建構 Android 應用程式,都能獲得更完善的支援。
Simona Milanovic • 閱讀時間:2 分鐘
隨時掌握最新消息
每週透過電子郵件接收最新的 Android 開發洞察資訊。