Android Studio 'da FCM (Firebase Cloud Messaging) İle Bildirim gönderme

Yazılarım

Yaptığımız mobil uygulamaları kullanıcılarımıza kullandırılmalarını sağlayabilmek için uygulamamız üzerinden bildirim gönderilmesi etkili yöntemlerinden biridir. Fakat burada orta yolu bulmak çok önemli olsa gerek sürekli bildirim yollayarak kullanıcıları sıkıp uygulamayı silmelerine neden de olabilmektedir. bu yüzden gereksiz bildirimlerden kaçınılması gerekmektedir. bildirim gönderme işlemleri 2 türlü gerçekleşmekte;  Google Cloud Messaging (GCM) ve Firebase Cloud Messaging (FCM) olarak 2 şekilde gerçekleştirilmektedir. Ancak 18 Nisan 2018 yılında GCM bildirim servislerini kapatarak (GCM servisi) Kullanıcılarına FCM  servislerine geçmelerini önermiştir. 

Anlatacağım yazı da php üzerinden post edeceğimiz verileri mysql veritabanda kayıt edilmesinin ardından uygulamanın yüklü olduğu android mobil cihazlara bildirim gidilmesi sağlanacaktır. Bildirim özelliğini uygulamamıza aktif ettirebilmemiz için Firebase hesabı, android uygulaması(bildirim gönderilecek) ve uygulamayı indiren kullanıcıların cihaz id(Token) bilgilerini veritabanımızda kullanarak bildirim gönderilebilmesi için yeterli olacaktır. yazının  anlaşılabilmesi için elimden geldikçe az resimler kullanarak anlatımı yalın bir şekilde anlatmaya çalışacağım.

1- Mysql Users Tablosu Oluşturmak (Kullanıcıların cihaz id bilgisini kaydetmek)

Bildirim gönderilecek olan kullanıcıları veritabanımıza kaydetmemiz gerekecektir. Tablomuzda PRIMARY KEY( birincil anahtar) olarak 'id' adında bir sütun ve Cihazın id bilgilerini tutmamızı sağlayacak 'Token' adında bir sütun bulunması gerekecektir.  Böylelikle mobil uygulamamızı indiren kişilerin cihaz id bilgilerini tutacağımız Users adında bir tablo oluşturduk. 

2- PHP dosyaları

Uygulamamızı indiren kişilerin id 'lerini kaydederek bildirim göndermek istediğimiz zaman users tablosunda bulunan kullanıcılara gönderilmesini sağlayacağız, kullanıcı kaydetmek  için kullaniciBilgileri.php dosyası oluşturarak kaydetme işlemlerini sağlayacağız. Bildirimlerin içeriğini android uygulamamıza post etmek için  bildirim.php dosyalarına kodlarımızı aşağıdaki gibi olması gerekmektedir.

