C++로 Firebase 클라우드 메시징 클라이언트 앱 설정

C++로 크로스 플랫폼 Firebase 클라우드 메시징 클라이언트 앱을 작성하려면 Firebase Cloud Messaging API를 사용하세요. C++ SDK는 Android 및 Apple 플랫폼에서 모두 작동하며 각 플랫폼마다 몇 가지 추가 설정이 필요합니다.

Firebase 및 FCM SDK 설정

Android

  1. 아직 추가하지 않은 경우 C++ 프로젝트에 Firebase를 추가합니다.

    • 연결된 설정 안내에서 CMake를 사용하여 앱을 빌드하기 위한 권장사항을 포함하여 Firebase C++ SDK 사용에 필요한 기기 및 앱의 요구사항을 검토하세요.

    • 프로젝트 수준 build.gradle 파일의 buildscriptallprojects 섹션에 Google의 Maven 저장소가 포함되어야 합니다.

  2. Firebase 앱 객체를 만들고 JNI 환경 및 액티비티를 전달합니다.

    app = ::firebase::App::Create(::firebase::AppOptions(), jni_env, activity);

  3. firebase::messaging::Listener 인터페이스를 구현하는 클래스를 정의합니다.

  4. 앱 및 구성된 리스너를 전달해 FCM을 초기화합니다.

    ::firebase::messaging::Initialize(app, listener);

  5. Play 서비스 SDK를 사용하는 앱은 기능에 액세스하기 전에 기기가 Google Play 서비스 APK와 호환되는지 확인해야 합니다. 자세히 알아보려면 Google Play 서비스 APK 확인을 참조하세요.

iOS+

  1. 유효한 APN 인증서가 필요합니다. 인증서가 아직 없으면 Apple Developer Member Center에서 만들어야 합니다.
  2. 아직 추가하지 않은 경우 C++ 프로젝트에 Firebase를 추가합니다. 그런 다음 FCM용 프로젝트를 설정합니다.
    1. 프로젝트의 Podfile에 FCM 종속 항목을 추가합니다.
      pod 'FirebaseMessaging'
    2. Firebase C++ SDK에서 firebase.frameworkfirebase_messaging.framework 프레임워크를 Xcode 프로젝트로 드래그합니다.
  3. Xcode 프로젝트를 구성하여 푸시 알림을 사용 설정합니다.

    1. 탐색기 영역에서 프로젝트를 선택합니다.
    2. 편집기 영역에서 프로젝트 대상을 선택합니다.
    3. 편집기 영역에서 General(일반) 탭을 선택합니다.

      1. Linked Frameworks and Libraries(연결된 프레임워크 및 라이브러리)까지 아래로 스크롤하고 + 버튼을 클릭하여 프레임워크를 추가합니다.
      2. 창이 표시되면 UserNotifications.framework로 스크롤하고 해당 항목을 클릭한 후 Add(추가)를 클릭합니다.

        이 라이브러리에서는 Xcode v8 이상을 요구하므로 해당 버전에서만 이 프레임워크가 표시됩니다.

    4. 편집기 영역에서 Capabilities(기능) 탭을 선택합니다.

      1. Push Notifications(푸시 알림)On(켜기)으로 전환합니다.
      2. Background Modes(백그라운드 모드)까지 아래로 스크롤하고 On(켜기)으로 전환합니다.
      3. Background Modes(백그라운드 모드) 아래의 Remote notifications(원격 알림)를 선택합니다.
  4. Firebase 앱 객체를 만듭니다.

    app = ::firebase::App::Create(::firebase::AppOptions());

  5. firebase::messaging::Listener 인터페이스를 구현하는 클래스를 정의합니다.

  6. 앱 및 구성된 리스너를 전달해 Firebase 클라우드 메시징을 초기화합니다.

    ::firebase::messaging::Initialize(app, listener);

기기 등록 토큰 액세스

Firebase 클라우드 메시징 라이브러리를 초기화할 때 클라이언트 앱 인스턴스의 등록 토큰을 요청받습니다. 앱에서 OnTokenReceived 콜백으로 토큰을 수신하며 firebase::messaging::Listener를 구현하는 클래스에 이 콜백이 정의되어야 합니다.

특정 기기를 타겟팅하려면 이 토큰에 액세스해야 합니다.

Android 메시지 전송 참고사항

