Device Token은 APNS가 푸시 알림을 라우팅하기 위해 각 iOS 장치에 할당하는 고유 식별자입니다. 토큰은 앱이 알림 수신을 위해 등록할 때 시스템에 의해 생성되며, 이 장치에 푸시를 보내기 위해 서버로 전송되어야 합니다. Apple Developer Documentation, 2026에 따르면, Device Token은 앱 재설치, 백업에서 장치 복원 또는 iOS 업데이트 시 변경될 수 있으므로, 서버는 전달을 보장하기 위해 정기적으로 토큰을 업데이트해야 합니다.
핵심 사항
Device Token(장치 토큰)은 APNS(Apple Push Notification Service)가 iOS 장치의 각 앱에 대해 생성하는 16진수 문자열 형태의 고유 식별자입니다. 토큰은 서버가 특정 장치에 푸시 알림을 보내는 키입니다. 유효한 Device Token이 없으면 서버는 푸시 알림을 전달할 수 없습니다 — APNS가 400 BadRequest 오류와 함께 요청을 거부합니다.
Device Token은 설치 후 앱이 처음으로 APNS에 연락할 때 iOS 시스템에 의해 생성됩니다. 생성 프로세스에는 앱의 Bundle ID와 장치의 고유 식별자(UID)에 대한 암호화 바인딩이 포함되며, 이후 APNS는 앱에 16진수 형식(64자)의 32바이트 토큰을 반환합니다. 토큰은 영구적이지 않습니다 — 시스템은 특정 조건에서 새 토큰을 생성할 수 있습니다.
서버가 푸시 알림을 보낼 때, APNS에 대한 HTTP/2 요청에 Device Token을 포함합니다. APNS는 토큰을 검증합니다: 토큰이 다른 환경(프로덕션 대신 샌드박스)에 속하거나, 만료되었거나, 취소된 경우 Apple 서버는 410 Gone 또는 400 BadRequest 오류를 반환합니다. 토큰 검증이 성공한 후에만 APNS가 장치로 알림 전달을 시작합니다.
Device Token은 IDFA(광고주 식별자), IDFV(벤더 식별자) 또는 UID(고유 장치 식별자)와 혼동해서는 안 됩니다. IDFA 및 IDFV는 광고 및 분석에 사용되며, UID는 하드웨어 일련 번호입니다. Device Token은 푸시 알림 전용으로 존재하며 APNS 외부에서 사용자 또는 장치에 대한 정보를 공개하지 않습니다.
| 식별자 | 목적 | 영구성 |
|---|---|---|
| Device Token | APNS 푸시 알림 라우팅 | 변경될 수 있음 |
| IDFA | 광고 및 추적 | 사용자가 재설정 가능 |
| IDFV | 벤더 식별(분석) | 동일 개발자의 앱에 대해 영구적 |
| Bundle ID | 고유 앱 식별자 | 영구적 |
Device Token을 얻는 프로세스는 사용자에게 권한을 요청하는 것부터 서버에 토큰을 전송하는 것까지 여러 필수 단계로 구성됩니다. 각 단계는 중요합니다 — 단계를 건너뛰면 장치에 푸시 알림을 보낼 수 없게 됩니다.
첫 번째 단계는 앱이 UNUserNotificationCenter.current().requestAuthorization을 통해 사용자에게 알림 전송 권한을 요청하는 것입니다. 사용자는 동의하거나, 거부하거나, 선택적 옵션(alert, badge, sound)을 선택할 수 있습니다. 명시적인 사용자 동의 없이는 앱이 registerForRemoteNotifications를 호출하더라도 시스템이 Device Token을 발급하지 않습니다. 권한을 얻은 후 앱은 UIApplication.shared.registerForRemoteNotifications()를 호출하여 APNS 등록 프로세스를 시작합니다.
등록 후 APNS는 AppDelegate를 통해 토큰을 반환합니다: application(_:didRegisterForRemoteNotificationsWithDeviceToken:). 성공적인 호출에는 토큰이 포함된 Data 객체가 포함되며, 서버로 전송하기 위해 16진수 문자열로 변환해야 합니다. 오류가 발생하면 시스템은 문제 설명과 함께 application(_:didFailToRegisterForRemoteNotificationsWithError:)를 호출합니다: 잘못된 인증서 구성, 네트워크 사용 불가 또는 잘못된 프로젝트 구성.
토큰을 받은 후 앱은 데이터베이스에 저장하기 위해 즉시 자체 서버로 보내야 합니다. API 요청에는 토큰, 장치 식별자(매핑용), 환경(sandbox/production), 선택적으로 추가 데이터(OS 버전, 장치 모델, 언어)가 포함됩니다. 서버가 항상 최신 토큰을 가지고 있도록 앱 시작 시마다 토큰을 다시 보내는 것이 좋습니다.
// 권한 요청 및 APNS 등록
func registerForPushNotifications() {
UNUserNotificationCenter.current()
.requestAuthorization(options: [.alert, .sound, .badge]) {
[weak self] granted, error in
guard granted else {
print("권한이 부여되지 않음")
return
}
DispatchQueue.main.async {
UIApplication.shared
.registerForRemoteNotifications()
}
}
}
// APNS에서 Device Token 받기
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
let tokenString = deviceToken
.map { String(format: "%02.2hhx", $0) }
.joined()
print("Device Token: \(tokenString)")
// 서버에 토큰 보내기
PushTokenService.shared
.sendTokenToServer(tokenString) { success in
if success {
UserDefaults.standard.set(tokenString,
forKey: "lastDeviceToken")
}
}
}
푸시 시스템의 서버 측은 Device Token을 데이터베이스에 저장하고 사용자 및 환경과 연결해야 합니다. 알림을 보낼 때 서버는 APNS에 요청을 구성하며, URL에 토큰과 인증을 위한 JWT 토큰(또는 인증서)을 포함합니다. 올바른 토큰 관리는 푸시 알림 전달률에 중요한 영향을 미칩니다.
서버의 토큰 테이블에는 최소한 Device Token(고유), 사용자 ID, 환경(sandbox/production), 마지막 업데이트 날짜, 상태(활성/비활성)가 포함되어야 합니다. 전송 시 빠른 검색을 위해 토큰에, 사용자의 모든 장치 목록을 가져오기 위해 사용자에 인덱스를 추가하는 것이 좋습니다. 많은 앱에서 한 사용자가 여러 장치를 가질 수 있으며, 각각 고유한 토큰을 가집니다.
푸시 알림을 보내려면 서버가 두 가지 방법으로 APNS에 요청을 인증해야 합니다. 인증서 기반은 Apple Developer Console에서 생성된 SSL 인증서를 사용합니다. 토큰 기반은 .p8 키가 있는 JWT(JSON Web Token)를 사용하며, 인증서 갱신 없이 최대 30일 동안 유효합니다. 토큰 기반 인증이 더 현대적이며 Apple이 새 프로젝트에 권장합니다.
APNS에 대한 요청에는 HTTP/2 POST 메서드, 경로 /3/device/{device_token}이 포함된 URL, 인증 헤더 및 페이로드가 포함된 JSON 본문이 포함됩니다. apns-topic 헤더에는 앱의 Bundle ID가 포함되어야 합니다. apns-priority는 전달 우선순위를 나타냅니다(5 — 즉시, 10 — 배터리 절약). apns-expiration은 APNS가 알림 전달을 시도할 에포크 이후의 시간(초)을 설정합니다.
// APNS HTTP/2를 통해 Node.js에서 푸시 전송 예제
const http2 = require('http2');
const client = http2.connect('https://api.push.apple.com');
const deviceToken = 'abcdef0123456789...';
const payload = JSON.stringify({
"aps": { "alert": "Hello!", "sound": "default" }
});
const req = client.request({
':method': 'POST',
':path': `/3/device/${deviceToken}`,
'apns-topic': 'com.example.app',
'apns-priority': '10',
'apns-expiration': '0',
'authorization': `bearer ${jwtToken}`
});
req.write(payload);
req.end();
req.on('response', (headers) => {
if (headers[':status'] === '200') {
console.log('푸시가 성공적으로 전송되었습니다');
}
});
많은 수의 장치에 푸시 알림을 보낼 때는 속도 제어와 함께 일괄 전송을 사용합니다. APNS는 연결당 초당 1500개를 초과하지 않도록 권장합니다. 제한을 초과하면 Apple 서버가 429 Too Many Requests 오류를 반환합니다. 대규모 캠페인의 경우 여러 연결을 사용하고 장치 간에 부하를 균등하게 분산합니다.
Device Token은 영구적이지 않으며 여러 시나리오에서 변경될 수 있으므로 서버에 업데이트 메커니즘이 필요합니다. 서버가 오래된 토큰으로 계속 푸시를 보내면 APNS는 410 Gone 오류를 반환하여 해당 환경에서 토큰이 더 이상 유효하지 않음을 나타냅니다.
Apple은 Device Token이 변경되는 여러 시나리오를 문서화합니다: 사용자가 앱을 재설치하고, iCloud 백업에서 장치를 복원하고, 새 iOS 버전을 설치하거나, 네트워크 또는 개인정보 보호 설정을 재설정하는 경우입니다. 각 경우에 앱은 다음 시작 시 APNS에서 새 토큰을 받습니다. 서버는 데이터베이스의 토큰을 업데이트하고, 이전 토큰을 제거하고 새 토큰을 저장해야 합니다.
서버가 오래된 토큰으로 푸시를 보내면 APNS는 apns-unless-timestamp 헤더와 함께 HTTP 410을 반환합니다. 이 헤더는 토큰이 무효화된 시간을 나타냅니다. 서버는 데이터베이스에서 이 토큰을 즉시 삭제하거나 비활성화하여 다시 보내지 않도록 해야 합니다. 410 오류를 무시하면 리소스가 낭비되고 전달 가능률이 감소합니다.
토큰 데이터베이스를 최신 상태로 유지하려면 정기적인 정리를 실행하는 것이 좋습니다. 정리 스크립트는 지난 N일 간의 APNS 로그를 분석하고 410 오류를 받은 모든 토큰을 찾아 데이터베이스에서 비활성화합니다. 또한 90일 이상 사용자 활동이 없는 토큰은 제거할 수 있습니다 — 이는 데이터베이스 크기만 증가시키는 쓸모없는 레코드입니다.
푸시 알림(뉴스레터, 프로모션 캠페인)을 대량 전송하기 전에 토큰을 사전 검증하는 것이 좋습니다. APNS는 일괄 토큰 검증을 위한 직접 API를 제공하지 않으므로, 낮은 우선순위로 테스트 푸시를 보내고 오류를 분석하는 전략이 사용됩니다. 410 오류를 반환하는 토큰은 기본 전송에서 제외됩니다.
Swift에서 Device Token을 얻는 전체 사이클을 오류 처리 및 서버 전송을 포함하여 살펴보겠습니다. 코드는 다음을 다룹니다: 권한 요청, APNS 등록, Data를 16진수 문자열로 변환, 오류 처리, 실패 시 재시도를 포함한 자체 서버로의 토큰 전송.
import UIKit
import UserNotifications
final class PushNotificationManager: NSObject {
static let shared = PushNotificationManager()
private let apiClient = APIClient()
private var currentToken: String?
func register() {
UNUserNotificationCenter.current()
.requestAuthorization(
options: [.alert, .badge, .sound]) {
[weak self] granted, error in
guard granted else {
Analytics.log(
"Push permission denied")
return
}
DispatchQueue.main.async {
UIApplication.shared
.registerForRemoteNotifications()
}
}
}
func handleDeviceToken(_ tokenData: Data) {
let token = tokenData
.map { String(format: "%02.2hhx", $0) }
.joined()
guard token != currentToken else { return }
currentToken = token
sendTokenToServer(token)
}
func handleRegistrationError(_ error: Error) {
Analytics.log(
"Push registration failed: \(error)")
// 네트워크 오류 시 지연 후 재시도
if let urlError = error as? URLError,
urlError.code == .notConnectedToInternet {
DispatchQueue.main.asyncAfter(
deadline: .now() + 10) { [weak self] in
self?.register()
}
}
}
private func sendTokenToServer(_ token: String) {
let body = PushTokenRequest(
token: token,
environment: Environment.current == .debug
? "sandbox" : "production",
osVersion: UIDevice.current.systemVersion,
locale: Locale.current.identifier
)
apiClient.sendToken(body) { [weak self] result in
if case .success = result {
self?.currentToken = token
}
}
}
}
APNS 등록 중 오류는 다양한 원인으로 발생할 수 있습니다. 가장 일반적인 원인으로는 네트워크 사용 불가, Xcode의 잘못된 인증서 구성(예: Push Notifications 기능 비활성화), 시뮬레이터 사용(푸시를 지원하지 않음), 또는 잘못된 프로비저닝 프로필이 있습니다. 프로덕션에서는 오류를 기록하고 가능하면 다음 앱 시작 시 등록을 재시도하는 것이 중요합니다.
iOS 시뮬레이터는 실제 Device Token 수신을 지원하지 않습니다. 시뮬레이터에서 등록 테스트를 위해 i386 아키텍처 검사를 사용합니다. 디버그 빌드에서는 토큰 수신을 시뮬레이션하거나 모의 객체를 사용한 UI 테스트를 사용할 수 있습니다. 실제 푸시 알림 테스트는 항상 Xcode에 연결된 실제 장치에서 수행됩니다.
자주 묻는 질문
네, Device Token은 앱 재설치, 백업에서 장치 복원 또는 iOS 업데이트 시 변경될 수 있습니다. 서버는 토큰 업데이트를 처리해야 합니다: 알려진 장치에서 새 토큰을 받으면 이전 토큰을 교체하고, 410 오류가 발생하면 데이터베이스에서 토큰을 제거합니다.
Device Token은 소문자(0–9, a–f)의 64자 32바이트 16진수 문자열입니다. 예: “a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2”. 토큰은 APNS에서 Data로 전달되며 앱 측에서 문자열로 변환됩니다.
샌드박스 토큰은 개발 프로비저닝 프로필로 빌드된 앱에 발급되며 api.sandbox.push.apple.com에서만 작동합니다. 프로덕션 토큰은 App Store 및 TestFlight용이며 api.push.apple.com에서 작동합니다. 서버는 환경을 구분하고 적절한 APNS 엔드포인트로 푸시를 보내야 합니다.
410 Gone 오류는 Device Token이 유효하지 않음을 의미합니다. 서버는 데이터베이스에서 이 토큰을 즉시 제거하고 전송 시도를 중단해야 합니다. 응답의 apns-unless-timestamp 헤더는 토큰이 작동을 중단한 시간을 나타냅니다.
AppDelegate의 델리게이트 메서드 application(_:didRegisterForRemoteNotificationsWithDeviceToken:)를 확인합니다. 메서드가 호출되면 토큰이 수신된 것입니다. 디버깅 로그 또는 OSLog를 사용하여 Xcode 콘솔에 토큰을 출력합니다. 실제 장치에서 Network Link Conditioner를 사용하여 토큰이 서버로 전송되고 있는지 확인합니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.