kullaniciBilgileri.php

 if(isset($_POST["Token"])) {
   
     // Kullanici adi-> veritabanında girdiğimiz kullanıcı adı default olarak root kullanılır.
    // sifre> veritabanında girdiğimiz sifre default olarak 1234 kullanılır.
   $conn = mysqli_connect("localhost", "kullanici_adi", "sifre", "databaseName");
   $conn->set_charset("utf8");

   $token = $_POST["Token"];

        $query = "INSERT INTO users (Token) VALUES ( '$token') "
        ." ON DUPLICATE KEY UPDATE Token = '$token';";
        
        mysqli_query($con, $query) or die(mysqli_error($con));
        
        mysqli_close($con);

Yapacağımız mobil uygulamayla ilk ekran açıldığında oluşturduğumuz dosyamıza Token adında cihaz bilgileri post edilmesi sağlanacaktır. Yaptığım çalışmada mysqli veritabanını kullandım, farklı veritabanları kullanılarakta işlemler yapılabilir. kod bloğunun 4. satırda bağlantı için gerekli bağlantılar sağlanarak kullanacağımız veritabanına bilgiler kaydedilecektir. 8. satırda gelen token bilgisini alarak yazdığımız sql sorgusuyla kullanıcı bilgilerimizi kaydetmiş olduk. Uygulamalara bildirim gönderimlerini mobil cihazlara bildirimlerimizi 'bildirimIcerigi.php' dosyası ile gönderilmesini sağlayacağız. bildirimler real time(eş zamanlı) olarak gerçekleştirilmesi için firebase hesaplarımız ile ilişkilendirmemiz gerekecektir. firebase hesabı üzerinden giriş yaparak Firebase Cloud Messaging servislerinden bize verilen Apı anahtarını kullanarak işlemlerimizi gerçekleştirelim (3. adımda Firebase key anahtarı alınması işlemleri anlatılacaktır). 

bildirimIcerigi.php

    
    function sendPushNotification($to = '', $data = array()) {
        
        $apiKey = 'firebase_api_key_anahtari';
        
        $fields = array(
                        'to' => $to,
                        'data' => $data,
                        );
        
        $headers = array('Authorization: key='.$apiKey, 'Content-Type: application/json');
        
        $url = 'https://fcm.googleapis.com/fcm/send'; //firebase haberleşmesini sağlanacak url
        
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);   
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
        
        echo json_encode($fields);
          
        $result = curl_exec($ch);
        
        curl_close($ch);
        
        return json_decode($result, true);
    }
    
    //$to = "alıcıya ait olan mesaj 'dispositivos'-> android ile ilişkilendirilecek ";
      $to = "/topics/dispositivos";
    
    // bildirim olarak gönderilecek alanlar
    $data = array(
                  'title' => 'Bildirim başlığı',
                  'body' => 'Bildirim detayı'
                  );
    
    sendPushNotification($to,  $data)

bildirim icerigini gönderecek alanları da oluşturduğumuza göre php kısmında gerekli olan işlemleri tamamlamış olduk. Bildirim göndermek istediğimizde dosyamızı tetiklememiz yeterli olacaktır. tetikleme işlemi başladıktan sonra gerekli users tablosunda bulunan cihazlara bildirim gönderilme işlemi sağlanacaktır. burada tetikleme işlemini manuel olarak 'http://localhost/rifaikuci/bildirimIcerigi.php' adresine gidilerekte yapılabilir. bizim istediğimiz yöntemde ise yönetim panelinden eklenen duyurulara anlık olarak bildirim gönderilmesi sağlaması olduğu için yukarıda yazan kodlarımızı duyuruların mysql veritabanında kayıt edildiği alanlara yapılarak bildirim işlemleri yapılması daha kullanışlı olacaktır. verilerimizi android tarafından da alınabilmesi için $data kısmında bulunan değerler ile android 'deki karşılığı aynı olması gerekmektedir. bizim bildirim başlığı ve bildirim detayı olarak yazdığımız alanları post edilen veriler yazılarak duyurular dinamik bir hale getirilebilir. sendPushNotification dönüş değer tipini json formatına çevrilerek post edilmesi sağlandı. böylelikle android tarafından okunması kolaylıkla sağlanacaktır.

3- Firebase API Key Anahtarı Oluşturma

Firebase servislerini kullanabilmemiz için öncelikle bir google hesabına sahip olmamız gerekmektedir. Firebase linkine tıklayarak sayfaya ulaştıktan sonra google hesabımız varsa sağ üst köşede "Konsola Git" ekranı ile karşılaşılacaktır. Konsol sayfasında gidilerek daha önceden yapılan kayıtlı projelerimiz varsa görülecek ve yeni bir proje başlatılması sağlanacaktır. Projemizi oluşturduktan sonra projemizi bilgileri görebilmek için sol  tarafta resimde de görülen proje ayarlarını değiştirmemiz için menü bulunmaktadır. burada yeni bir veritabanı, hafıza bilgileri gibi çeşitli ayarlandırmalar yapılabilmektedir. Bizim burada ihtiyacımız olan Cloud messaging servisini kullanabilmek için sunucu anahtarı gerekmektedir. Sunucu anahtarı bilgilerine ulaşabilmek için resimde görüldüğü gibi projeye genel bakış menüsünden proje ayarlarına tıklanarak bizi ayarlar menüsüne yönlendirecektir.

