Google Play의 연락처 권한 정책에 따라, 2027년 1월 27일부터 Android 17(API 레벨 37) 이상을 타겟으로 하는 앱은 다음 경우에만 요청할 수 있습니다. READ_CONTACTS Android Contact Picker가 핵심 기능을 지원하지 않을 때이며, Play Console 선언으로 이를 정당화해야 합니다. 친구 초대, 파일 공유, 전화번호 입력을 위해 연락처를 읽는 대부분의 Capacitor 앱의 경우, Contact Picker로 전환하고 권한을 제거하는 것이 해결책입니다. 이 가이드는 정책을 설명하고, @capgo/capacitor-contacts를 사용하여 이를 수행하는 방법을 보여주고, 전체 주소록이 실제로 필요한 경우의 대응 방안을 다룹니다.
정책에서 말하는 내용
Google은 2026년 4월 15일, 프라이버시 업데이트 일부분으로 이 정책을 발표했습니다. Play Console 도움말 페이지의 주요 내용은 다음과 같습니다:
- 범위: Android 17(API 37) 이상을 타겟으로 하고 요청하는 앱
READ_CONTACTS. - 규칙: 앱의 핵심 기능이 Android Contact Picker로 충족되지 않을 때만 요청할 수 있습니다.
READ_CONTACTSAndroid Contact Picker가 앱의 핵심 기능에 충분하지 않은 경우에만 - 선언: 권한을 유지하는 앱은 Play Console에서 해당 권한이 필요한 기능과 Picker가 부족한 이유를 설명하는 선언을 작성해야 합니다.
- 타임라인: Play Console은 선언하는 앱에 대해
READ_CONTACTS2026년 9월. 2027년 1월 27일부터 준수가 필수입니다. Google은 Play Console에서 30일 셀프 서비스 연장을 언급합니다. - 예외 사항: 프라이빗 앱 및 엔터프라이즈 기기 관리 앱은 적용 대상에서 제외됩니다.
- 데이터: 연락처 데이터는 사용자 데이터 정책상 개인적이고 민감한 정보이며, 해당 정보의 당사자 허가 없이 비공개 연락처 데이터를 게시할 수 없습니다.
READ_CONTACTS를 유지할 수 있는 사용 사례
Google은 연락처 관리 앱, 다이얼러 및 SMS 앱, 통화 기록 및 통화 스크리닝, CRM, 접근성 기능, 개인 비서, 친구 매칭, 백업 및 복구, 키보드 또는 자동 완성 등을 핵심 기능으로 나열합니다.
연락처 피커로 전환해야 하는 사용 사례
누군가를 초대하거나 추천하기, 파일 공유, 협업, 송금할 연락처 선택. 앱이 연락처를 읽는 이유가 이에 해당하면 선언이 승인되지 않습니다. Picker를 사용하세요.
Android 17에서 달라지는 점
Android 17에는 새로운 시스템 Contact Picker가 탑재됩니다. 앱은 별도의 권한 없이도 사용자가 선택한 연락처와 필드만 노출되는 임시 읽기 전용 세션 URI를 받게 됩니다. Android 17을 타겟팅하는 앱의 경우, 시스템이 기존의 Intent.ACTION_PICK contacts intent를 이 새로운 picker로 자동 업그레이드합니다. 앱은 새로운 intent action을 통해 특정 데이터 필드(전화번호, 이메일, 우편 주소) 및 다중 선택을 요청할 수도 있습니다.
이전 Android 버전에서는 연락처 선택기로 특정 데이터 행(예: 전화번호)을 선택하면 앱이 권한 없이 읽을 수 있는 URI를 항상 반환해 왔습니다. READ_CONTACTS이 덕분에 모든 Android 버전에서 권한 요청 없는 플로우를 구현할 수 있습니다.
예전에 “연락처 선택”에 READ_CONTACTS가 필요했던 이유
많은 Capacitor 플러그인은 연락처 전체를 고르는 선택기를 연 뒤, 해당 연락처의 전화번호와 이메일을 주소록에서 조회하는 식으로 “pick contact”를 구현합니다. 이 두 번째 쿼리에는 READ_CONTACTS권한이 필요합니다. 따라서 전화번호 하나만 원했던 앱조차 권한을 선언하게 되었고, 이것이 바로 이번 정책이 겨냥하는 지점입니다.
해결 방법은 선택기에 필요한 특정 필드를 요청하여, 결과 URI에 데이터가 이미 포함되도록 하는 것입니다.
READ_CONTACTS 없이 전화번호, 이메일, 주소 선택하기
@capgo/capacitor-contacts 버전 8.1.0에서 property 옵션을 추가했습니다. 이 옵션을 설정하면 Android는 전화, 이메일 또는 우편 주소 테이블을 대상으로 선택기를 열고, 부여된 URI에서 선택된 행을 읽어옵니다. 어떤 Android 버전에서도 READ_CONTACTS 권한이 필요하지 않습니다. iOS에서는 시스템 선택기에 연락처 권한이 전혀 필요하지 않습니다.
bun add @capgo/capacitor-contacts
bunx cap sync
import { CapacitorContacts, ContactProperty } from '@capgo/capacitor-contacts';
export async function pickPhoneNumber(): Promise<string | undefined> {
const { contacts } = await CapacitorContacts.pickContacts({
property: ContactProperty.PhoneNumber,
});
const picked = contacts[0];
return picked?.phoneNumbers?.[0]?.value;
}
export async function pickEmail(): Promise<string | undefined> {
const { contacts } = await CapacitorContacts.pickContacts({
property: ContactProperty.EmailAddress,
});
return contacts[0]?.emailAddresses?.[0]?.value;
}
사용하면 property, 결과에 연락처가 포함됩니다. id, displayName 선택한 속성만 반환합니다. 다중 선택은 무시되며, 속성 선택은 항상 하나의 값만 반환합니다. 사용자가 취소하면 빈 배열인지 확인하세요.
이 플러그인은 자체 매니페스트에 READ_CONTACTS 또는 WRITE_CONTACTS 선언하지 않으므로, 속성 선택만 사용하면 병합된 매니페스트가 깔끔하게 유지됩니다.
READ_CONTACTS가 여전히 필요하다면
다음 플러그인 메서드들은 주소록을 읽어오며 계속 권한을 요구합니다:
pickContacts()또는pickContact()없이property, 전체 연락처 레코드가 필요할 때getContacts(),getContactById(),countContacts()getGroups(),getGroupById(),getAccounts()
앱이 CRM, 백업 도구 또는 친구 매칭 기능이라면 이는 정당한 핵심 용도입니다. 권한을 직접 추가하고 선언서를 제출하세요:
<!-- android/app/src/main/AndroidManifest.xml -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
import { CapacitorContacts } from '@capgo/capacitor-contacts';
const perm = await CapacitorContacts.requestPermissions({ permissions: ['readContacts'] });
if (perm.readContacts === 'granted' || perm.readContacts === 'limited') {
const { contacts } = await CapacitorContacts.getContacts({
fields: ['displayName', 'phoneNumbers'],
limit: 200,
offset: 0,
});
console.log(contacts.length);
}
해당 정책은 다음을 대상으로 합니다 READ_CONTACTS. 연락처를 작성하는 경우 WRITE_CONTACTS ( createContact, updateContactById, deleteContactById)는 이번 정책의 대상이 아니며, 해당 메서드를 사용하는 경우에만 추가하세요.
Capacitor 앱 마이그레이션 계획
-
병합된 매니페스트를 검토하세요. 릴리스를 빌드하고 다음을 여세요
android/app/build/intermediates/merged_manifest/(또는 Android Studio의 Merged Manifest 탭 사용). 일부 플러그인은READ_CONTACTS사용자 모르게 추가됩니다. 플러그인이 추가했는데 필요 없다면 다음으로 제거하세요.tools:node="remove":<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.READ_CONTACTS" tools:node="remove" /> </manifest> -
연락처에 접근하는 모든 곳을 나열하세요. 각 항목에 대해 속성 기반 피커를 쓸지, 전체 주소록을 쓸지 결정하세요.
-
초대 및 공유 플로우를 교체하세요 포함
pickContacts({ property }). -
핵심 기능에만 권한을 유지하세요, 그리고 설명 문구를 준비하세요: 어떤 기능인지, 왜 picker로는 부족한지, 기능을 찾기 어렵다면 영상도 함께.
-
네이티브 빌드 배포. Manifest와 플러그인 변경 사항은 새 Play 릴리스가 필요합니다. CI에서 빌드한다면, Capgo 빌드 서명된 Android 빌드를 생성할 수 있으며, Android 키스토어 생성기 처음으로 서명을 설정하는 경우 도움이 됩니다.
-
UI 변경 사항은 OTA로 배포. 새 네이티브 플러그인이 라이브로 배포되면, 피커 관련 문구와 플로우 조정은 Live Update를 통해 Capgo Live Update 사용하기.
다른 연락처 플러그인에서 마이그레이션하기
사용 중이라면 @capacitor-community/contacts (작성 시점 기준 8.0.0), 해당 Android pickContact 피커를 열기 전에 연락처 권한 그룹을 요청한 뒤 주소록에서 전체 연락처를 읽습니다. property mode는 없습니다. 메서드 이름도 다릅니다 (getContact vs getContactById, projection 객체와 a fields 배열)입니다. 저희가 커뮤니티 contacts 플러그인과 Capgo 플러그인을 비교하여 각 호출을 매핑합니다.
아직 Capacitor 안에서 Cordova contacts 플러그인을 사용 중이라면, 지금이 교체할 좋은时机입니다. 참고: Cordova에서 Capacitor로 마이그레이션하기.
문제 해결
피커가 전화번호가 없는 연락처를 반환합니다. 호출한 내용: pickContacts() 없이 property 그리고 앱에는 없습니다 READ_CONTACTS. 오직 id 및 displayName (그리고 Android 17+에서는 picker-granted 필드도) 반환됩니다. 추가하세요 property.
Play Console에는 여전히 앱이 READ_CONTACTS 권한을 선언한 것으로 표시됩니다. 라이브러리가 권한을 추가합니다. 병합된 manifest를 확인하고 다음을 사용해 제거하세요 tools:node="remove". 또한 다른 트랙의 이전 릴리스도 확인하세요. 활성 아티팩트 각각이 카운트됩니다.
선언이 거부되었습니다. 초대, 추천, 공유 기능은 picker 사용 사례로 분류됩니다. 기능을 재설계하거나, 전체 연락처 목록이 왜 필수인지 명확히 설명하세요(예: 전체 주소록을 대상으로 실행되는 친구 매칭).
iOS에서 연락처 권한을 요청합니다. 주소록을 읽는 메서드를 호출하고 있습니다. Picker 사용에는 절대 필요하지 않습니다. 제거하세요 NSContactsUsageDescription 선택한 경우에만.
주요 일정
| 날짜 | 내용 |
|---|---|
| 2026년 4월 15일 | 정책 발표 |
| 2026년 9월 | Play Console에서 선언 대상 앱에 prompt 표시 READ_CONTACTS 선언서 제출 |
| 2027년 1월 27일 | Android 17 (API 37) 이상을 타겟팅하는 앱은 준수 필수 |
제출하기 전에 Play Console 도움말 페이지에서 정책을 확인하세요. Google이 마감일과 문구를 업데이트할 수 있습니다.