← back to the blog


Sample Code for sending Firebase Cloud Message (FCM) with Xamarin

Posted in Firebase by dake

This blog show how to setup Firebase Cloud Message for Xamarin.Android

First, register project at console.firebase.google.com

Package name at firebase console

Make sure the package is your xamarin app's package ID, for example, com.yourcompany.yourapp.

Also, make note at console.firebase.google.com for following values, because you'll need those when you add code at Xamarin.Android.

  • Project ID
    • Firebase Setting, General Tab.
  • Web API Key
    • Firebase Setting, General Tab
  • Sender ID
    • Firebase Setting, Cloud MessagingTab

Versions

First, following example code is under these version.

  • Visual Studio 2015 - Version 14 Update 3
  • Xamain - 4.4.0.34
  • Xamarin.Android - 7.2.0.7
  • Xamarin.iOS- 10.8.0.174

Add code to Xamarin.Android Code

packages.config at Xamarin.Android

We'll need firebase and google play service.

  <package id="Xamarin.Firebase.Common" version="42.1021.0" targetFramework="monoandroid71" />
  <package id="Xamarin.Firebase.Iid" version="42.1021.0" targetFramework="monoandroid71" />
  <package id="Xamarin.Firebase.Messaging" version="42.1021.0" targetFramework="monoandroid71" />
  <package id="Xamarin.Forms" version="2.3.4.224" targetFramework="monoandroid71" />
  <package id="Xamarin.GooglePlayServices.Basement" version="42.1021.0" targetFramework="monoandroid71" />
  <package id="Xamarin.GooglePlayServices.Tasks" version="42.1021.0" targetFramework="monoandroid71" />

AndroidManifest.xml

<application android:label="YourAppLabel" android:icon="@drawable/icon">
    <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
    <receiver
      android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver"
      android:exported="false" />

    <receiver
      android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver"
      android:exported="true"
      android:permission="com.google.android.c2dm.permission.SEND" >
      <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
        <category android:name="${applicationId}" />
      </intent-filter>
    </receiver>

  </application>
  <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  <uses-permission android:name="android.permission.WAKE_LOCK" />
  <uses-permission android:name="android.permission.GET_ACCOUNTS" />
  <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

google-services.json

Based on the current document, need google-services.json under project. You could get this under console.firebase.google.com, however I'm still not sure why do we need this file. I'll do more research for this later.

Add code to MainActivity

  private void FirebaseNotificationSetup()
        {
            var options = new FirebaseOptions.Builder()
         .SetApplicationId(GetConfigValues(ConfigKeys.FCMAndroidProjectID))
         .SetApiKey(GetConfigValues(ConfigKeys.FCMAndroidAPIKEY))
         .SetGcmSenderId(GetConfigValues(ConfigKeys.FCMAndroidSenderID))
         .Build();

            var firebaseApp = FirebaseApp.InitializeApp(ApplicationContext, options, APP_NAME);
            if (FirebaseApp.GetApps(this) != null)
            {
                var x = FirebaseApp.GetInstance(APP_NAME);
            }

            Task.Run(() =>
            {
                var instanceID = FirebaseInstanceId.Instance;
                instanceID.DeleteInstanceId();
                var iid1 = instanceID.Token;
                var iid2 = instanceID.GetToken(GetConfigValues(ConfigKeys.FCMAndroidSenderID), 
                    Firebase.Messaging.FirebaseMessaging.InstanceIdScope);

                // subscribe the topic as Test
                // this will be /topics/test
                FirebaseMessaging.Instance.SubscribeToTopic("Test");
            });
        }
        public enum ConfigKeys
        {
            FCMAndroidProjectID,
            FCMAndroidSenderID,
            FCMAndroidAPIKEY
        }

        public static string GetConfigValues(ConfigKeys keys)
        {
            switch (keys)
            {
                case ConfigKeys.FCMAndroidProjectID:
                    return GetValue("YourProjectIdForDebug", "YourProjectIdForRelease");
                case ConfigKeys.FCMAndroidSenderID:
                    return GetValue("YourSenderIDForDebug", "YourSenderIDForRELEASE");
                case ConfigKeys.FCMAndroidAPIKEY:
                    return GetValue("YourWebAPIKEYForDebug", "YourWebAPIKEYForRELEASE");
                default:
                    return string.Empty;
            }
        }

        public static string GetValue(string debugValue, string releaseValue)
        {
#if DEBUG
            return debugValue;
#elif RELEASE
            return releaseValue;
#else
            return string.Empty;
#endif
        }

