예약 기능을 붙인 앱에서, 사용자가 예약을 잡고 나면 끝이 아니었다. 그 시간을 기억하려고 다들 캘린더 앱을 따로 열어서 손으로 일정을 옮겨적고 있었다. "캘린더에 추가" 버튼 하나면 될 걸, 그걸 안 넣어서 생긴 번거로움이다.
Expo에선 expo-calendar로 기기 캘린더에 이벤트를 바로 꽂을 수 있다.
설치와 설정
npx expo install expo-calendar
app.json에 플러그인과 권한 설명 문구를 넣는다. iOS는 이 문구가 없으면 심사에서 걸린다.
{
"expo": {
"plugins": [
["expo-calendar", { "calendarPermission": "일정을 캘린더에 저장하기 위해 접근합니다." }]
]
}
}
Expo Go에서도 동작하지만, 플러그인 설정을 반영하려면 dev client로 빌드하는 게 안전하다.
권한과 쓸 수 있는 캘린더 찾기
이벤트를 직접 쓰려면 쓰기 권한과 "수정 가능한" 캘린더가 필요하다. iOS는 기본 캘린더를 바로 주지만, Android는 직접 골라야 한다.
import * as Calendar from 'expo-calendar';
import { Platform } from 'react-native';
async function getWritableCalendarId() {
const { status } = await Calendar.requestCalendarPermissionsAsync();
if (status !== 'granted') return null;
if (Platform.OS === 'ios') {
const def = await Calendar.getDefaultCalendarAsync();
return def.id;
}
// Android: 수정 가능한 캘린더 중 하나 선택
const cals = await Calendar.getCalendarsAsync(Calendar.EntityTypes.EVENT);
const writable = cals.find((c) => c.allowsModifications);
return writable?.id ?? null;
}
이벤트 추가
날짜는 Date 객체로 넘긴다. 알림도 alarms로 같이 걸 수 있다.
async function addReservation() {
const calendarId = await getWritableCalendarId();
if (!calendarId) return;
const start = new Date('2026-11-10T14:00:00');
const end = new Date('2026-11-10T15:00:00');
await Calendar.createEventAsync(calendarId, {
title: '치과 예약',
startDate: start,
endDate: end,
location: '서울시 강남구',
notes: '앱에서 자동 추가됨',
alarms: [{ relativeOffset: -30 }], // 30분 전 알림
});
}
권한 없이 더 간단하게
사실 "그냥 캘린더에 추가만" 하면 되는 경우엔 권한 요청조차 필요 없다. createEventInCalendarAsync는 OS 기본 캘린더 편집 화면을 띄워서, 사용자가 직접 저장을 누르게 한다.
await Calendar.createEventInCalendarAsync({
title: '치과 예약',
startDate: start,
endDate: end,
});
권한 팝업도, 캘린더를 고르는 로직도 없이 네이티브 UI가 뜬다. 사용자가 날짜나 알림을 바꿀 여지도 주고.
정리하면, 앱이 조용히 일정을 넣어주고 싶으면 권한 + createEventAsync, 사용자에게 확인받고 싶으면 createEventInCalendarAsync다. 예약·알림·배송 날짜처럼 "기억해야 할 시간"을 다루는 앱이라면, 이 버튼 하나로 사용자가 손으로 옮겨적는 수고가 사라진다.