FCM
As everyone knows the importance of push notification in apps, we will discuss FCM (Firebase Cloud Messaging) in this article.
Let’s see what the definition of FCM is.
Firebase Cloud Messaging is a powerful API that lets you deliver the messages reliably and independently of the platform you are developing on. With the help of FCM, you can send notification and message to your client’s app. We can send instant messages of up to 4KB in size.
Before moving ahead, we will summarize how we are going to implement it.
- We are going to develop an Android app that will display the notification.
- Setting up FCM.
- Saving token ID generated from android device to server using web service developed in .net
- Sending notification message from C# code.
Android app to display a notification
- First, let us create a new Android Studio Project with an Empty Activity.
- Once your project is loaded, click on "Firebase" from the Tools menu. With Android Studio 2.2, it is really easy to integrate Firebase into your project.
- All the available features will get opened. Click "Cloud Messaging".
- Click on "Set up Firebase Cloud Messaging".
- Click on the "Connect to Firebase" button. A dialog will open.
- Enter the project name and click on "Connect to Firebase".
- Click on the button "Add FCM to your app" and you will see a dialog box.
- Click on "Accept Changes".
- Every device generates a unique token or device id to receive notifications. And for this, we have to create a class that will extend the class FirebaseInstanceIdService. So, we have created MyFirebaseInstanceIDService.java
- To store the generated token in SharedPreferences, we have created SharedPrefManager.java in Singleton Pattern.
- To actually receive the notification FirebaseMessagingService is used, so we will create MyFirebaseMessagingService.java.
- We will edit the activity_main.xml file.
- Also, we will edit the MainActivity.java file.
- Also, edit the AndroidManifest.xml file.
MyFirebaseInstanceIDService.java
- package com.infobytessolutions.sretailer;
-
-
-
-
- import android.util.Log;
-
- import com.google.firebase.iid.FirebaseInstanceId;
- import com.google.firebase.iid.FirebaseInstanceIdService;
-
- public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
-
- private static final String TAG = "MyFirebaseIIDService";
-
- @Override
- public void onTokenRefresh() {
-
-
- String refreshedToken = FirebaseInstanceId.getInstance().getToken();
-
-
- Log.d(TAG, "Refreshed token: " + refreshedToken);
-
-
- storeToken(refreshedToken);
- }
-
- private void storeToken(String token) {
-
- SharedPrefManager.getInstance(getApplicationContext()).saveDeviceToken(token);
- }
- }
SharedPrefManager.java
- package com.infobytessolutions.sretailer;
-
-
-
-
- import android.content.Context;
- import android.content.SharedPreferences;
-
- public class SharedPrefManager {
- private static final String SHARED_PREF_NAME = "FCMSharedPref";
- private static final String TAG_TOKEN = "tagtoken";
-
- private static SharedPrefManager mInstance;
- private static Context mCtx;
-
- private SharedPrefManager(Context context) {
- mCtx = context;
- }
-
- public static synchronized SharedPrefManager getInstance(Context context) {
- if (mInstance == null) {
- mInstance = new SharedPrefManager(context);
- }
- return mInstance;
- }
-
-
- public boolean saveDeviceToken(String token){
- SharedPreferences sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = sharedPreferences.edit();
- editor.putString(TAG_TOKEN, token);
- editor.apply();
- return true;
- }
-
-
- public String getDeviceToken(){
- SharedPreferences sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
- return sharedPreferences.getString(TAG_TOKEN, null);
- }
-
- }
MyFirebaseMessagingService.java
- package com.infobytessolutions.sretailer;
-
-
-
-
- import android.app.NotificationManager;
- import android.app.PendingIntent;
- import android.content.Context;
- import android.content.Intent;
- import android.media.RingtoneManager;
- import android.net.Uri;
- import android.support.v4.app.NotificationCompat;
- import android.util.Log;
-
- import com.google.firebase.messaging.FirebaseMessagingService;
- import com.google.firebase.messaging.RemoteMessage;
-
- import org.json.JSONException;
- import org.json.JSONObject;
-
- public class MyFirebaseMessagingService extends FirebaseMessagingService {
-
- private static final String TAG = "MyFirebaseMsgService";
- @Override
- public void onMessageReceived(RemoteMessage remoteMessage) {
- if (remoteMessage.getData().size() > 0) {
- Log.e(TAG, "Data Payload: " + remoteMessage.getData().toString());
- try {
- JSONObject json = new JSONObject(remoteMessage.getData().toString());
-
- sendNotification(json);
- } catch (Exception e) {
- Log.e(TAG, "Exception: " + e.getMessage());
- }
- }
- }
-
- private void sendNotification(JSONObject json) {
- Intent intent = new Intent(this, MainActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- Log.e(TAG, "Notification JSON " + json.toString());
- try{
- JSONObject data = json.getJSONObject("data");
- String title = data.getString("title");
- String message = data.getString("message");
- String imageUrl = data.getString("image");
-
- PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 , intent,
- PendingIntent.FLAG_ONE_SHOT);
-
- Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
- NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
- .setSmallIcon(R.drawable.ic_launcher_background)
- .setContentTitle(title)
- .setContentText(message)
- .setAutoCancel(true)
- .setSound(defaultSoundUri)
- .setContentIntent(pendingIntent);
-
- NotificationManager notificationManager =
- (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
-
- notificationManager.notify(0 , notificationBuilder.build());
-
- } catch (JSONException e) {
- Log.e(TAG, "Json Exception: " + e.getMessage());
- } catch (Exception e) {
- Log.e(TAG, "Exception: " + e.getMessage());
- }
- }
- }
activity_main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/activity_main"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- tools:context=".MainActivity">
-
- <EditText
- android:id="@+id/editTextPhoneNo"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_above="@+id/buttonRegister"
- android:hint="Enter Phone No"
- android:inputType="phone" />
-
- <Button
- android:layout_centerVertical="true"
- android:text="Register Device"
- android:id="@+id/buttonRegister"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </RelativeLayout>
MainActivity.java
AndroidManifest.xml
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.infobytessolutions.sretailer">
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
- <uses-permission android:name="android.permission.WAKE_LOCK"/>
- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
- <uses-permission android:name="android.permission.VIBRATE" />
- <permission
- android:name="${applicationId}.permission.C2D_MESSAGE"
- android:protectionLevel="signature"/>
- <uses-permission android:name="${applicationId}.permission.C2D_MESSAGE"/>
-
- <application
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:roundIcon="@mipmap/ic_launcher_round"
- android:supportsRtl="true"
- android:theme="@style/AppTheme">
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name"
- android:theme="@style/AppTheme.NoActionBar">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <service
- android:name=".MyFirebaseInstanceIDService">
- <intent-filter>
- <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
- </intent-filter>
- </service>
- <service
- android:name=".MyFirebaseMessagingService">
- <intent-filter>
- <action android:name="com.google.firebase.MESSAGING_EVENT"/>
- </intent-filter>
- </service>
- </application>
-
- </manifest>
Setting up FCM in Firebase console
- Now, put your app name and select your country.
- Now, click "Add Firebase to your Android app".
- Now, you have to enter your project's package name and click on "Add App".
- After this, you will get a google-services.json file by going to the Project Settings.
- Go to the root level build.gradle file and add the following code.
- buildscript {
- repositories {
- jcenter()
- google()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:3.0.1'
-
- classpath 'com.google.gms:google-services:3.1.0'
- }
- }
- allprojects {
- repositories {
- jcenter()
- google()
- }
- }
- task clean(type: Delete) {
- delete rootProject.buildDir
- }
- Inside app level build.gradle file, make the following changes.
- apply plugin: 'com.android.application'
-
- android {
- compileSdkVersion 26
- defaultConfig {
- applicationId "com.infobytessolutions.sretailer"
- minSdkVersion 21
- targetSdkVersion 26
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
- }
-
- dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation 'com.android.support:appcompat-v7:26.1.0'
- implementation 'com.android.support:support-v4:26.1.0'
- implementation 'com.android.support:design:26.1.0'
- implementation 'com.android.support.constraint:constraint-layout:1.0.2'
- implementation 'com.google.firebase:firebase-messaging:10.2.1'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'com.android.support.test:runner:1.0.1'
- androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
- compile files('libs/ksoap2-android-assembly-2.5.8-jar-with-dependencies.jar')
- }
- apply plugin: 'com.google.gms.google-services'
Saving token ID generated from android device to server using web service developed in .net
If you have knowledge of creating a web service, then add the below code to it, else learn it by searching on Google because our main focus in this article is FCM.
- We have table “Customers” with phoneNo and tokenID columns.
- In my case, phone number values are already stored.
- [WebMethod]
- public void updateTokenID(string phoneNo, string TokenID) {
- int count = db.Customers.Where(c => c.PhoneNo == phoneNo).Count();
- Customer cust = db.Customers.FirstOrDefault(c => c.PhoneNo == phoneNo);
- cust.TokenID = TokenID;
- db.SubmitChanges();
- }
To run web service properly in Android, you have to add ksoap2-android-assembly-2.5.8-jar-with-dependencies.jar in Android project.
Also, have a look at mainactivity.java file's sendTokenToServer() method where web service call is handled.
Sending notification message from C# code
Create a new C# project and add the following class and call it in any event like button.
- public class FCMPushNotification {
- public FCMPushNotification() {
-
- }
- public bool Successful {
- get;
- set;
- }
- public string Response {
- get;
- set;
- }
- public Exception Error {
- get;
- set;
- }
- public FCMPushNotification SendNotification(string _title, string _message, string _topic, string deviceId) {
- FCMPushNotification result = new FCMPushNotification();
- try {
- result.Successful = true;
- result.Error = null;
-
- string serverKey = "Your server key";
- string senderId = "your sender id";
- var requestUri = "https://fcm.googleapis.com/fcm/send";
- WebRequest webRequest = WebRequest.Create(requestUri);
- webRequest.Method = "POST";
- webRequest.Headers.Add(string.Format("Authorization: key={0}", serverKey));
- webRequest.Headers.Add(string.Format("Sender: id={0}", senderId));
- webRequest.ContentType = "application/json";
- var data = new {
- to = deviceId,
-
- priority = "high",
- notification = new {
- title = _title,
- body = _message,
- show_in_foreground = "True",
- icon = "myicon"
- }
- };
- var serializer = new JavaScriptSerializer();
- var json = serializer.Serialize(data);
- Byte[] byteArray = Encoding.UTF8.GetBytes(json);
- webRequest.ContentLength = byteArray.Length;
- using(Stream dataStream = webRequest.GetRequestStream()) {
- dataStream.Write(byteArray, 0, byteArray.Length);
- using(WebResponse webResponse = webRequest.GetResponse()) {
- using(Stream dataStreamResponse = webResponse.GetResponseStream()) {
- using(StreamReader tReader = new StreamReader(dataStreamResponse)) {
- String sResponseFromServer = tReader.ReadToEnd();
- result.Response = sResponseFromServer;
- }
- }
- }
- }
- } catch (Exception ex) {
- result.Successful = false;
- result.Response = null;
- result.Error = ex;
- }
- return result;
- }
- }
How to get server key and sender id
- Go to Firebase Console and inside your project settings, go to Cloud Messaging tab.
- You will find the Cloud Messaging Server Key here, copy it.
So that’s it. Though a few mobile phones will kill this notification when an application is killed. I am working on it too. Feel free to comment, I would like to guide you if you are stuck somewhere and also like to learn more from you guys.