Firebase proje ayarlarına genel bakış

Ayarlar menüsünde çeşitli servisler bulunmaktadır. Bizim için gerekli olan Cloud Messaging menüsüne gelerek proje kimlik bilgilerinden "sunucu anahtar" da projemiz için hazırlanan id bilgisini kopyalayıp 'bildirimIcerigi.php' dosyasında  $apikey değişkenine atayarak firebase kısmında gerekli işlemlerimizi bitirmiş olduk.

Firebase apikey şifreleri

 

4- Android Uygulamasında Bildirim İçeriğini Ayarlamak

Bildirim gönderme işleminde php ve firebase kısımlarını bitirdikten sonra android kısmında gerekli kodları yazılarak işlemimizi bitirmiş olacağız. Android kısmında ilk olarak yapmamız gereken uygulamamıza firebase ayarlarını bağlamak olacaktır. Android studio kurulurken firebase eklentili bir şekilde kullanıma hazır olarak gelmektedir. Android studio açıldığında üst kısmında bulunan Tools(araçlar) menüsünü seçtiğimizden sağ taraftan açılır pencerede assistant penceresinden Cloud messaging tıklayarak connect(bağlan) tıklayarak projemize firebase bağlanma işlemlerini başlatmış olduk. Projemizi bağladıktan sonra firebase için gerekli paketleri indirimemiz gerekmektedir;

"build.gradle(Project)" 

dependencies {
        classpath 'com.google.gms:google-services:4.0.1'
    }

"build.gradle(Module)" 

dependencies {

    implementation 'com.google.firebase:firebase-core:16.0.1'
    implementation 'com.google.firebase:firebase-messaging:17.3.4'

    implementation 'com.android.volley:volley:1.1.0'

}

"AndroidManifest.xml


     <application

       .
       .
       . 
       .
       .
       .

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <meta-data
    android:name= "com.google.firebase.messaging.default_notification_icon"
    android:resource= "@drawable/logo" />
    <meta-data
        android:name="com.google.firebase.messaging.default_notification_color"
        android:resource="@color/colorPrimary"/>

    <service android:name=".firebase.MyFirebaseMessagingService">

        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT"/>
        </intent-filter>

    </service>
         

Uygulamamızda build.gradle dosyasında gerekli paketlerin indirme işlemlerini hallettikten sonra "AndroidManifest.xml" dosyasında bildirim logosunu üst panelde olacak renkleri seçme işlemini yaptık. "MyFirebaseMessagingService"  uygulama indirilirken arka planda ilk gireceği sınıf olacaktır. böylelikle uygulamayı indiren kullanıcıların cihaz bilgilerini veritabanına kaydetmesini sağlamış olacağız. bildirimin logosunu 'android:resource' üzerinden değiştirilebilir. şimdi de son işlem olan MyFirebaseMessagingService dosyasına göz atarak işlemlerimizi sonlandırmış olacağız.

Not: .firebase.MyFirebaseMessagingService olmasının nedeni kendi uygulamamda firebase paketinin altında oluşturduğumdan dolayıdır. uygulamanızı yazarken yollarını doğru belirtmeniz gerekecektir aksi takdirde hatalar ortaya çıkacaktır.

"MyFirebaseMessagingService.java"

package packageName;

import android.annotation.SuppressLint;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Build;

import androidx.core.app.NotificationCompat;