Code for refresh token

   [Service]
    [IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
    public class MyFirebaseIIDService : FirebaseInstanceIdService
    {
        const string TAG = "MyFirebaseIIDService";
        public override void OnTokenRefresh()
        {
            var refreshedToken = FirebaseInstanceId.Instance.Token;
            SendRegistrationToServer(refreshedToken);
        }
        void SendRegistrationToServer(string token)
        {
            // Add custom implementation, as needed.
        }
    }

Code for receive message from app server

  [Service]
    [IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
    public class MyFirebaseMessagingService : FirebaseMessagingService
    {
        const string TAG = "MyFirebaseMsgService";

        public override void OnMessageReceived(RemoteMessage message)
        {
            SendNotification(message.GetNotification().Body);
        }

        void SendNotification(string messageBody)
        {
            var intent = new Intent(this, typeof(MainActivity));
            intent.AddFlags(ActivityFlags.ClearTop);
            var pendingIntent = PendingIntent.GetActivity(this, 0 /* Request code */, intent, PendingIntentFlags.OneShot);

            var defaultSoundUri = RingtoneManager.GetDefaultUri(RingtoneType.Notification);
            var notificationBuilder = new NotificationCompat.Builder(this)
                .SetContentTitle("FCM Message")
                .SetContentText(messageBody)
                .SetAutoCancel(true)
                .SetSound(defaultSoundUri)
                .SetContentIntent(pendingIntent);

            var notificationManager = NotificationManager.FromContext(this);

            notificationManager.Notify(0, notificationBuilder.Build());
        }
    }

App server code example

  try
            {

                string applicationID = "firebase.google.com cloud message server key";

                string senderId = "sender ID";

                string deviceId = "device created by your device, emulator or actual device";

                WebRequest tRequest = WebRequest.Create("https://fcm.googleapis.com/fcm/send");
                tRequest.Method = "post";
                tRequest.ContentType = "application/json";
                var data = new
                {
                    // send to device
                    //to = deviceId,
   // send to subscribed topic "test"                 
   to = "/topics/Test",
                    

                    notification = new
                    {
                        body = "body",
                        title = "my title",
                        sound = "Enabled"

                    }
                };

                var json = JsonConvert.SerializeObject(data);
                Byte[] byteArray = Encoding.UTF8.GetBytes(json);
                tRequest.Headers.Add(string.Format("Authorization: key={0}", applicationID));
                tRequest.Headers.Add(string.Format("Sender: id={0}", senderId));
                tRequest.ContentLength = byteArray.Length;
                using (Stream dataStream = tRequest.GetRequestStream())
                {
                    dataStream.Write(byteArray, 0, byteArray.Length);
                    using (WebResponse tResponse = tRequest.GetResponse())
                    {
                        using (Stream dataStreamResponse = tResponse.GetResponseStream())
                        {
                            using (StreamReader tReader = new StreamReader(dataStreamResponse))
                            {
                                String sResponseFromServer = tReader.ReadToEnd();
                                string str = sResponseFromServer;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                string str = ex.Message;
            }

That's it

You could either use above app server code to send message or go to Firebase UI to send message to your device.

What's more

How to change project ID, sender ID for different Enviroment and since have to include google-services.json to the project?

Things for watch out

the topic should be match this format [a-zA-Z0-9-_.~%]{1,900}, otherwise will get exceptin error.

{Java.Lang.IllegalArgumentException: Invalid topic name:

Reference