본문 바로가기

Capacitor Community Contacts 대안

@capacitor-community/contacts 플러그인의 대안: 연락처, 그룹, 페이지네이션 및 권한 없는 선택 기능을 지원하며, 전체 마이그레이션 가이드를 포함합니다.

Capacitor contacts 플러그인 비교를 위한 Capgo 플러그인 예시

Capacitor 커뮤니티 contacts 대안이 필요하다면, 가장 완벽한 드롭인 교체 방식은 @capgo/capacitor-contacts입니다. 이 플러그인은 @capacitor-community/contacts 기능(연락처 읽기, 생성, 삭제 및 선택)을 모두 지원하며, ID 변경 없이 연락처를 업데이트하는 기능, 페이지네이션, 그룹, 계정, 네이티브 연락처 화면, 그리고 2027년 Google Play 연락처 정책에 중요한 Android 권한 없는 연락처 선택 기능까지 추가되었습니다. 이 가이드는 두 플러그인을 비교하고 모든 호출 방식을 매핑하여 오후 한나절 만에 마이그레이션을 마칠 수 있도록 도와줍니다.

왜 대안을 찾아야 할까요?

@capacitor-community/contacts 는 지속적으로 관리되고 있으며 Capacitor 8 버전이 출시되었습니다. 단순한 읽기 및 생성 흐름에는 좋은 선택입니다. 하지만 팀이 성장함에 따라 보통 다음과 같은 이유로 한계를 느끼게 됩니다:

  • 업데이트 메서드 부재. 연락처를 생성하고 삭제할 수는 있지만, 수정할 수는 없습니다. 삭제 후 다시 생성하면 연락처 ID가 바뀌어 기존에 저장된 참조가 깨지고, 플러그인이 읽지 못하는 데이터가 손실될 수 있습니다.
  • 페이지네이션 미지원. getContacts 는 한 번의 호출로 전체 주소록을 가져옵니다. 연락처와 사진이 5,000개 있는 기기에서는 속도가 느리고 메모리 사용량이 매우 높습니다.
  • Android에서 선택하려면 권한이 필요합니다. Android는 pickContact 피커를 열기 전에 연락처 권한 그룹을 요청한 뒤 주소록에서 연락처를 읽어옵니다. Google Play 연락처 권한 정책에 따라Android 17을 타겟팅하는 앱은 핵심 기능을 위해서만 READ_CONTACTS 권한을 유지할 수 있습니다.
  • 그룹, 계정 또는 네이티브 화면은 지원하지 않습니다. 그룹을 나열하거나, 새 연락처가 저장될 계정을 선택하거나, 시스템 “새 연락처” 양식을 열 수 없습니다.

기능 비교

기능 @capacitor-community/contacts 8.0 @capgo/capacitor-contacts 8.1
연락처 하나 또는 전체 읽기 getContact, getContacts getContactById, getContacts
필드 선택 projection 객체 fields 배열
페이지네이션 아니요 limit, offset
연락처 개수 세기 아니요 countContacts
생성 createContact createContact
기존 항목 업데이트 아니요 updateContactById
삭제 deleteContact deleteContactById
연락처 하나 선택 pickContact pickContact
여러 개 선택 아니요 pickContacts({ multiple: true })
권한 없이 전화번호/이메일/주소 하나 선택 아니요 pickContacts({ property })
그룹 아니요 getGroups, getGroupById, createGroup, deleteGroupById
계정 아니요 getAccounts
네이티브 생성 / 조회 / 편집 화면 아니요 displayCreateContact, displayContactById, displayUpdateContactById
읽기 및 쓰기 권한 상태 분리 아니요 (단일 별칭) readContacts, writeContacts
iOS 제한적 접근 상태 limited limited
설정 열기 아니요 openSettings

설치

bun add @capgo/capacitor-contacts
bunx cap sync

이 플러그인은 Android manifest에 권한을 자동으로 추가하지 않습니다. 사용하는 권한만 직접 추가하세요:

