(Tutorial Android) Push Notification using Firebase Cloud Messaging (FCM)

Wednesday, July 19, 2017

Firebase Cloud Messaging adalah layanan push notifikasi cross-platform yang dikembangkan oleh Google yang sebelumnya menggantikan GCM, yang memungkinkan kita mengirimkan push notifikasi ke pengguna. Layanan FCM ini sepenuhnya gratis dan tidak dibatasi.

Pada tutorial kali ini saya akan membahas cara mengimplementasikan FCM di Android.

Firebase Cloud Messaging pada umumnya memiliki beberapa tipe notifikasi. Tipe yang akan kita coba pada tutorial ini adalah Notification Message. Tipe notifikasi ini merupakan tipe yang pada umumnya digunakan untuk mengirimkan push notification.

Contoh data yang dikirimkan berupa json sebagai berikut :
{
    "to": "e1w6hEbZn-8:APA91bEUIb2JewYCIiApsMu5JfI5Ak...",
    "notification": {
        "body": "Hello? This is push notification :)",
        "title": "Push Notification",
        "icon": "ic_launcher"
    }
}
Kita dapat juga memilih kemana kita akan mengirimkan push notification tersebut. Misal kita ingin mengirim push notification ke device tertentu bisa menggunakan FCM registration token dari device tersebut. Atau ke segment-segment tertentu bisa dengan mengirimkannya ke topics di firebase.

Itu dia sedikit penjelasannya dari saya. Nah sekarang kita langsung praktek aja.

Sebelumnya buat project baru dulu di Android Studio.

Setelah selesai buat project baru, lalu kita harus login ke firebase console. Silahkan login dulu dengan akun google agan-agan kemudian buka halaman https://firebase.google.com/ lalu klik Go To Console.


Halaman dashboard akan tampak seperti gambar di bawah ini. Untuk membuat project baru klik Add project.


Buat project baru kemudian isi Project name dan Country.


Setelah itu masuk ke menu notification. Di sini ada 2 pilihan platform yang bisa kita pilih, berhubung tutorial kita tentang Android maka kita pilih platform Android.


Setelah itu muncul form untuk mengisi nama package, nickname dan debug certificate SHA-1. Untuk mendapatkan debug certificate, buka terminal atau command prompt dan perintahnya bisa lihat di https://developers.google.com/android/guides/client-auth.


Kemudian download google-services.json lalu letakkan di dalam folder project→app.


Setelah aplikasi di daftarkan di firebase console, kemudian kita masuk ke project baru yang sudah dibuat.

Buka build.gradle pada bagian Top-Level dan tambahkan dependencies berikut.
dependencies {
    ...
    classpath 'com.google.gms:google-services:3.1.0'
    // NOTE: Do not place your application dependencies here; they belong
    // in the individual module build.gradle files
}
Lalu build.gradle pada bagian Module-Level tambahkan plugin dan library firebase.
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:25.0.1'
    compile 'com.google.firebase:firebase-messaging:11.0.2'
    testCompile 'junit:junit:4.12'
}
// Add to the bottom of the file
apply plugin: 'com.google.gms.google-services'
Setelah itu re-build project.

Jika agan menemukan error di bawah, mungkin Google Repository agan belum di update. Silahkan buka SDK Manager lalu update Google Repository.


Sampai di sini kita lanjut ke bagian desain layout.

Buat layout dengan nama activity_main.xml lalu tambahkan kode berikut :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    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"
    android:orientation="vertical"
    tools:context="id.co.blogspot.wimsonevel.android_pushnotification.MainActivity">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:src="@drawable/firebase_lockup_400"
        tools:ignore="ContentDescription" />

    <Switch
        android:id="@+id/switchNews"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="16dp"
        android:gravity="start"
        android:checked="false"
        android:text="@string/news"/>

    <Switch
        android:id="@+id/switchPromo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="16dp"
        android:gravity="start"
        android:checked="false"
        android:text="@string/promo" />

    <Button
        android:id="@+id/btn_token"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:text="@string/show_token"/>

    <TextView
        android:id="@+id/tv_token"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="16dp" />

