FCM 클라이언트는 Android 5.0 이상의 Google Play 스토어 앱이 설치된 기기 또는 Google API로 Android 5.0을 실행하는 에뮬레이터가 필요합니다. Google Play 스토어를 통해서만 Android 앱을 배포하도록 제한되지는 않습니다.
SDK 설정
이 섹션은 앱에서 다른 Firebase 기능을 이미 사용 설정한 경우 완료되었을 작업에 대해 설명하고 있습니다. 아직 설정하지 않은 경우 Android 프로젝트에 Firebase를 추가하세요.
앱 매니페스트 수정
앱의 매니페스트에 다음을 추가합니다.
FirebaseMessagingService
를 확장하는 서비스를 추가합니다. 이 서비스는 백그라운드에서 앱의 알림을 수신하는 것 외에 다른 방식으로 메시지를 처리하려는 경우에 필요합니다. 포그라운드 앱의 알림 수신, 데이터 페이로드 수신, 업스트림 메시지 전송 등을 수행하려면 이 서비스를 확장해야 합니다.
<service android:name=".java.MyFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>
<!-- Set custom default icon. This is used when no icon is set for incoming notification messages. See README(https://goo.gl/l4GJaQ) for more. --> <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/ic_stat_ic_notification" /> <!-- Set color used with incoming notification messages. This is used when no color is set for the incoming notification message. See README(https://goo.gl/6BKBk7) for more. --> <meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/colorAccent" />
default_notification_channel_id
를 알림 채널 객체의 ID로 설정합니다. 받은 메시지에 명시적으로 설정된 알림 채널이 없으면 FCM에서는 항상 이 값을 사용합니다. 자세한 내용은 알림 채널 관리를 참조하세요.
<meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="@string/default_notification_channel_id" />
Android 13 이상에서 런타임 알림 권한 요청
Android 13에는 알림 표시를 위한 새로운 런타임 권한이 도입되었습니다. 이러한 새로운 런타임 권한은 FCM 알림을 사용하고 Android 13 이상에서 실행되는 모든 앱에 영향을 미칩니다.
기본적으로 FCM SDK(버전 23.0.6 이상)에는 매니페스트에 정의된 POST_NOTIFICATIONS
권한이 포함되어 있습니다.
그러나 앱에서 상수 android.permission.POST_NOTIFICATIONS
를 통해 이 권한의 런타임 버전도 요청해야 합니다.
사용자가 이 권한을 부여할 때까지 앱에서 알림을 표시할 수 없습니다.
새 런타임 권한을 요청하려면 다음 안내를 따르세요.
Kotlin+KTX
// Declare the launcher at the top of your Activity/Fragment: private val requestPermissionLauncher = registerForActivityResult( ActivityResultContracts.RequestPermission(), ) { isGranted: Boolean -> if (isGranted) { // FCM SDK (and your app) can post notifications. } else { // TODO: Inform user that that your app will not show notifications. } } private fun askNotificationPermission() { // This is only necessary for API level >= 33 (TIRAMISU) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED ) { // FCM SDK (and your app) can post notifications. } else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) { // TODO: display an educational UI explaining to the user the features that will be enabled // by them granting the POST_NOTIFICATION permission. This UI should provide the user // "OK" and "No thanks" buttons. If the user selects "OK," directly request the permission. // If the user selects "No thanks," allow the user to continue without notifications. } else { // Directly ask for the permission requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) } } }
Java
// Declare the launcher at the top of your Activity/Fragment: private final ActivityResultLauncher<String> requestPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> { if (isGranted) { // FCM SDK (and your app) can post notifications. } else { // TODO: Inform user that that your app will not show notifications. } }); private void askNotificationPermission() { // This is only necessary for API level >= 33 (TIRAMISU) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) { // FCM SDK (and your app) can post notifications. } else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) { // TODO: display an educational UI explaining to the user the features that will be enabled // by them granting the POST_NOTIFICATION permission. This UI should provide the user // "OK" and "No thanks" buttons. If the user selects "OK," directly request the permission. // If the user selects "No thanks," allow the user to continue without notifications. } else { // Directly ask for the permission requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS); } } }
일반적으로 앱에서 알림을 게시하도록 권한을 부여하면 사용 설정되는 기능을 사용자에게 설명하는 UI를 표시해야 합니다. 이 UI는 확인 및 아니요 버튼과 같이 사용자가 동의하거나 거부할 수 있는 옵션을 제공해야 합니다. 사용자가 확인을 선택하면 권한을 직접 요청합니다. 사용자가 아니요를 선택하면 알림 없이 계속 진행할 수 있도록 합니다.
앱이 사용자에게 POST_NOTIFICATIONS
권한을 요청해야 할 때 적용되는 권장사항을 자세히 알아보려면 알림 런타임 권한을 참조하세요.
Android 12L(API 수준 32) 이하를 타겟팅하는 앱의 알림 권한
앱이 포그라운드에 있을 때 앱에서 알림 채널을 처음 만들면 Android에서 자동으로 사용자에게 권한을 요청합니다. 하지만 채널 생성 및 권한 요청 시기와 관련하여 중요한 주의사항이 있습니다.
- 앱이 백그라운드에서 실행 중일 때 첫 알림 채널을 만드는 경우(FCM 알림 수신 시 FCM SDK가 실행됨) 다음에 앱을 열 때까지 Android에 알림이 표시되지 않고 사용자에게 알림 권한을 요청하지 않습니다. 즉, 앱을 열고 사용자가 권한을 수락하기 전에 수신된 알림은 잃게 됩니다.
- Android 13 이상을 타겟팅하는 앱은 플랫폼의 API를 이용하여 권한을 요청하도록 업데이트하는 것이 좋습니다. 이 방법이 가능하지 않다면 앱에서 알림 권한 대화상자를 트리거하기 위해 앱에 알림을 보내기 전에 알림 채널을 생성하고 손실되는 알림이 없도록 해야 합니다. 자세한 내용은 알림 권한 권장사항을 참조하세요.
선택사항: POST_NOTIFICATIONS
권한 삭제
기본적으로 FCM SDK에는 POST_NOTIFICATIONS
권한이 포함되어 있습니다.
앱에서 FCM 알림 또는 다른 SDK를 통하거나 앱에 직접 게시하는 등의 방법으로 알림 메시지를 사용하지 않고 앱에 권한을 포함하고 싶지 않다면 매니페스트 병합 도구의 remove
마커를 사용하여 이를 삭제할 수 있습니다. 이 권한을 삭제하면 FCM 알림뿐만 아니라 모든 알림이 표시되지 않는 점에 유의하세요. 앱의 매니페스트 파일에 다음을 추가합니다.
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" tools:node="remove"/>
기기 등록 토큰 액세스
FCM SDK는 앱을 처음 시작할 때 클라이언트 앱 인스턴스용 등록 토큰을 생성합니다. 단일 기기를 타겟팅하거나 기기 그룹을 만들려면 FirebaseMessagingService
를 확장하고 onNewToken
을 재정의하여 이 토큰에 액세스해야 합니다.
이 섹션에서는 토큰을 검색하고 토큰의 변경을 모니터링하는 방법을 설명합니다. 토큰은 최초 시작 후에 순환될 수 있으므로 마지막으로 업데이트된 등록 토큰을 가져오는 것이 좋습니다.
다음과 같은 경우에 등록 토큰이 변경될 수 있습니다.
- 새 기기에서 앱 복원
- 사용자가 앱 제거/재설치
- 사용자가 앱 데이터 소거
현재 등록 토큰 가져오기
현재 토큰을 가져오려면 FirebaseMessaging.getInstance().getToken()
을 호출합니다.
Kotlin+KTX
FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task -> if (!task.isSuccessful) { Log.w(TAG, "Fetching FCM registration token failed", task.exception) return@OnCompleteListener } // Get new FCM registration token val token = task.result // Log and toast val msg = getString(R.string.msg_token_fmt, token) Log.d(TAG, msg) Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show() })
Java
FirebaseMessaging.getInstance().getToken() .addOnCompleteListener(new OnCompleteListener<String>() { @Override public void onComplete(@NonNull Task<String> task) { if (!task.isSuccessful()) { Log.w(TAG, "Fetching FCM registration token failed", task.getException()); return; } // Get new FCM registration token String token = task.getResult(); // Log and toast String msg = getString(R.string.msg_token_fmt, token); Log.d(TAG, msg); Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show(); } });
토큰 생성 모니터링
새 토큰이 생성될 때마다 onNewToken
콜백이 호출됩니다.
Kotlin+KTX
/** * Called if the FCM registration token is updated. This may occur if the security of * the previous token had been compromised. Note that this is called when the * FCM registration token is initially generated so this is where you would retrieve the token. */ override fun onNewToken(token: String) { Log.d(TAG, "Refreshed token: $token") // If you want to send messages to this application instance or // manage this apps subscriptions on the server side, send the // FCM registration token to your app server. sendRegistrationToServer(token) }
Java
/** * There are two scenarios when onNewToken is called: * 1) When a new token is generated on initial app startup * 2) Whenever an existing token is changed * Under #2, there are three scenarios when the existing token is changed: * A) App is restored to a new device * B) User uninstalls/reinstalls the app * C) User clears app data */ @Override public void onNewToken(@NonNull String token) { Log.d(TAG, "Refreshed token: " + token); // If you want to send messages to this application instance or // manage this apps subscriptions on the server side, send the // FCM registration token to your app server. sendRegistrationToServer(token); }
토큰이 확보되었으면 앱 서버로 전송하고 원하는 방법으로 저장할 수 있습니다.
Google Play 서비스 확인
Play 서비스 SDK를 사용하는 앱에서 Google Play 서비스 기능에 액세스하기 전에 항상 기기에 호환되는 Google Play 서비스 APK가 있는지 확인해야 합니다. 기본 활동의 onCreate()
메서드 및 onResume()
메서드 등 두 위치에서 확인 작업을 하는 것이 좋습니다. onCreate()
로 확인하면 확인에 성공하지 못한 앱을 사용할 수 없게 됩니다. onResume()
으로 확인하면 사용자가 '뒤로' 버튼과 같은 다른 수단을 통해 실행 중인 앱으로 돌아오는 경우에 확인 작업이 계속 수행될 수 있습니다.
기기에 호환되는 Google Play 서비스 버전이 없으면 앱에서 GoogleApiAvailability.makeGooglePlayServicesAvailable()
을 호출하여 사용자가 Play 스토어에서 Google Play 서비스를 다운로드하도록 허용할 수 있습니다.
자동 초기화 방지
FCM 등록 토큰이 생성되면 라이브러리는 식별자와 구성 데이터를 Firebase에 업로드합니다. 토큰이 자동 생성되는 것을 방지하려면 AndroidManifest.xml
에 다음 메타데이터 값을 추가하여 애널리틱스 수집 및 FCM 자동 초기화를 사용 중지해야 합니다(둘 다 사용 중지해야 함).
<meta-data android:name="firebase_messaging_auto_init_enabled" android:value="false" /> <meta-data android:name="firebase_analytics_collection_enabled" android:value="false" />
FCM 자동 초기화를 다시 사용 설정하려면 런타임 호출을 만듭니다.
Kotlin+KTX
Firebase.messaging.isAutoInitEnabled = true
Java
FirebaseMessaging.getInstance().setAutoInitEnabled(true);
애널리틱스 수집을 다시 사용 설정하려면 FirebaseAnalytics
클래스의 setAnalyticsCollectionEnabled()
메서드를 호출합니다. 예를 들면 다음과 같습니다.
setAnalyticsCollectionEnabled(true);
이 값을 설정하고 나면 앱을 다시 시작해도 유지됩니다.
다음 단계
클라이언트 앱이 설정되었으면 알림 작성기를 사용하여 다운스트림 메시지를 보낼 수 있습니다. 이 기능은 빠른 시작 샘플에 나와 있으며 샘플을 다운로드하여 실행하거나 검토할 수 있습니다.
앱에 다른 고급 동작을 추가하려면 인텐트 필터를 선언하고 받은 메시지에 응답하는 작업을 구현하면 됩니다. 자세한 내용은 앱 서버에서 메시지를 전송하는 방법 가이드를 참조하세요.
이러한 기능을 활용하려면 서버 구현과 서버 프로토콜(HTTP 또는 XMPP) 또는 Admin SDK 구현이 필요합니다.