유니티에 Firebase Cloud Messaging으로 push notifications 구현하기
- 개요
- Firebase 설정
- 스크립트 작성
- 테스트용 알림 전송하는 기능 만들기
- Android 기기에서 테스트
- Android 알림 권한 요청하기
- Android 헤드업 알림 보내기
- iOS 관련 사항
- iOS: Firebase와 APNs 연결하기
- iOS: 푸시 알림 사용 설정
- 기타 iOS 관련 사항들
개요
이번에는 Firebase Cloud Messaging을 활용해서 push notifications을 구현할 것이다.
Firebase 설정
먼저 Firebase console에 들어가서 새 프로젝트를 만들고 유니티 앱을 추가한다. 여기서는 유니티 앱을 만들 때 Android와 iOS를 모두 선택하는 것으로 했다.
앱을 추가하는 과정에 해야 할 일이 단계별로 잘 설명되어 있고, 필요하다면 공식 문서도 참고하면 어렵지 않게 진행할 수 있다.
스크립트 작성
using System.Linq;
using UnityEngine;
using Firebase;
using Firebase.Messaging;
public class TestScript : MonoBehaviour
{
private void Awake()
{
InitializeFcm();
}
private async void InitializeFcm()
{
DependencyStatus dependencyStatus = await FirebaseApp.CheckAndFixDependenciesAsync();
if (dependencyStatus != DependencyStatus.Available)
{
return;
}
string token = await FirebaseMessaging.GetTokenAsync();
FirebaseMessaging.TokenReceived += OnTokenReceived;
FirebaseMessaging.MessageReceived += OnMessageReceived;
}
private void OnTokenReceived(object sender, TokenReceivedEventArgs token)
{
Debug.Log("Received Registration Token: " + token.Token);
}
private void OnMessageReceived(object sender, MessageReceivedEventArgs e)
{
string data = string.Join(", ", e.Message.Data.Select((pair) => $"{pair.Key}:{pair.Value}"));
Debug.Log($"title={e.Message.Notification.Title}, body={e.Message.Notification.Body} data={data}");
}
}
가장 먼저 FirebaseApp.CheckAndFixDependenciesAsync()
를 호출해서 Firebase를 초기화한다. 그 후에 FirebaseMessaging.TokenReceived
이벤트와 FirebaseMessaging.MessageReceived
이벤트를 등록하면 끝이다. FirebaseMessaging.TokenReceived
이벤트는 처음 토큰을 발급받을 때 1회만 실행되고 앱을 재실행하는 경우 해당 이벤트가 발생하지 않는다. 따라서 토큰을 따로 캐싱해 두거나 FirebaseMessaging.GetTokenAsync()
함수를 통해 토큰을 직접 가져올 수 있다.
테스트용 알림 전송하는 기능 만들기
테스트를 하기 위해 우리가 직접 알림을 전송할 수 있어야 한다. 여기서는 python을 사용하였다. (참고)
pip를 통해 Firebase Admin Python SDK를 설치한다. python 가상환경을 사용하는 것을 추천한다.
$ sudo pip install firebase-admin
Firebase console의 프로젝트 설정에서 서비스 계정에 들어간 후 “새 비공개 키 생성”을 클릭하여 키 파일을 다운로드 받는다. 다음의 python 스크립트에서 해당 파일을 사용할 것이다.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import messaging
cred = credentials.Certificate("your-key-file.json")
firebase_admin.initialize_app(cred)
client_token = 'your-client-token'
message = messaging.Message(
notification=messaging.Notification(
title='my title',
body='my body',
),
data={
'key1': 'value1',
'key2': 'value2',
'key3': 'value3',
},
token=client_token,
)
response = messaging.send(message)
이 스크립트에서 your-key-file.json
부분은 앞서 다운로드 받은 키 파일의 경로를, your-client-token
은 앞의 유니티 프로젝트를 안드로이드나 iOS에서 실행하여 로그로 출력된 토큰을 입력하면 된다.
Android 기기에서 테스트
이제 Android 기기에서 바로 테스트해볼 수 있다. 토큰을 설정한 후 알림 전송 스크립트를 실행하면 아래와 같이 알림 수신 로그가 잘 출력되는 것을 확인할 수 있다.
title=my title, body=my body data=key1:value1, key2:value2, key3:value3
Android 알림 권한 요청하기
Android 13 버전(API 33) 이후부터는 알림 권한을 요청하지 않은 경우 기본적으로 알림이 차단된다. 따라서 앱이 실행중이 아닐 때 알림을 상태표시줄에 표시하도록 하기 위해서는 알림 권한을 요청해야 한다.
프로젝트 세팅에서 Android Target API Level이 33 이상인 경우 다음과 같이 스크립트에서 알림 권한을 요청할 수 있다.
public void RequestPermission(Action<bool> callback)
{
PermissionCallbacks permissionCallbacks = new PermissionCallbacks();
permissionCallbacks.PermissionDenied += (string msg) => callback(false);
permissionCallbacks.PermissionDeniedAndDontAskAgain += (string msg) => callback(false);
permissionCallbacks.PermissionGranted += (string msg) => callback(true);
Permission.RequestUserPermission("android.permission.POST_NOTIFICATIONS", permissionCallbacks);
}
만약 API 33 미만을 타게팅해야 하는 경우 약간 복잡해진다. Android 13 이상이 탑재된 기기에서는 API 33 미만을 타게팅해서 빌드된 앱이 알림 관련해서 설정하는 코드를 실행하면 OS가 자동으로 알림 권한을 사용자에게 요청해준다. 이 기능을 사용해서 알림 권한을 요청하는 기능을 구현할 것이다.
우선 유니티 공식 패키지 중 하나인 Mobile Notifications package를 추가해야 한다. 어차피 다음 장에서 Android 헤드업 알림을 보낼 때 필요하니 지금 받아두면 좋다. 다만 2024년 2월 기준으로 최신 버전은 2.3.2인데, 이를 사용하려면 API 33 이상이어야 하므로 현재 상황과 같이 API 33 미만을 타게팅해야 하는 경우에는 2.1.1 버전을 사용해야 한다.
다음과 같이 스크립트를 작성하고 실행하면 알림 권한을 요청할 수 있다.
public void RequestPermission()
{
var channel = new AndroidNotificationChannel()
{
Id = "temp_channel_id",
Name = "Temp Channel",
Importance = Importance.High,
Description = "Temp notifications Channel",
};
AndroidNotificationCenter.RegisterNotificationChannel(channel);
AndroidNotificationCenter.CancelAllDisplayedNotifications();
AndroidNotificationCenter.DeleteNotificationChannel("temp_channel_id");
}
다만 사용자가 수락했는지 여부는 받을 수 없다.
Android 헤드업 알림 보내기
앱이 실행중이 아닐 때 알림을 받으면 알림표시줄에만 조용히 표시된다. 만약 아래와 같이 헤드업 알림을 보내고 싶은 경우 어떻게 하면 되는지 알아 볼 것이다.
먼저 유니티 공식 패키지 중 하나인 Mobile Notifications package를 추가한다. 앞 장에서 이미 추가했다면 넘어가면 된다. 프로젝트가 Android API 33 이상을 타겟팅한다면 최신 버전을 추가해도 무방하나, 미만이라면 2.1.1 버전을 사용해야 한다.
그 다음 유니티 스크립트에서 아래와 같이 Android Notification Channel을 추가한다.
AndroidNotificationChannel channel = new AndroidNotificationChannel()
{
Id = "my_test_channel",
Name = "Test channel",
Importance = Importance.High,
Description = "Test channel",
};
AndroidNotificationCenter.RegisterNotificationChannel(channel);
Importance
를 Importance.High
로 설정해야 헤드업 알림이 표시된다.
이제 알림을 전송하는 python 코드는 message
를 다음과 같이 설정하면 된다.
message = messaging.Message(
notification=messaging.Notification(
title='my title',
body='my body',
),
android=messaging.AndroidConfig(
notification=messaging.AndroidNotification(
channel_id='my_test_channel',
),
),
data={
'key1': 'value1',
'key2': 'value2',
'key3': 'value3',
},
token=client_token,
)
여기서 중간에 channel_id
를 앞서 유니티에서 Android Notification Channel을 추가할 때 Id
에 지정한 문자열과 동일하게 해야 한다. 이제 다시 알림을 보내면 헤드업 알림이 표시될 것이다.
다음으로, 알림 아이콘을 바꾸고 싶다면 Player Settings의 Mobile Notifications 섹션에서 다음과 같이 아이콘 이미지를 설정한다.
Identifier
에는 아이콘의 key 값을 입력한다. Type
이 Small
인 경우 단색으로 표시되며, Large
인 경우 컬러로 표시된다.
알림을 전송하는 python 코드의 message
에 icon
파라미터를 추가한다.
message = messaging.Message(
notification=messaging.Notification(
title='my title',
body='my body',
),
android=messaging.AndroidConfig(
notification=messaging.AndroidNotification(
channel_id='my_test_channel',
icon='icon_0',
),
),
data={
'key1': 'value1',
'key2': 'value2',
'key3': 'value3',
},
token=client_token,
)
icon
에 들어가는 문자열은 앞서 유니티의 Mobile Notifications 설정에서 Identifier
에 입력된 아이콘의 key 값과 동일한 문자열을 사용해야 한다.
백그라운드 알림을 눌러서 앱을 실행한 경우에도 FirebaseMessaging.MessageReceived
를 통해 그 알림에 포함된 Data를 받을 수 있다. 다만 이 경우에 안드로이드에서는 title
과 body
를 얻을 수는 없다.
다음과 같이 앱이 백그라운드일 때 사용자가 누른 알림인지, 앱이 실행중일 때 받은 알림인지를 확인할 수 있다.
private void OnMessageReceived(object sender, MessageReceivedEventArgs e)
{
Debug.Log("is background: " + e.Message.NotificationOpened);
}
iOS 관련 사항
iOS에서는 별도로 설정해야 할 사항이 몇 가지 있다.
- Firebase와 APNs 연결하기
- 푸시 알림 사용 설정
iOS: Firebase와 APNs 연결하기
APNs는 Apple Push Notification service의 약자로, 애플이 개발한 푸시 알림 서비스이다. 애플 기기에는 반드시 APNs를 통해서만 알림을 보낼 수 있다. 따라서 APNs와 Firebase를 연결하는 과정이 필요하다.
연결은 APNs 인증서를 애플 개발자 센터에서 발급받은 후에 이를 Firebase에 업로드하는 형식으로 진행된다. APNs 인증서를 받기 위해선 Apple developer program 멤버십에 가입된 애플 계정이 필요하다.
애플 개발자 계정의 Key 목록에 들어간 후 추가 버튼을 누르고 “ Apple Push Notifications service (APNs)”를 체크한다. 그리고 키 파일을 다운로드받아서 잘 저장한다. 그 다음 Firebase console에서 프로젝트 설정 내의 클라우드 메시징 탭으로 들어가서, Apple 앱 구성의 APNs 인증 키에 다운로드받은 키 파일을 업로드하면 된다.
iOS: 푸시 알림 사용 설정
Unity에서 Xcode 프로젝트로 빌드한 후 그 Xcode 프로젝트에서 추가 설정을 진행해야 한다. 방법은 관련 공식 문서대로 하면 된다.
기타 iOS 관련 사항들
무슨 이유에선지 iOS에서는 FirebaseMessaging.GetTokenAsync()
함수가 동작하지 않고 Exception이 발생한다. 대신에 안드로이드와 다르게 FirebaseMessaging.TokenReceived
이벤트가 앱을 실행할 때 마다 발생하므로 이를 통해 토큰 값을 받아오면 된다.
알림 권한은 Firebase를 초기화하는 순간에 자동으로 요청된다.
그러나 만약 Mobile Notifications 패키지가 설치되어 있고, 아래와 같이 Player Settings의 Mobile Notifications 섹션에서 Request Authorization on App Launch가 체크되어 있다면 앱이 실행될 때 자동으로 권한을 요청한다.
만약 수동으로 요청하고 싶다면 체크를 해제하고 다음과 같이 하면 된다. (Mobile Notifications 공식 문서의 예제 코드)
public IEnumerator RequestAuthorization()
{
var authorizationOption = AuthorizationOption.Alert | AuthorizationOption.Badge;
using (var req = new AuthorizationRequest(authorizationOption, true))
{
while (!req.IsFinished)
{
yield return null;
};
string res = "\n RequestAuthorization:";
res += "\n finished: " + req.IsFinished;
res += "\n granted : " + req.Granted;
res += "\n error: " + req.Error;
res += "\n deviceToken: " + req.DeviceToken;
Debug.Log(res);
}
}