</LinearLayout>
Dan beberapa resources lainnya.

strings.xml
<resources>
    <string name="app_name">Android-PushNotification</string>

    <string name="token">Token : %s</string>
    <string name="news">News</string>
    <string name="promo">Promo</string>
    <string name="show_token">Show Token</string>

</resources>
colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#FFCC01</color>
    <color name="colorPrimaryDark">#FFA701</color>
    <color name="colorAccent">#FF4081</color>
</resources>
Selanjutnya kita masuk ke bagian coding java-nya. Buat kelas-kelas java di bawah ini :

MyFirebaseInstanceIDService.java
import android.util.Log;

import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;

/**
 * Created by Wim on 7/15/17.
 */

public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {

    private static final String TAG = "MyFirebaseIIDService";

    @Override
    public void onTokenRefresh() {
        // Get updated InstanceID token.
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
        Log.d(TAG, "Refreshed token: " + refreshedToken);

        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // Instance ID token to your app server.
        sendRegistrationToServer(refreshedToken);
    }

    private void sendRegistrationToServer(String token) {
        // TODO: Implement this method to send token to your app server.
    }

}
Kelas ini merupakan firebase service untuk mendapatkan token unik yang selalu diupdate. Nah, token inilah nantinya yang akan membedakan device satu dengan device lainnya.

MyFirebaseMessagingService.java
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;

/**
 * Created by Wim on 7/15/17.
 */

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    private static final String TAG = "MyFirebaseMsgService";

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

        // TODO(developer): Handle FCM messages here.
        Log.d(TAG, "From: " + remoteMessage.getFrom());

        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
            Log.d(TAG, "Message data payload: " + remoteMessage.getData());

        }

        // Check if message contains a notification payload.
        if (remoteMessage.getNotification() != null) {
            Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
            sendNotification(remoteMessage.getNotification().getBody());
        }

    }

    private void sendNotification(String messageBody) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        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.mipmap.ic_launcher)
                .setContentTitle("FCM Message")
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        notificationManager.notify(0, notificationBuilder.build());
    }

}
Kelas ini berfungsi untuk menerima message dari push notification. Message diterima melalui method onMessageReceived(RemoteMessage remoteMessage).

Lanjutkan dengan membuat kelas activity dengan nama MainActivity.java
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;

import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.messaging.FirebaseMessaging;

public class MainActivity extends AppCompatActivity {

    private static final String PREF_SWITCH_NEWS = "switch_news";
    private static final String PREF_SWITCH_PROMO = "switch_promo";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        Switch switchNews = (Switch) findViewById(R.id.switchNews);
        Switch switchPromo = (Switch) findViewById(R.id.switchPromo);
        Button btnToken = (Button) findViewById(R.id.btn_token);

        btnToken.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String token = FirebaseInstanceId.getInstance().getToken();
                TextView tvToken = (TextView) findViewById(R.id.tv_token);
                tvToken.setText(getResources().getString(R.string.token, token));

                Log.i("TOKEN", token);
            }
        });

        switchNews.setChecked(isSwitchChecked(PREF_SWITCH_NEWS));
        switchPromo.setChecked(isSwitchChecked(PREF_SWITCH_PROMO));

        switchNews.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
                setSwitchChecked(PREF_SWITCH_NEWS, checked);

                if(checked) {
                    FirebaseMessaging.getInstance().subscribeToTopic("news");
                    Toast.makeText(getApplicationContext(), "Subscribe to News Topic" , Toast.LENGTH_SHORT).show();
                }else{
                    FirebaseMessaging.getInstance().unsubscribeFromTopic("news");
                    Toast.makeText(getApplicationContext(), "Unsubscribe from News Topic" , Toast.LENGTH_SHORT).show();
                }

            }
        });

        switchPromo.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
                setSwitchChecked(PREF_SWITCH_PROMO, checked);

                if(checked) {
                    FirebaseMessaging.getInstance().subscribeToTopic("promo");
                    Toast.makeText(getApplicationContext(), "Subscribe to Promo Topic", Toast.LENGTH_SHORT).show();
                }else{
                    FirebaseMessaging.getInstance().unsubscribeFromTopic("promo");
                    Toast.makeText(getApplicationContext(), "Unsubscribe from Promo Topic", Toast.LENGTH_SHORT).show();
                }

            }
        });
    }

    private void setSwitchChecked(String permission, boolean isChecked) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        SharedPreferences.Editor editor = preferences.edit();
        editor.putBoolean(permission, isChecked);
        editor.apply();
    }

    private boolean isSwitchChecked(String permission) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        return preferences.getBoolean(permission, false);
    }
}

