본문 바로가기

2027년 Google Play 연락처 정책: Capacitor 가이드

Google Play의 연락처 권한 정책에 따라 2027년 1월부터 READ_CONTACTS 권한 사용이 제한됩니다. Capacitor 앱에 적용되는 변경 사항과 Contact Picker 사용법을 알아보세요.

2027년 Google Play 연락처 정책: Capacitor 가이드

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.
  • 규칙: 다음의 경우에만 요청할 수 있습니다: READ_CONTACTS 앱의 핵심 기능 구현에 Android Contact Picker만으로는 충분하지 않은 경우.
  • 선언 사항: 해당 권한을 유지하려는 앱은 Play Console에서 어떤 기능에 왜 이 권한이 필요한지, 그리고 왜 Picker를 사용할 수 없는지 설명하는 선언서를 작성해야 합니다.
  • 타임라인: Play Console은 해당 권한을 선언한 앱에 대해 prompt를 시작했습니다. READ_CONTACTS 2026년 9월까지 완료해야 하며, 2027년 1월 27일부터는 준수가 필수입니다. Google은 Play Console에서 30일간의 셀프 서비스 연장 기간을 제공한다고 밝혔습니다.
  • 예외 사항: 프라이빗 앱 및 엔터프라이즈 기기 관리 앱은 적용 대상에서 제외됩니다.
  • 데이터: 연락처 데이터는 사용자 데이터 정책에 따라 개인정보이자 민감 정보로 분류됩니다. 대상자의 권한 없이 공개되지 않은 연락처 데이터를 게시할 수 없습니다.

READ_CONTACTS 권한을 유지할 수 있는 유스케이스:

Google은 연락처 관리 앱, 다이얼러 및 SMS 앱, 통화 기록 및 통화 스크리닝, CRM, 접근성 기능, 개인 비서, 친구 매칭, 백업 및 복구, 키보드 또는 자동 완성 등을 핵심 기능으로 나열했습니다.

Picker로 전환해야 하는 유스케이스:

사용자 초대 또는 추천, 파일 공유, 협업, 또는 송금 대상 연락처 선택 등이 해당됩니다. 이러한 목적으로 앱이 연락처를 읽는다면 선언이 승인되지 않습니다. 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 플러그인은 연락처 전체를 선택하는 피커를 연 다음, 해당 연락처의 전화번호와 이메일을 가져오기 위해 주소록을 다시 조회하는 방식으로 “연락처 선택”을 구현합니다. 이 두 번째 조회에는 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;
}

GCP는 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 앱 마이그레이션 계획

  1. 병합된 Manifest를 검토하세요. 릴리스를 빌드하고 다음을 여세요 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>
  2. 연락처에 접근하는 모든 지점을 나열하세요. 각 지점에 대해 속성 기반 피커를 쓸지, 전체 주소록을 쓸지 결정하세요.

  3. 초대 및 공유 플로우를 교체하세요 함께 pickContacts({ property }).

  4. 핵심 기능에만 권한을 유지하세요, 그리고 다음 내용을 포함한 설명 문구를 준비하세요: 해당 기능, Picker만으로는 부족한 이유, 기능이 찾기 어렵다면 시연 영상.

  5. Native Build를 배포합니다. Manifest 및 플러그인 변경 사항은 새로운 Play 출시가 필요합니다. CI에서 빌드하는 경우, Capgo 빌드 서명된 Android 빌드를 생성할 수 있으며, Android keystore 생성기 처음으로 서명을 설정하는 경우 도움이 됩니다.

  6. UI 변경 사항을 OTA로 배포합니다. Once the new native plugin is live, wording and flow tweaks around the picker can go out through Capgo Live Update 사용하기.

다른 연락처 플러그인에서 마이그레이션하기

사용 중이라면 @capacitor-community/contacts (작성 시점 기준 8.0.0), Android의 pickContact 피커를 열기 전 연락처 권한 그룹을 요청한 뒤 주소록에서 전체 연락처를 읽어옵니다. 별도의 property mode는 없으며, 메서드 이름도 다릅니다 ("getContact vs getContactById, projection 객체 vs fields 배열). 저희의 community 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에서 선언 앱에 대해 안내 READ_CONTACTS 선언서 제출 필요
2027년 1월 27일 Android 17 (API 37) 이상 타겟 앱 준수 필수

제출 전 Play Console 도움말 페이지에서 정책을 확인하세요. Google은 마감일과 문구를 변경할 수 있습니다.

Capacitor 앱을 위한 Live Updates

웹 레이어 버그가 라이브 상태일 때, 앱 스토어 승인을 며칠씩 기다리지 말고 Capgo를 통해 수정 사항을 배포하세요. 네이티브 변경 사항은 정상적인 리뷰 절차를 따르는 동안, 사용자는 백그라운드에서 업데이트를 받습니다.

블로그 최신 글

Capgo는 진정한 프로급 모바일 앱을 만드는 데 필요한 최고의 인사이트를 제공합니다.