<!-- Needed for getContacts, getContactById, countContacts, groups, accounts -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<!-- Needed for createContact, updateContactById, deleteContactById, groups writes -->
<uses-permission android:name="android.permission.WRITE_CONTACTS" />

iOS의 경우, 다음을 추가하세요 NSContactsUsageDescription 대상 Info.plist 주소록을 읽거나 쓰는 경우에만 필요합니다. 연락처 선택(Picking) 시에는 필요하지 않습니다.

단계별 마이그레이션 가이드

권한

// Before
import { Contacts } from '@capacitor-community/contacts';
const perm = await Contacts.requestPermissions();
if (perm.contacts !== 'granted') return;

// After
import { CapacitorContacts } from '@capgo/capacitor-contacts';
const status = await CapacitorContacts.requestPermissions({ permissions: ['readContacts'] });
if (status.readContacts !== 'granted' && status.readContacts !== 'limited') {
  await CapacitorContacts.openSettings();
  return;
}

iOS 18 이상에서는 사용자가 연락처의 일부에만 접근 권한을 부여할 수 있습니다. 플러그인은 이를 다음과 같이 보고합니다: limited. 이를 당연하게 여기고 공유된 연락처만 기대하세요.

모든 연락처 읽기

// Before: whole address book, projection object
const { contacts } = await Contacts.getContacts({
  projection: { name: true, phones: true, emails: true },
});
const first = contacts[0];
console.log(first.name?.display, first.phones?.[0]?.number);

// After: fields array, paginated
const pageSize = 200;
let offset = 0;
for (;;) {
  const { contacts } = await CapacitorContacts.getContacts({
    fields: ['displayName', 'givenName', 'familyName', 'phoneNumbers', 'emailAddresses'],
    limit: pageSize,
    offset,
  });
  render(contacts);
  if (contacts.length < pageSize) break;
  offset += pageSize;
}

declare function render(list: unknown[]): void;

사용 countContacts() 진행 표시줄을 보여주고 싶다면 먼저 실행하세요.

연락처 하나 읽기

// Before
const { contact } = await Contacts.getContact({
  contactId: id,
  projection: { name: true, phones: true },
});

// After
const { contact } = await CapacitorContacts.getContactById({
  id,
  fields: ['displayName', 'phoneNumbers'],
});
if (!contact) console.log('Not found');

연락처 생성

// Before
const { contactId } = await Contacts.createContact({
  contact: {
    name: { given: 'Ada', family: 'Lovelace' },
    phones: [{ type: PhoneType.Mobile, number: '+44 20 7946 0000' }],
    emails: [{ type: EmailType.Work, address: 'ada@example.com' }],
  },
});

// After
const { id } = await CapacitorContacts.createContact({
  contact: {
    givenName: 'Ada',
    familyName: 'Lovelace',
    phoneNumbers: [{ type: 'MOBILE', value: '+44 20 7946 0000' }],
    emailAddresses: [{ type: 'WORK', value: 'ada@example.com' }],
  },
});

displayName Capgo 플러그인에서는 읽기 전용입니다. 쓰기 givenName 및 familyName, 하면 디바이스가 표시 이름을 포맷합니다.

연락처 업데이트 (신규)

await CapacitorContacts.updateContactById({
  id,
  contact: {
    givenName: 'Ada',
    familyName: 'King',
    jobTitle: 'Analyst',
    phoneNumbers: [{ type: 'MOBILE', value: '+44 20 7946 0000' }],
  },
});

ID는 그대로 유지되므로 저장된 참조가 여전히 유효합니다. 실수로 데이터를 지우지 않도록 먼저 연락처를 읽은 뒤 유지할 필드들을 다시 보내세요.

사용자가 직접 편집하게 하려면 시스템 에디터를 여세요:

await CapacitorContacts.displayUpdateContactById({ id });

연락처 삭제

// Before
await Contacts.deleteContact({ contactId: id });