Pada kode di atas, untuk men-subscibe atau men-unsubscribe ke topik yang diinginkan tinggal memanggil method :
FirebaseMessaging.getInstance().subscribeToTopic("news");

FirebaseMessaging.getInstance().unsubscribeFromTopic("news");
Terakhir, tambahkan service di AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="id.co.blogspot.wimsonevel.android_pushnotification">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- [START fcm_default_icon] -->
        <!-- Set custom default icon. This is used when no icon is set for incoming notification messages.
             See README(https://goo.gl/l4GJaQ) for more. -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_icon"
            android:resource="@mipmap/ic_launcher" />
        <!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
             notification message. See README(https://goo.gl/6BKBk7) for more. -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_color"
            android:resource="@color/colorAccent" />
        <!-- [END fcm_default_icon] -->

        <!-- [START firebase_service] -->
        <service
            android:name=".MyFirebaseMessagingService">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT"/>
            </intent-filter>
        </service>
        <!-- [END firebase_service] -->
        <!-- [START firebase_iid_service] -->
        <service
            android:name=".MyFirebaseInstanceIDService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
            </intent-filter>
        </service>
        <!-- [END firebase_iid_service] -->

    </application>

</manifest>
Build dan jalankan maka tampilannya seperti berikut.



Push Notification melalui Firebase Console

Sekarang kita akan coba mengirimkan push notification dari firebase console.


Klik Send Message, di aplikasi langsung menerima push notification.


Lalu kita tes juga mengirim push notification ke topik news.


Pada aplikasi, aktifkan pemberitahuan news maka akan mendapatkan push notification di topik news.


Push Notification melalui backend PHP

Selain dari firebase console kita juga dapat mengirimkan push notification dari PHP. Di sini yang dibutuhkan adalah alamat url dan server key. Untuk melihat server key bisa dilihat di menu firebase console bagian settings.


Copy Server key agan, kemudian buat kode php berikut :

index.php
<html>
    <head>
        <title>Firebase Cloud Messaging</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">

        <style>
            input[type=text], select {
                width: 100%;
                padding: 12px 20px;
                margin: 8px 0;
                display: inline-block;
                border: 1px solid #ccc;
                border-radius: 4px;
                box-sizing: border-box;
            }

            input[type=submit] {
                background-color: #4CAF50;
                color: white;
                padding: 14px 20px;
                margin: 8px 0;
                border: none;
                border-radius: 4px;
                cursor: pointer;
            }

            input[type=submit]:hover {
                background-color: #45a049;
            }

        </style>
        
    </head>
    <body>
        <h3>Firebase Cloud Messaging</h3>

        <div>
          <form action="index.php" method="get">
            <label for="token">FCM Registration Token</label>
            <input type="text" id="token" name="token" placeholder="Input Token">

            <label for="message">Message</label>
            <input type="text" id="message" name="message" placeholder="Input Message">
            
            <input type="hidden" name="type" value="single" >
            <input type="submit" value="Kirim">
          </form>
            
            
          <form action="index.php">
            <label for="fname">Topics</label>
              
            <select name="topics">
              <option value="news">News</option>
              <option value="promo">Promo</option>
            </select>

            <label for="lname">Message</label>
            <input type="text" id="message" name="message" placeholder="Input Message">
              
            <input type="hidden" name="type" value="topics" >
            <input type="submit" value="Kirim">
          </form>
            
        </div>

        <?php
        // Enabling error reporting
        error_reporting(-1);
        ini_set('display_errors', 'On');
 
        $type = isset($_GET['type']) ? $_GET['type'] : '';
        
        $fields = NULL;
        
        if($type == "single") {
            $token = isset($_GET['token']) ? $_GET['token'] : '';
            $message = isset($_GET['message']) ? $_GET['message'] : '';
            
            $res = array();
            $res['body'] = $message;
            
            $fields = array(
                'to' => $token,
                'notification' => $res,
            );
        
            echo 'FCM Reg Id : '. $token . '<br/>Message : ' . $message;
        }else if($type == "topics") {
            $topics = isset($_GET['topics']) ? $_GET['topics'] : '';
            $message = isset($_GET['message']) ? $_GET['message'] : '';
            
            $res = array();
            $res['body'] = $message;
            
            $fields = array(
                'to' => '/topics/' . $topics,
                'notification' => $res,
            );
            
            echo json_encode($fields);
            echo 'Topics : '. $topics . '<br/>Message : ' . $message;
        }
        
        // Set POST variables
        $url = 'https://fcm.googleapis.com/fcm/send';
        $server_key = "SERVER KEY AGAN";
        
        $headers = array(
            'Authorization: key=' . $server_key,
            'Content-Type: application/json'
        );
        // Open connection
        $ch = curl_init();
 
        // Set the url, number of POST vars, POST data
        curl_setopt($ch, CURLOPT_URL, $url);
 
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 
        // Disabling SSL Certificate support temporarly
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
 
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
 
        // Execute post
        $result = curl_exec($ch);
        if ($result === FALSE) {
            echo 'Curl failed: ' . curl_error($ch);
        }
 
        // Close connection
        curl_close($ch);
               
        ?>
        
    </body>
</html>
Sekarang silahkan agan coba mengirim push notification. (Tested : 100% work)


Jika ingin mempelajari lebih lanjut silahkan lihat di dokumentasinya di https://firebase.google.com/docs/.

Source code lengkap dapat dilihat di https://github.com/wimsonevel/Android-PushNotification

Sekian dulu tutorial kali ini semoga bermanfaat.
Don’t forget to share, thanks :)

Share this :

Previous
Next Post »
34 Komentar
This comment has been removed by the author. - Hapus
avatar

aku coba send message dari FCM tp kenapa "no topic found" gan?

Balas
avatar

gpp gan abaikan saja, aslinya bisa kok

Balas
avatar

Gan, bantuin cara biar switch nya klo di close app tetap ke save. Buat tugas skripsi. Thanks

Balas
avatar

tutorialnya sudah ane update gan, skrg udh bisa save kondisi switchnya..

Balas
avatar

Terimakasih gan. Sukses untuk blog nya

Balas
avatar

Gan, itu bisa gak file Php nya kirim Notifikasi ke All User. jadi gak perlu masukan Token lagi.. Trims

Balas
avatar

klo itu ane jg masih nyari2 caranya gan, klo mau ngirim notif ke smua device msh hrs lewat consolenya.., tpi bisa diakalin dgn ngirim ke topic yg di subscribe oleh devicenya

Balas
avatar

gan, notifnya gak muncul kalo app di tutup ya?

Balas
avatar

Gan, kalo aplikasinya (php & android) ga connect ke internet (dijalanin local) apakah ada caranya ? thanks

Balas
avatar

harus connect internet gan, kalaupun gak connect internet tetep bisa running cuma push notificationnya di pending sampai connect lg ke internet..

Balas
avatar

gan input token itu dapatnya dari mana ya???

Balas
avatar

bang, itu file php nya kok kalo refresh page langsung ngirim ulang notif nya ?

Balas
avatar

kurang tau gan, kalo ane ngetesnya ketika klik tombol kirim aja baru ngirim notif,, kalo misalkan bermasalah disitu di utak-atik aja file phpnya gan..

Balas
avatar

Gan ada yg untuk versi ionic/Cordova gak?

Balas
avatar

Iya gan dapet tokennya darimana? tolong dijawaba

Balas
avatar

tutorialnya udh gk bisa, MOHON DIPERBAIKI!

Balas
avatar

bisa dibantu gan
saya coba error nya ini
error: cannot access zzbck
class file for com.google.android.gms.internal.zzbck not found

Balas
avatar

mantap gan tutorialnya, lancar jaya running, sya lgi coba pake kotlin nih..

Balas
This comment has been removed by the author. - Hapus
This comment has been removed by the author. - Hapus
This comment has been removed by the author. - Hapus
avatar

Kalo misalkan mau ngasih notifikasi tanpa harus masuk ke firebase konsol gimana masbro? Maap masih kurang paham nih

Balas
avatar

Gan.. kalo misal notifikasinya dinamis gimana ya gan? Misal sebuah aplikasi sudah jadi, ngga mungkin dong dri sisi backend sistem mengirim notifikasi dg cara buka firebase console.. apakah bisa, mengirim notifikasi dari firebase console, dg cara dijembatani suatu CMS/backend.. thx gan๐Ÿ™

Balas
avatar

Gokil, makasih gan tutorialnya mudah dimengerti dan simple, terutama bagian phpnya, ini yang saya cari.
@masrurin s, getToken() udah deprecated, bisa ikutin instruksi jawaban ini : https://stackoverflow.com/a/51129304
mudah dimengerti dan simple, kepanjangan klo ditulis disini hehe.

@Muhammad Ajat Jatmika, @Unknown, kalo mau ngirim dinamis push notifnya, logikanya gini aja :
Tinggal ambil script php pas ngirim by tokennya aja, dengan asumsi token agan udah disimpen ke database untuk masing" user, jadi tinggal get from database aja tokennya. (cara nyimpen token ke database bisa pas login ke aplikasi, save berdasarkan siapa yg login)
Kalo messagenya, bisa kustom sesuai kebutuhan agan, selesai deh.

Balas
avatar

gan punya ane kok sama sekali gak muncul apa-apa, gimana solusinya padahal di kodingan gak ada yang error ?

Balas
avatar

Gan, terima kasih untuk ilmunya.. tapi kalo boleh saya bertanya, ketika App sedang di close atau di background App, saat notif di klik activity yang dibuka adalah activity launcher atau activity awal yang kita set di AndroidManifest. Bukan membuka Activity yang sudah kita set dari Intent dan PendingIntent nya, Solusinya gimana ya gan? Kalo app nya lagi dibuka sih aman

Balas
avatar

yang file phpnya gak bisa gan
gak muncul notif

Balas
avatar

Thank you for sharing nice article!I really loved reading your blog about thereact native push notifications.I also found your posts very interesting. In fact, after reading, I had to go show it to my friend and he enjoyed it as well!!!!

Balas
avatar

di firebase saya kok ngga ada legacy server key nya yah
mohon bantuannya ..

Balas

Penulisan markup di komentar
  • Silakan tinggalkan komentar sesuai topik. Komentar yang menyertakan link aktif, iklan, atau sejenisnya akan dihapus.
  • Untuk menyisipkan kode gunakan <i rel="code"> kode yang akan disisipkan </i>
  • Untuk menyisipkan kode panjang gunakan <i rel="pre"> kode yang akan disisipkan </i>
  • Untuk menyisipkan quote gunakan <i rel="quote"> catatan anda </i>
  • Untuk menyisipkan gambar gunakan <i rel="image"> URL gambar </i>
  • Untuk menyisipkan video gunakan [iframe] URL embed video [/iframe]
  • Kemudian parse kode tersebut pada kotak di bawah ini
  • © 2015 Simple SEO ✔

Ads