To write your cross-platform Firebase Cloud Messaging client app with C++, use the Firebase Cloud Messaging API. The C++ SDK works for both Android and Apple platforms, with some additional setup required for each platform.
Set up Firebase and the FCM SDK
Android
If you haven't already, add Firebase to your C++ project.
In the linked setup instructions, review the device and app requirements for using the Firebase C++ SDK, including the recommendation to use CMake to build your app.
In your project-level
build.gradle
file, make sure to include Google's Maven repository in both yourbuildscript
andallprojects
sections.
Create a Firebase App object, passing in the JNI environment and Activity:
app = ::firebase::App::Create(::firebase::AppOptions(), jni_env, activity);
Define a class that implements the
firebase::messaging::Listener
interface.Initialize FCM, passing in the App and a constructed Listener:
::firebase::messaging::Initialize(app, listener);
Apps that rely on the Google Play services SDK should check the device for a compatible Google Play services APK before accessing the features. To learn more, refer to Check for Google Play services APK.
iOS+
- If you haven't already,
add Firebase to your C++ project. Then,
to set up your project for FCM:
- In your project's Podfile, add the FCM dependency:
pod 'FirebaseMessaging'
- Drag the
firebase.framework
andfirebase_messaging.framework
frameworks into your Xcode project from the Firebase C++ SDK.
- In your project's Podfile, add the FCM dependency:
Upload your APNs authentication key to Firebase. If you don't already have an APNs authentication key, make sure to create one in the Apple Developer Member Center.
-
Inside your project in the Firebase console, select the gear icon, select Project Settings, and then select the Cloud Messaging tab.
-
In APNs authentication key under iOS app configuration, click the Upload button.
-
Browse to the location where you saved your key, select it, and click Open. Add the key ID for the key (available in the Apple Developer Member Center) and click Upload.
-
Configure your Xcode project to enable Push Notifications:
- Select the project from the Navigator area.
- Select the project target from the Editor area.
Select the General tab from the Editor area.
- Scroll down to Linked Frameworks and Libraries, then click the + button to add frameworks.
In the window that appears, scroll to UserNotifications.framework, click on that entry, then click Add.
This framework only appears in Xcode v8 and later and is required by this library.
Select the Capabilities tab from the Editor area.
- Switch Push Notifications to On.
- Scroll down to Background Modes, then switch it to On.
- Select Remote notifications under Background Modes.
Create a Firebase App object:
app = ::firebase::App::Create(::firebase::AppOptions());
Define a class that implements the
firebase::messaging::Listener
interface.Initialize Firebase Cloud Messaging, passing in the App and a constructed Listener:
::firebase::messaging::Initialize(app, listener);
Access the device registration token
Upon initializing the Firebase Cloud Messaging library, a registration token is
requested for the client app instance. The app will receive the token with the
OnTokenReceived
callback, which should be defined in the class that implements
firebase::messaging::Listener
.
If you want to target that specific device, you'll need access to this token.
Note about message delivery on Android
When the app is not running at all and a user taps on a notification,
the message is not, by default, routed through FCM's built in
callbacks. In this case, message payloads are received through an Intent
used to start the application. To have FCM forward these incoming
messages to the C++ library callback, you need to override the method
onNewIntent
in your Activity and pass the Intent
to the
MessageForwardingService
.
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); } }
Messages received while the app is in the background have the content of
their notification field used to populate the system tray notification, but
that notification content will not be communicated to FCM. That is,
Message::notification
will be a null.
In summary:
App state | Notification | Data | Both |
---|---|---|---|
Foreground | OnMessageReceived |
OnMessageReceived |
OnMessageReceived |
Background | System tray | OnMessageReceived |
Notification: system tray Data: in extras of the intent. |
Custom Message Handling on Android
By default, notifications sent to the app are passed to
::firebase::messaging::Listener::OnMessageReceived
, but in some cases you may
want to override the default behavior. To do this on Android you will need to
write custom classes that extend
com.google.firebase.messaging.cpp.ListenerService
as well as update your
project's AndroidManifest.xml
.
Override ListenerService
Methods.
The ListenerService
is the Java class that intercepts incoming messages sent to
the app and routes them to the C++ library. When the app is in the foreground
(or when the app is the background and it receives a data-only payload),
messages will pass through one of the callbacks provided on this class. To add
custom behavior to the message handling, you will need to extend FCM's
default ListenerService
:
import com.google.firebase.messaging.cpp.ListenerService; class MyListenerService extends ListenerService {
By overriding the method ListenerService.onMessageReceived
, you can
perform actions based on the received
RemoteMessage
object and get the message data:
@Override public void onMessageReceived(RemoteMessage message) { Log.d(TAG, "A message has been received."); // Do additional logic... super.onMessageReceived(message); }
ListenerService
also has a few other methods that are used less frequently.
These can be overridden as well, for more information see the
FirebaseMessagingService
reference.
@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); }
Update AndroidManifest.xml
Once your custom classes have been written, they must be included in the
AndroidManifest.xml
to take effect. Ensure that the manifest includes the
merge tools by declaring the appropriate attribute inside the <manifest>
tag,
like so:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.google.firebase.messaging.cpp.samples" xmlns:tools="http://schemas.android.com/tools">
In the firebase_messaging_cpp.aar
archive there is an AndroidManifest.xml
file which declares FCM's default ListenerService
. This manifest
is normally merged with the project specific manifest which is how the
ListenerService
is able to run. This ListenerService
needs to replaced with
the cusom listener service. That is accomplished by removing the default
ListenerService
and adding the custom Service, which can be done with the
following lines your projects AndroidManifest.xml
file:
<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>
New versions of Firebase C++ SDK (7.1.0 onwards) use JobIntentService
which requires
additional modifications in AndroidManifest.xml
file.
<service android:name="com.google.firebase.messaging.MessageForwardingService" android:permission="android.permission.BIND_JOB_SERVICE" android:exported="false" > </service>
Prevent auto initialization
FCM generates a registration token for device targeting.
When a token is generated, the library uploads the
identifier and configuration data to Firebase. If you want to get an explicit
opt-in before using the token, you can prevent generation at configure time by
disabling FCM (and on Android, Analytics). To do this, add a metadata value to
your Info.plist
(not your GoogleService-Info.plist
) on Apple platforms,
or your AndroidManifest.xml
on Android:
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
To re-enable FCM, you can make a runtime call:
::firebase::messaging::SetTokenRegistrationOnInitEnabled(true);
This value persists across app restarts once set.
Handling Messages with Deep Links on Android
FCM allows messages to be sent containing a deep link into your app. To receive messages that contain a deep link, you must add a new intent filter to the activity that handles deep links for your app. The intent filter should catch deep links of your domain. If your messages do not contain a deep link, this configuration is not necessary. In 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>
It is also possible to specify a wildcard to make the intent filter more flexible. For example:
<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>
When users tap a notification containing a link to the scheme and host you specify, your app will start the activity with this intent filter to handle the link.
Next steps
After setting up the client app, you are ready to send downstream and topic messages with the Firebase. To learn more, see this functionality demonstrated in the quickstart sample which you can download, run, and review.
To add other, more advanced behavior to your app see the guides for sending messages from an app server:
Keep in mind that you'll need a server implementation to make use of these features.