EM Business Products Corp.
  • Services
  • Case studies
  • Blog
  • Connect with us
EM Business Products Corp.
  • Services
  • Case studies
  • Blog

06/20/2020

How to add a custom push notification sound on iOS and Android with React Native Firebase and FCM

#react-native
How to add a custom push notification sound on iOS and Android with React Native Firebase and FCM

I want to document how I got custom push notification sounds working on iOS and Android with the React Native Firebase library and Firebase Cloud Messaging (FCM).

The process is not difficult once you understand it. It's just hard to find a complete set of instructions on how to do it. I hope this will save you time when setting it up in your project.

Groundwork

Set up the Firebase libraries

First step is an obvious one. Make sure you install React Native Firebase core library and the Cloud Messaging modules. Be sure to follow all instructions for each platform carefully.

Select a sound format

Apple supports .wav .aiff or .caf files. Android supports .mp3, .ogg or .wav.

Since our back-end server used the same push body for both platforms, it was easier to use a format that both platforms could share, so I chose .wav.

Custom sounds

Set up custom sound on iOS

  1. Go to your_project_root/ios and place the sound in there. This doesn't yet add it to the project, it just places the sound in a logical spot.
  2. Open up Xcode and go to the project navigator tab.
  3. Drag your sound into your project. Select "copy files if needed" on the dialog.
  4. That's it!

Set up custom sound on Android

Setup on Android is a little more complex than iOS. As of Android API level 26, notifications need to be set to a notification channel in order for them to work at all.

Android Notification Channels

The channel defines the sound to use, vibration pattern, and other things about your push notifications. React Native Firebase creates its own channel internally to help provide a basic push functionality with their Cloud Messaging library, but if you want a custom sound or other customization, this channel is not accessible to you to edit. You must create your own custom notification channel. On native Android, this is Java code that executes at runtime, it's not done on a configuration file.

React Native Firebase does not provide an API to this native API for creating a channel. It used to provide it on v5, but since v6 it has stopped supporting it because it was out of scope of Firebase.

Luckily it's pretty simple to add you own without the need of a custom library to do it. You simply need to update your MainActivity.java file in your project so a notification channel is created and configured.

Before you can create your notification channel. You must do the following:

1. Define a name for your notification channel

It can be anything, and you will use it to target your custom channel from your push message, so that the custom sound you will tie to your channel plays.

I should note that after installing the app the channel name will remain registered until the app is uninstalled. So keep that in mind if you change channel names later.

2. Add your sound as a resource

Drag your .wav sound into the your_project_root/android/app/src/main/res/raw folder (if it doesn't exist, create it).

Add the notification channel code

The code below must be placed inside the onCreate method of your MainActivity class. Fill in the text surrounded in brackets with your own, and customize anything else you need on your notification:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
          NotificationChannel notificationChannel = new NotificationChannel("{ENTER THE NOTIFICATION NAME HERE}", "{ENTER APP NAME HERE}", NotificationManager.IMPORTANCE_HIGH);
          notificationChannel.setShowBadge(true);
          notificationChannel.setDescription("");
          AudioAttributes att = new AudioAttributes.Builder()
                  .setUsage(AudioAttributes.USAGE_NOTIFICATION)
                  .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                  .build();
          notificationChannel.setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + getPackageName() + "/raw/{ENTER SOUND NAME HERE WITHOUT EXTENSION}"), att);
          notificationChannel.enableVibration(true);
          notificationChannel.setVibrationPattern(new long[]{400, 400});
          notificationChannel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC);
          NotificationManager manager = getSystemService(NotificationManager.class);
          manager.createNotificationChannel(notificationChannel);
      }

Here's a code example with some values filled in:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
          NotificationChannel notificationChannel = new NotificationChannel("new_email_arrived_channel", "My Emailer", NotificationManager.IMPORTANCE_HIGH);
          notificationChannel.setShowBadge(true);
          notificationChannel.setDescription("");
          AudioAttributes att = new AudioAttributes.Builder()
                  .setUsage(AudioAttributes.USAGE_NOTIFICATION)
                  .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                  .build();
          notificationChannel.setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + getPackageName() + "/raw/my_custom_sound"), att);
          notificationChannel.enableVibration(true);
          notificationChannel.setVibrationPattern(new long[]{400, 400});
          notificationChannel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC);
          NotificationManager manager = getSystemService(NotificationManager.class);
          manager.createNotificationChannel(notificationChannel);
      }

Notice my_custom_sound is not written with the extension (.wav). You just need to add the file name.

Test the custom sound

With the sound in place you can now test your implementation. Before you can test it you will need to fish out Firebase's FCM token from your app. This token is used by FCM to route the push notification to the correct device.

Log the FCM token to your console

Firebase lets you retreive the FCM token using the messaging().getToken() function. Use this function to log the FCM token to your console:

const _getToken = async () => {
  try {
    const token = await messaging().getToken();
    console.log('FCM token registered:', token);
        ...
  } catch (error) {
    console.error('Error getting FCM token:', error);
  }
};

