본문으로 건너뛰기

푸시 (Push)

iOS(APNS), Android(FCM), Web Push를 지원하는 통합 푸시 알림 API입니다.


디바이스 등록

iOS/Android 디바이스 등록

typescript
// iOS 디바이스 등록 (APNS)
const device = await cb.push.registerDevice({
  device_token: 'apns-device-token-here',
  platform: 'ios',
  device_name: 'iPhone 15 Pro',
  device_model: 'iPhone15,2',
  os_version: '17.0',
  app_version: '1.0.0',
  language: 'ko',
  timezone: 'Asia/Seoul'
})

// Android 디바이스 등록 (FCM)
const device = await cb.push.registerDevice({
  device_token: 'fcm-registration-token-here',
  platform: 'android',
  device_name: 'Galaxy S24',
  device_model: 'SM-S928N',
  os_version: '14',
  app_version: '1.0.0'
})

파라미터

필드타입필수설명
device_tokenstringAPNS/FCM 토큰
platform'ios' | 'android' | 'web'디바이스 플랫폼
device_idstring디바이스 고유 ID
device_namestring디바이스 이름
device_modelstring디바이스 모델
os_versionstringOS 버전
app_versionstring앱 버전
languagestring언어 코드 (예: "ko")
timezonestring타임존 (예: "Asia/Seoul")

디바이스 관리

typescript
// 디바이스 등록 해제 (등록 시 사용한 device_token 그대로 전달)
await cb.push.unregisterDevice('apns-or-fcm-device-token')

📌 SDK는 getDevices() / getSubscribedTopics() 메서드를 제공하지 않습니다. 디바이스/토픽 목록은 콘솔이나 REST API 를 사용하세요.


토픽 구독

토픽을 사용하면 특정 그룹에만 푸시 알림을 보낼 수 있습니다. 디바이스 단위로 구독합니다.

typescript
const deviceToken = 'apns-or-fcm-device-token'

// 토픽 구독
await cb.push.subscribeTopic(deviceToken, 'announcements')
await cb.push.subscribeTopic(deviceToken, 'marketing')

// 토픽 구독 해제
await cb.push.unsubscribeTopic(deviceToken, 'marketing')

Web Push (브라우저 푸시)

브라우저에서 푸시 알림을 받으려면 Service Worker와 VAPID 키를 사용합니다.

VAPID 키 조회 및 구독 등록

typescript
// 1. VAPID 공개키 조회
const vapidKey = await cb.push.getVAPIDPublicKey()

// 2. Service Worker 등록 및 Push 구독
const registration = await navigator.serviceWorker.register('/sw.js')
await navigator.serviceWorker.ready

const permission = await Notification.requestPermission()
if (permission === 'granted') {
  const subscription = await registration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: urlBase64ToUint8Array(vapidKey.public_key)
  })

  // 3. Connect Base에 구독 정보 등록
  await cb.push.registerWebPush(subscription)
  console.log('Web Push 등록 완료!')
}

Web Push 구독 해제

typescript
// 등록 시 받은 device_token 을 그대로 전달
await cb.push.unregisterWebPush(deviceToken)

Base64 변환 헬퍼 함수

typescript
function urlBase64ToUint8Array(base64String: string): Uint8Array {
  const padding = '='.repeat((4 - base64String.length % 4) % 4)
  const base64 = (base64String + padding)
    .replace(/-/g, '+')
    .replace(/_/g, '/')

  const rawData = window.atob(base64)
  const outputArray = new Uint8Array(rawData.length)

  for (let i = 0; i < rawData.length; ++i) {
    outputArray[i] = rawData.charCodeAt(i)
  }
  return outputArray
}

Service Worker 예제

javascript
// sw.js
self.addEventListener('push', (event) => {
  const data = event.data?.json() || {}

  const options = {
    body: data.body || '새 알림이 있습니다',
    icon: data.icon || '/icon-192.png',
    badge: data.badge || '/badge-72.png',
    image: data.image,
    data: data.data,
    actions: data.actions || []
  }

  event.waitUntil(
    self.registration.showNotification(data.title || '알림', options)
  )
})

// 알림 클릭 처리
self.addEventListener('notificationclick', (event) => {
  event.notification.close()

  const url = event.notification.data?.url || '/'
  event.waitUntil(clients.openWindow(url))
})

API 레퍼런스

메서드설명반환 타입
registerDevice(request)디바이스 등록Promise<DeviceInfo>
unregisterDevice(deviceToken)디바이스 해제Promise<void>
subscribeTopic(deviceToken, topicName)토픽 구독Promise<void>
unsubscribeTopic(deviceToken, topicName)토픽 구독 해제Promise<void>
getVAPIDPublicKey()VAPID 공개키 조회Promise<VAPIDPublicKeyResponse>
registerWebPush(subscription)Web Push 등록Promise<DeviceInfo>
unregisterWebPush(deviceToken)Web Push 해제Promise<void>

DeviceInfo 응답 타입

typescript
interface DeviceInfo {
  id: string                // 디바이스 고유 ID
  device_token: string      // APNS/FCM/Web Push 토큰
  platform: 'ios' | 'android' | 'web'
  device_id?: string        // 사용자 지정 디바이스 ID
  device_name?: string      // 디바이스 이름
  device_model?: string     // 디바이스 모델
  os_version?: string       // OS 버전
  app_version?: string      // 앱 버전
  language?: string         // 언어
  timezone?: string         // 타임존
  is_active: boolean        // 활성 상태
  last_active_at?: string   // 마지막 활성 시간
  created_at: string        // 등록 시간
  updated_at: string        // 수정 시간
}