Django 서버에서 iOS Push Notification 보내기
Django에서 iOS 푸시 알림 구현하기
📱 Django 백엔드에서 iOS 앱으로 실시간 푸시 알림 보내는 방법 단계별로 알아봄
🎯 개요
이 글에서는 Django 서버에서 Apple Push Notification Service(APNs)를 통해 iOS 기기로 푸시 알림 보내는 방법을 다룸.
사전 준비사항
- Django 프로젝트 환경
- Apple Developer 계정
- APNs 인증 키(.p8 파일) 또는 인증서(.pem 파일)
- iOS 앱에서 푸시 알림 권한 설정 완료
📦 1단계: 필요한 패키지 설치
먼저 Django에서 푸시 알림 처리하기 위한 패키지들 설치함.
pip install django-push-notifications
pip install apns2 # Apple Push Notification Service용
패키지 설명
- django-push-notifications: Django에서 푸시 알림 쉽게 관리할 수 있는 패키지
- apns2: Apple의 HTTP/2 기반 APNs와 통신하기 위한 라이브러리
⚙️ 2단계: Django 설정 구성
settings.py
파일에 푸시 알림 관련 설정 추가함.
# settings.py
INSTALLED_APPS = [
# ... 기존 앱들
'push_notifications',
]
PUSH_NOTIFICATIONS_SETTINGS = {
"APNS_AUTH_KEY_PATH": os.path.join(BASE_DIR, 'AuthKey_KAN8G8U237.p8'),
"APNS_AUTH_KEY_ID": "KAN8G8U237",
"APNS_TEAM_ID": "5QA7Y24MQ4",
"APNS_USE_SANDBOX": True, # 개발용: True, 프로덕션: False
"APNS_TOPIC": "com.yourcompany.yourapp"
}
설정값 설명
- APNS_AUTH_KEY_PATH: APNs 인증 키 파일 경로
- APNS_AUTH_KEY_ID: Apple Developer에서 생성한 키 ID
- APNS_TEAM_ID: Apple Developer Team ID
- APNS_USE_SANDBOX: 개발 환경에서는 True, 프로덕션에서는 False
- APNS_TOPIC: iOS 앱의 Bundle Identifier
📊 3단계: 데이터베이스 마이그레이션
설정 완료한 후 데이터베이스에 푸시 알림 관련 테이블 생성함.
python manage.py migrate
이 명령어 실행하면 push_notifications_apnsdevice
테이블이 생성되어 iOS 기기의 토큰 정보 저장할 수 있음.
📱 4단계: 디바이스 토큰 등록 API 구현
iOS 앱에서 받은 디바이스 토큰을 Django 서버에 등록하는 API 구현함.
views.py 구현
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from push_notifications.models import APNSDevice
class RegisterDeviceView(APIView):
def post(self, request, *args, **kwargs):
token = request.data.get('token')
if not token:
return Response(
{"error": "디바이스 토큰 필요함"},
status=status.HTTP_400_BAD_REQUEST
)
# 기존 토큰이 있는지 확인하고 없으면 새로 생성
device, created = APNSDevice.objects.get_or_create(
registration_id=token,
defaults={'active': True}
)
if created:
message = "디바이스 성공적으로 등록됨"
else:
message = "디바이스 이미 등록되어 있음"
return Response(
{"message": message},
status=status.HTTP_201_CREATED
)
urls.py 설정
# urls.py
from django.urls import path, include
from .views import RegisterDeviceView
urlpatterns = [
path('admin/', admin.site.urls),
path('api/register-device/', RegisterDeviceView.as_view(), name='register-device'),
# ... 기타 URL 패턴들
]
🚀 5단계: 푸시 알림 전송 로직 구현
이제 실제로 푸시 알림 전송하는 로직 구현함.
models.py - 자동 푸시 알림 예제
# models.py
from django.db import models
from push_notifications.models import APNSDevice
class Deal(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
def save(self, *args, **kwargs):
# 모델 저장
super().save(*args, **kwargs)
# 새로운 딜이 생성되면 푸시 알림 전송
self.send_push_notification()
def send_push_notification(self):
"""등록된 모든 iOS 기기에 푸시 알림 전송"""
devices = APNSDevice.objects.filter(active=True)
for device in devices:
try:
device.send_message(
message={
"title": "새로운 딜 알림",
"body": self.title
}
)
except Exception as e:
print(f"푸시 알림 전송 실패: {e}")
수동 푸시 알림 전송 함수
# utils.py 또는 services.py
from push_notifications.models import APNSDevice
def send_custom_notification(title, body, user_ids=None):
"""
커스텀 푸시 알림 전송
Args:
title (str): 알림 제목
body (str): 알림 내용
user_ids (list): 특정 사용자에게만 보낼 경우 사용자 ID 리스트
"""
if user_ids:
# 특정 사용자들에게만 전송
devices = APNSDevice.objects.filter(
user__id__in=user_ids,
active=True
)
else:
# 모든 활성 기기에 전송
devices = APNSDevice.objects.filter(active=True)
success_count = 0
fail_count = 0
for device in devices:
try:
device.send_message(
message={
"title": title,
"body": body
},
extra={
"badge": 1, # 앱 아이콘 배지
"sound": "default" # 알림 소리
}
)
success_count += 1
except Exception as e:
print(f"푸시 알림 전송 실패 - Device: {device.registration_id}, Error: {e}")
fail_count += 1
return {
"success": success_count,
"failed": fail_count,
"total": success_count + fail_count
}
🛠️ 트러블슈팅 및 주의사항
1. ATS(App Transport Security) 설정
iOS 클라이언트에서 로컬 서버로 테스트할 때는 info.plist
에 ATS 설정 필요함.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
2. 인증서 vs 인증 키
- 인증서(.pem): 기존 방식, 만료일이 있음
- 인증 키(.p8): 새로운 방식, 만료되지 않음 (권장)
인증 키 사용할 때는 위에서 보여준 설정 사용하고, 인증서 사용할 때는 다른 설정 필요함.
3. Sandbox vs Production 환경
개발 중에는 반드시 APNS_USE_SANDBOX: True
설정하고, 앱스토어 배포 시에는 False
로 변경해야 함.
4. 디바이스 토큰 관리
디바이스 토큰은 다음과 같은 경우에 변경될 수 있음:
- 앱 재설치
- iOS 업데이트
- 백업에서 복원
따라서 앱 실행 시마다 토큰 확인하고 업데이트하는 로직 필요함.
📊 고급 기능
1. 푸시 알림 분석
# models.py
class PushNotificationLog(models.Model):
device = models.ForeignKey(APNSDevice, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
body = models.TextField()
sent_at = models.DateTimeField(auto_now_add=True)
success = models.BooleanField(default=False)
error_message = models.TextField(blank=True)
def send_notification_with_logging(device, title, body):
log = PushNotificationLog.objects.create(
device=device,
title=title,
body=body
)
try:
device.send_message(message={"title": title, "body": body})
log.success = True
log.save()
except Exception as e:
log.error_message = str(e)
log.save()
raise
2. 배치 전송
대량의 푸시 알림 효율적으로 전송하려면 Celery와 같은 백그라운드 작업 큐 사용하는 것이 좋음.
# tasks.py (Celery 사용 시)
from celery import shared_task
@shared_task
def send_bulk_notifications(title, body, device_ids):
devices = APNSDevice.objects.filter(id__in=device_ids, active=True)
for device in devices:
try:
device.send_message(message={"title": title, "body": body})
except Exception as e:
print(f"Failed to send to {device.registration_id}: {e}")
🔗 참고 자료
📝 마무리
Django에서 iOS 푸시 알림 구현하는 과정 단계별로 살펴봤음. 핵심은 올바른 APNs 설정과 디바이스 토큰 관리임.
실제 프로덕션 환경에서는 다음 사항들도 고려해야 함:
- 푸시 알림 성능 모니터링
- 실패한 토큰 정리
- 사용자별 알림 설정 관리
- 알림 내용 개인화