Do this for both Android and iOS devices. It will create a different token for both.

We will use this token to test sending push notifications directly to our test devices.

Test with the FCM REST API

I will show how to test with the FCM REST API because it will give you all the flexibility you need to edit the push body as you would need to set it on your server.

Follow the steps below to get testing.

Install Postman

Postman is a great API testing application for your desktop computer and will make setting up the FCM REST API very easy. Download and install the app here

Get your Firebase server key

Before we configure Postman we need that our API push requests are authenticated against our project. For this we need to authenticate with our server key. To find it:

  1. Go to your Firebase project
  2. Click the project settings button (the gear icon) and select Project Settings
  3. Go to the Cloud Messaging tab
  4. If you followed installation instructions for React Native Firebase earlier, you should have a server key listed at the top of this page. If you don't it means you have not yet set up your project for Cloud Messaging and you need to go back to the installation instructions.
  5. Copy the server key
Configure Postman to send an FCM push request
  1. Open Postman
  2. Click on the + button on the page to create a new API request
  3. For the HTTP method, set it to POST
  4. Set the URL to https://fcm.googleapis.com/fcm/send
  5. Go to the Authorization tab
  6. For authorization type select "Bearer Token"
  7. Add your server key from your Firebaess project, into the token field
  8. Go back to the body tab
  9. Set the body type to "raw"
  10. Make sure the data type at the end of the body type options is set to JSON and not Text or any other type
Set up the push body

Now that your request is configured, let's add the push body. This is done in the body tab in the empty area under the data type options. Here is an example body:

{
  "to": "<FCM TOKEN>",
  "notification": {
    "title": "Some title",
    "body": "Some body",
    "sound": "my_custom_sound.wav",
    "android_channel_id": "new_email_arrived_channel"
  },
  "data": {
    "field1": "value1",
    "field2": "value2"
  },
  "content_available": true,
  "priority": "high"
}

The key items here to get your sound to work is the "to", "sound", and "android_channel_id" fields.

to field

Here you will need to add your device's FCM token in quotes

sound field

Your sound field must set the sound name including the extension.

android_channel_id field

The "android_channel_id" field must have the name of your custom Android push channel you created earlier. These names must match or else your channel won't be found and your device will simply play a default sound.

NOTE: You may find some forums out on the internet saying the field name should be "channel_id" and not "android_channel_id". This is half true. They are correct that the REAL name for the push field is "channel_id" on Android. But remember, we are using FCM and FCM handles both iOS and Android. We are not making a request to Google's push server directly.

So for FCM, the field name is "android_channel_id", but once the push is delivered to the Android device this field comes in as "channel_id". FCM translates the field name correctly for us once its delivered.

Send the notification

Hit the send button on Postman, you should receive the push with custom sound.

If you get any errors on the API call, make sure you resolve those

Troubleshoot common problems

If you are having trouble getting the sound to play or the push doesn't come through here are some suggestions you can try to help you troubleshoot.

  • Make sure you've followed the Firebase project and React Native Firebase library installation instructions exactly, for each platform
  • Make sure for iOS that you've either added a push certificate for the sandbox and production APNS servers OR that you've added a push auth key.
  • Try re-creating the push certificate OR push auth key. This resolved a push problem on iOS for me on one occassion.
  • Make sure the push sound on your FCM body HAS the extension set to it
  • Make sure the push sound defined on your Android channel in MainActivity.java does NOT have the file extension on it
  • Make sure the sounds are being bundled with the build
  • It's possible the sound format or compression chosen is not working or not supported by the platform. Try changing the sound compression/format settings.

Conclusion

Hope this helps you in your push journey. It's strangely a confusing and complex feature to set up.

Copy of MainActivity.java for reference

package io.myapp;

import com.facebook.react.ReactActivity;

import org.devio.rn.splashscreen.SplashScreen;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.media.AudioAttributes;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;

import androidx.core.app.NotificationCompat;

public class MainActivity extends ReactActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
          NotificationChannel notificationChannel = new NotificationChannel("myapp_notification", "MyApp", NotificationManager.IMPORTANCE_HIGH);
          notificationChannel.setShowBadge(true);
          notificationChannel.setDescription("");
          AudioAttributes att = new AudioAttributes.Builder()
                  .setUsage(AudioAttributes.USAGE_NOTIFICATION)
                  .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                  .build();
          notificationChannel.setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + getPackageName() + "/raw/myapp"), att);
          notificationChannel.enableVibration(true);
          notificationChannel.setVibrationPattern(new long[]{400, 1000, 400});
          notificationChannel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC);
          NotificationManager manager = getSystemService(NotificationManager.class);
          manager.createNotificationChannel(notificationChannel);
      }

      SplashScreen.show(this);
      super.onCreate(savedInstanceState);
  }

  /**
   * Returns the name of the main component registered from JavaScript. This is used to schedule
   * rendering of the component.
   */
  @Override
  protected String getMainComponentName() {
    return "MyApp";
  }
}
Like this article? Cool! You may like these:

CONNECT WITH US

Full Name

Email address

Message

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.