import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import com.rifaikuci.myapplication.DuyurularDetay;
import com.rifaikuci.myapplication.R;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Hashtable;
import java.util.Map;
import java.util.Random;

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);

        if(remoteMessage.getData() != null) { enviarNotificacion(remoteMessage); }

        if(remoteMessage.getNotification() != null) { enviarNotificacion(remoteMessage); }
    }

    private void enviarNotificacion(RemoteMessage remoteMessage) {
        Map data = remoteMessage.getData();
        String baslik = data.get("title");
        String detay = data.get("body");
       


        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        String NOTIFICATION_CHANNEL_ID = "com.rifaikuci.myApplication";



        // Versiyon O serisinden daha yüksekse
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            @SuppressLint("WrongConstant")
            NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID,
                    "Mi notificacion",
                    NotificationManager.IMPORTANCE_MAX
            );

            // bildirim kanal ayarlamaları default olarak kalabilir.
            channel.setDescription("xcheko51x channel para app");
            channel.enableLights(true);
            channel.setLightColor(Color.BLUE);
            channel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
            channel.enableVibration(true);

            manager.createNotificationChannel(channel);

        }
        //bildirim paneline tıkladıktan sonra gidilecek alan
        Intent intent = new Intent(this, DuyurularDetay.class);

        //gidilecek ekrana veri gönderme işlemleri
        //karşı taraftan gelen verileri almak için getIntent(valueIsmi) kullanilmali
        intent.putExtra("duyuruBaslik", title);
        intent.putExtra("duyuruDetay", body);
  
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK    );

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,    
           PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);



        builder.setAutoCancel(true)
         .setWhen(System.currentTimeMillis())
         .setTicker("Hearty365")
         .setContentTitle(title)// bildirim başlığı
         .setContentText(body) //tek satırlık bildirim detayı
         .setLights(Color.BLUE,1000,1000)//bildirimde sönen renk türü
         .setVibrate(new long[]{0, 1000, 500, 1000})//titreşim uzunluğu
         .setSmallIcon(R.drawable.logo) // bildirim logosu
         .setLargeIcon(bitmap) //resim bitmap türünde olmalı
         .setContentIntent(pendingIntent)//bildirimin istenilen ekrana geçiş yapılmasını sağlar
         .setContentInfo("body");

        // aynı uygulamadan birden fazla bildirim gelmesi koşulunda listelenmesini sağlar.
        Random random = new Random();
        int m = random.nextInt(9999 - 1000) + 1000;
        manager.notify(m, builder.build()); // birden fazla bildirim gelse bile sadece son bildirimin görüntülenmesi için m değerini herhangi sabit sayı ile değiştirmek yeterli olacaktır.
    }

    //cihaz id değeri kontrol edilir.
    @Override
    public void onNewToken(String token) {

        FirebaseMessaging.getInstance().subscribeToTopic("dispositivos");
        enviarTokenToServer(token); // id kayitli değilse kayıt işlemi için token değeri alınıp fonksiyona gönderilir.

    }

    // cihazın id bilgisi kaydedilir.
    private void enviarTokenToServer(final String token) {
        //id bilgisini yukarıda oluşturduğumuz kullaniciBilgileri.php dosyasına post ederek 
        // users tablosuna kayıt edilmiş oldu.
        StringRequest stringRequest = new StringRequest(Request.Method.POST,
                "https://rifaikuci.com/kullaniciBilgileri.php",
                new Response.Listener() {
            
            @Override public void onResponse(String response) { }}, new Response.ErrorListener() {
            @Override public void onErrorResponse(VolleyError error) { }}){
            @Override protected Map getParams()
                    throws AuthFailureError { Map parametres = new 
                    Hashtable();
                    parametres.put("Token", token);

                return parametres; }};
        
        RequestQueue requestQueue = Volley.newRequestQueue(this);
        
        requestQueue.add(stringRequest);
    }

   }

Android kısmında da gerekli kodlar yazılarak uygulamamızı bitirmiş olduk. Android kısmında gerekli olan kod açıklamaları yorum satırı olarak açıklamaya çalıştım. iyi çalışmalar.

Takıldığınız yerlerde aşağıda bulunan iletişim formundan sorabilirsiniz en yakın sürede geri dönüş yapılacaktır. sağlıcakla kalın. 

Ebu Hüreyre (r.a.)'den : Rasullah (s.a.v.): "İnsanları doğruluğa çağıran kimseye o yola uyanların sevabı gibi sevap verilir. O yola uyanların sevaplarından da hiçbir şey eksilmez. İnsanları sapıklığa çağıran kimseye o yola uyanların günahı gibi günah verilir. O yola uyanların günahlarından da hiçbir şey eksilmez. buyurdular. (Müslim, İlim 16)