앱이 전혀 실행되지 않을 때 사용자가 알림을 탭하면 기본적으로 메시지가 FCM의 기본 제공 콜백을 통해 라우팅되지 않습니다. 이러한 경우에는 메시지 페이로드가 애플리케이션을 시작하는 데 사용되는 Intent를 통해 수신됩니다. FCM에서 수신 메시지를 C++ 라이브러리 콜백에 전달하도록 하려면 액티비티에서 onNewIntent 메서드를 재정의하고 IntentMessageForwardingService에 전달해야 합니다.

import com.google.firebase.messaging.MessageForwardingService;

class MyActivity extends Activity {
  private static final String TAG = "MyActvity";

  @Override
  protected void onNewIntent(Intent intent) {
    Log.d(TAG, "A message was sent to this app while it was in the background.");
    Intent message = new Intent(this, MessageForwardingService.class);
    message.setAction(MessageForwardingService.ACTION_REMOTE_INTENT);
    message.putExtras(intent);
    message.setData(intent.getData());
    // For older versions of Firebase C++ SDK (< 7.1.0), use `startService`.
    // startService(message);
    MessageForwardingService.enqueueWork(this, message);
  }
}

앱이 백그라운드 상태일 때 수신된 메시지에는 작업 표시줄 알림을 채우는 데 사용되는 알림 필드의 콘텐츠가 포함되지만 이 알림 콘텐츠는 FCM에 전달되지 않습니다. 즉 Message::notification은 null입니다.

요약하면 다음과 같습니다.

앱 상태 알림 데이터 모두
포그라운드 OnMessageReceived OnMessageReceived OnMessageReceived
백그라운드 작업 표시줄 OnMessageReceived 알림: 작업 표시줄
데이터: 인텐트 부가 정보

Android 커스텀 메시지 처리

기본적으로 앱에 전송되는 알림은 ::firebase::messaging::Listener::OnMessageReceived로 전달되지만 경우에 따라서는 기본 동작을 재정의할 수 있습니다. Android에서 기본 동작을 재정의하려면 com.google.firebase.messaging.cpp.ListenerService를 확장하는 커스텀 클래스를 작성하고 프로젝트의 AndroidManifest.xml을 업데이트해야 합니다.

ListenerService 메서드 재정의

ListenerService는 앱에 전송된 수신 메시지를 가로채 C++ 라이브러리로 라우팅하는 자바 클래스입니다. 앱이 포그라운드 상태일 때 또는 앱이 백그라운드 상태이고 데이터 전용 페이로드를 수신하는 경우에 메시지가 이 클래스에서 제공되는 콜백 중 하나를 통해 전달됩니다. 메시지 처리에 커스텀 동작을 추가하려면 FCM의 기본 ListenerService를 확장해야 합니다.

import com.google.firebase.messaging.cpp.ListenerService;