// After
await CapacitorContacts.deleteContactById({ id });

연락처 선택

// Before: requests the contacts permission on Android first
const { contact } = await Contacts.pickContact({
  projection: { name: true, phones: true },
});

// After: one phone number, no permission on Android or iOS
import { ContactProperty } from '@capgo/capacitor-contacts';

const { contacts } = await CapacitorContacts.pickContacts({
  property: ContactProperty.PhoneNumber,
});
const phone = contacts[0]?.phoneNumbers?.[0]?.value;

피커에서 전체 연락처 레코드가 필요한 경우 다음을 호출하세요 pickContact() 없이 property. Android에서는 다음 권한이 부여된 경우에만 READ_CONTACTS 전체 연락처를 반환합니다.

필드 매핑

Community 페이로드 Capgo Contact
contactId id
name.display displayName (읽기 전용)
name.given / middle / family givenName / middleName / familyName
name.prefix / suffix namePrefix / nameSuffix
organization.company organizationName
organization.jobTitle jobTitle
birthday { day, month, year } birthday { day, month, year }
note note
phones[].number phoneNumbers[].value
emails[].address emailAddresses[].value
urls[] (문자열) urlAddresses[].value
postalAddresses[].region / postcode postalAddresses[].state / postalCode
image.base64String photo (base64 문자열)

값의 타입도 변경됩니다. Capgo 플러그인은 다음과 같이 대문자 문자열을 사용합니다: 'MOBILE', 'HOME', 'WORK' 전화번호 및 이메일의 경우.

한 번에 하나의 화면씩 마이그레이션하세요

두 플러그인은 서로 다른 네이티브 이름으로 등록되어 있어 (Contacts 및 CapacitorContacts), 호출부를 옮기는 동안 함께 설치할 수 있습니다. 간단한 어댑터를 사용하면 앱의 나머지 부분은 변경할 필요가 없습니다:

import { CapacitorContacts } from '@capgo/capacitor-contacts';

export interface AppContact {
  id: string;
  name: string;
  phones: string[];
}

export async function listContacts(limit = 200, offset = 0): Promise<AppContact[]> {
  const { contacts } = await CapacitorContacts.getContacts({
    fields: ['displayName', 'phoneNumbers'],
    limit,
    offset,
  });
  return contacts.map((c) => ({
    id: c.id ?? '',
    name: c.displayName ?? '',
    phones: (c.phoneNumbers ?? []).map((p) => p.value),
  }));
}

마지막 호출부까지 모두 옮겼다면, 커뮤니티 플러그인을 제거하고 bunx cap sync를 실행한 뒤, 병합된 Android manifest를 확인하여 필요한 권한만 남아 있는지 확인하세요.

문제 해결

getContacts iOS에서는 빈 리스트를 반환합니다. 사용자가 제한된 액세스 권한을 부여하여 연락처를 공유하지 않았거나, 액세스를 거부했습니다. readContacts 를 확인하고 openSettings().

Android의 특정 계정에서 생성된 연락처가 표시되지 않는 문제. 다음 항목을 전달하세요: account ( getAccounts())를

사진 때문에 목록 로딩이 느려집니다. 요청하지 마세요 photo 목록 뷰에서는. 다음을 사용해 로드하세요 getContactById 사용자가 연락처를 열 때.

Play Console 경고 READ_CONTACTS. 초대 및 공유 흐름을 pickContacts({ property }) 로 옮기고, 다른 곳에서 필요하지 않다면 권한을 제거하세요.

배포하기

플러그인 교체는 네이티브 변경이므로 스토어 빌드가 필요합니다. Capgo 빌드 클라우드에서 iOS 및 Android 빌드를 생성할 수 있습니다. 그 이후 연락처 화면 수정은 JavaScript이므로 함께 배포할 수 있습니다 Capgo Live Update 사용하기. 전체 API은 다음에 있습니다 contacts 플러그인 문서.

Capacitor 앱용 Live updates

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

블로그 최신 글

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