class MyListenerService extends ListenerService {

ListenerService.onMessageReceived 메서드를 재정의하면 수신된 RemoteMessage 객체를 기준으로 작업을 수행하고 메시지 데이터를 가져올 수 있습니다.

@Override
public void onMessageReceived(RemoteMessage message) {
  Log.d(TAG, "A message has been received.");
  // Do additional logic...
  super.onMessageReceived(message);
}

ListenerService에는 자주 사용되지 않는 몇 가지 다른 메서드가 더 있습니다. 이러한 메서드는 재정의도 가능합니다. 자세한 내용은 FirebaseMessagingService 참조를 확인하세요.

@Override
public void onDeletedMessages() {
  Log.d(TAG, "Messages have been deleted on the server.");
  // Do additional logic...
  super.onDeletedMessages();
}

@Override
public void onMessageSent(String messageId) {
  Log.d(TAG, "An outgoing message has been sent.");
  // Do additional logic...
  super.onMessageSent(messageId);
}

@Override
public void onSendError(String messageId, Exception exception) {
  Log.d(TAG, "An outgoing message encountered an error.");
  // Do additional logic...
  super.onSendError(messageId, exception);
}

AndroidManifest.xml 업데이트

커스텀 클래스가 작성되면 AndroidManifest.xml에 포함시켜야 클래스가 적용됩니다. 다음과 같이 <manifest> 태그 안에 적절한 속성을 선언하여 매니페스트에 병합 도구가 포함되도록 합니다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.google.firebase.messaging.cpp.samples"
    xmlns:tools="http://schemas.android.com/tools">

firebase_messaging_cpp.aar 보관 항목에 FCM의 기본 ListenerService를 선언하는 AndroidManifest.xml 파일이 있습니다. 이 매니페스트는 일반적으로 ListenerService가 실행되는 방법을 나타내는 프로젝트별 매니페스트와 병합됩니다. 이 ListenerService를 커스텀 리스너 서비스로 바꿔야 합니다. 프로젝트 AndroidManifest.xml 파일에서 다음 줄을 사용하여 기본 ListenerService를 삭제하고 커스텀 서비스를 추가하면 됩니다.

<service android:name="com.google.firebase.messaging.cpp.ListenerService"
         tools:node="remove" />
<service android:name="com.google.firebase.messaging.cpp.samples.MyListenerService"
         android:exported="false">
  <intent-filter>
    <action android:name="com.google.firebase.MESSAGING_EVENT"/>
  </intent-filter>
</service>

Firebase C++ SDK의 새 버전(7.1.0 이상)은 JobIntentService를 사용하므로 AndroidManifest.xml 파일에서 추가 수정이 필요합니다.

<service android:name="com.google.firebase.messaging.MessageForwardingService"
     android:permission="android.permission.BIND_JOB_SERVICE"
     android:exported="false" >
</service>

자동 초기화 방지

FCM은 기기 타겟팅을 위한 등록 토큰을 생성합니다. 토큰이 생성되면 라이브러리는 식별자와 구성 데이터를 Firebase에 업로드합니다. 토큰을 사용하기 전에 명시적으로 수신 동의하려면 Android나 애널리틱스에서 FCM을 사용 중지하여 구성 시 생성을 방지할 수 있습니다. 이를 위해 Apple 플랫폼에서는 GoogleService-Info.plist가 아닌 Info.plist에, Android에서는 AndroidManifest.xml에 메타데이터 값을 추가합니다.

Android

<?xml version="1.0" encoding="utf-8"?>
<application>
  <meta-data android:name="firebase_messaging_auto_init_enabled"
             android:value="false" />
  <meta-data android:name="firebase_analytics_collection_enabled"
             android:value="false" />
</application>

Swift

FirebaseMessagingAutoInitEnabled = NO

FCM을 다시 사용 설정하려면 런타임 호출을 만들면 됩니다.

::firebase::messaging::SetTokenRegistrationOnInitEnabled(true);

이 값을 설정하고 나면 앱을 다시 시작해도 유지됩니다.

FCM을 사용하면 앱에 딥 링크가 포함된 메시지를 보낼 수 있습니다. 딥 링크가 포함된 메시지를 수신하려면 앱의 딥 링크를 처리하는 활동에 새 인텐트 필터를 추가해야 합니다. 인텐트 필터가 도메인의 딥 링크를 인식합니다. 메시지에 딥 링크가 포함되어 있지 않다면 이 구성이 필요하지 않습니다. AndroidManifest.xml에 다음을 추가합니다.

<intent-filter>
  <action android:name="android.intent.action.VIEW"/>
  <category android:name="android.intent.category.DEFAULT"/>
  <category android:name="android.intent.category.BROWSABLE"/>
  <data android:host="CHANGE_THIS_DOMAIN.example.com" android:scheme="http"/>
  <data android:host="CHANGE_THIS_DOMAIN.example.com" android:scheme="https"/>
</intent-filter>

인텐트 필터를 보다 유연하게 만들기 위해 와일드 카드를 지정할 수도 있습니다. 예를 들면 다음과 같습니다.

<intent-filter>
  <action android:name="android.intent.action.VIEW"/>
  <category android:name="android.intent.category.DEFAULT"/>
  <category android:name="android.intent.category.BROWSABLE"/>
  <data android:host="*.example.com" android:scheme="http"/>
  <data android:host="*.example.com" android:scheme="https"/>
</intent-filter>

지정한 스키마 및 호스트로 연결되는 링크가 포함된 알림을 사용자가 탭하면 앱에서 이 인텐트 필터로 링크를 처리하는 활동을 시작합니다.

다음 단계

클라이언트 앱이 설정되면 Firebase로 다운스트림 메시지와 주제 메시지를 보낼 수 있습니다. 자세히 알아보려면 빠른 시작 샘플에 나와 있는 기능을 참조하세요. 샘플을 다운로드하여 실행하거나 검토할 수 있습니다.

앱에 다른 고급 동작을 추가하려면 앱 서버에서 알림을 전송하는 방법 가이드를 참조하세요.

이러한 기능을 사용하려면 서버 구현이 필요하다는 점에 유의하세요.