관리 메뉴

막내의 막무가내 프로그래밍 & 일상

파이어베이스 FCM 노티피케이션(notification)하는 방법 정리 2019 본문

안드로이드/자바 & Previous

파이어베이스 FCM 노티피케이션(notification)하는 방법 정리 2019

막무가내막내 2019. 6. 12. 11:31
728x90

 

예를들어 카톡알림처럼 내가 누군가에게 채팅을 했을때 상대방에게 알림을 주고싶을 때 즉 , 디바이스에서 디바이스로 알림을 주고 싶은데 하는방법에 대해 포스팅해볼려고합니다. 

 

먼저 OkHttp3, 클라우드메세징 파이어베이스 관련된 것은 gradle에서 implementation 해줬다고 생각하고 진행해보도록 하겠습니다.

 //okHttp
    implementation 'com.squareup.okhttp3:okhttp:3.14.1'
    
   implementation 'com.google.firebase:firebase-messaging:17.3.4'

FCM을 하기위해서는 먼저 상대방의 토큰 값을 알아야합니다. 그래서 전 저의 토큰값을 데이터베이스에 저장하여 상대방이 저의 토큰을 데이터베이스를 통해 알고 푸시메세지를 쏴줄 수 있게 했습니다. 다음은 그 코드입니다.

 //fcm토큰 얻어서 디비에 저장해줌
    private void sendPushTokenToDB() {
        //파이어베이스
        FirebaseInstanceId.getInstance().getInstanceId()
                .addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
                    @Override
                    public void onComplete(@NonNull Task<InstanceIdResult> task) {
                        if (!task.isSuccessful()) {
                            Log.w(TAG, "getInstanceId failed", task.getException());
                            return;
                        }

                        // Get new Instance ID token
                        String token = task.getResult().getToken();
                        Map<String, Object> map = new HashMap<>();
                        map.put("fcmToken", token);
                        FirebaseHelper.db.collection("Users").document(FirebaseHelper.mUid).collection("FcmToken").document(FirebaseHelper.mUid).set(map);
                        finish();
                    }
                });
    }

 

 


 

 

 

package com.mtjinse.myapplication.activity.services;

import android.app.Notification;
import android.app.NotificationChannel;
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.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import com.mtjinse.myapplication.R;
import com.mtjinse.myapplication.activity.activities.MainActivity;

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    private static final String TAG = "MyFirebaseMsgService";

    /**
     * Called when message is received.
     *
     * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
        sendNotification(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody());
    }
    // [END receive_message]


    // [START on_new_token]

    /**
     * Called if InstanceID token is updated. This may occur if the security of
     * the previous token had been compromised. Note that this is called when the InstanceID token
     * is initially generated so this is where you would retrieve the token.
     */
    @Override
    public void onNewToken(String token) {
        Log.d(TAG, "Refreshed token: " + token);
    }
    // [END on_new_token]



    /**
     * Create and show a simple notification containing the received FCM message.
     *
     * @param messageBody FCM message body received.
     */
    private void sendNotification(String title, String messageBody) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);

        String channelId = getString(R.string.default_notification_channel_id);
        Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder =
                new NotificationCompat.Builder(this, channelId)
                        .setSmallIcon(R.drawable.com_facebook_button_icon)
                        .setContentTitle(title)
                        .setContentText(messageBody)
                        .setAutoCancel(true)
                        .setSound(defaultSoundUri)
                        .setContentIntent(pendingIntent);

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

        // Since android Oreo notification channel is needed.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("fcm_default_channel",
                    "fcm_default_channel",
                    NotificationManager.IMPORTANCE_DEFAULT);
            notificationManager.createNotificationChannel(channel);
        }

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }
}

1. FirebaseMessagingService를 상속한 서비스를 만들어줍니다. 구글 파이어베이스 문서에는 해당 클래스에 다른 메소드들도 몇개 더 써져있으나 저는 안쓰므로 이렇게 3가지 메소드만 남겨주었습니다. 오레오 버전부터는 노티피케이션 채널이 필요한데 저는 fcm_default_channel 이라고 지었습니다. 원하시는대로 짓되 통일되게만 해주시면 됩니다. 

그리고 notify()에서 0 /*ID 는 노피케이션의 아이디인데 이게 숫자를 0으로고정해놓으면 알림이 한개가왔으면 거기에 이어서 하나 더 온 경우, 하나의 알림창에 중복되서 뜬다. 즉 위에 뜨는 알림창 하나에 모든 알림 정보를 중첩해서 넣는다는거다. 만약 아이디를 다르게 보내면 알림창이 1개, 2개, 3개 이렇게 각각 구분해서 뜬다.

 

그리고 PendingIntent는 알림을 눌렀을 때 해당 액티비티로 이동할 수 있게해준다. 일반 인텐트처럼 putExtra로 값도 넣을 수도 있다.

 

 

<manifest>

<service
    android:name=".java.MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

위에건 필수

밑에건 옵션(선택) => 노티색상변경 등

<!-- 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="@drawable/ic_stat_ic_notification" />
<!-- 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" />

 

 

 

<수신용>

package com.mtjinse.myapplication.activity.models;

import android.os.AsyncTask;
import android.util.Log;
import android.view.textclassifier.TextLinks;

import org.json.JSONObject;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class SendNotification {
    public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    public static void sendNotification(String regToken, String title, String messsage){
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... parms) {
                try {
                    OkHttpClient client = new OkHttpClient();
                    JSONObject json = new JSONObject();
                    JSONObject dataJson = new JSONObject();
                    dataJson.put("body", messsage);
                    dataJson.put("title", title);
                    json.put("notification", dataJson);
                    json.put("to", regToken);
                    RequestBody body = RequestBody.create(JSON, json.toString());
                    Request request = new Request.Builder()
                            .header("Authorization", "key=" + "AKXY5Wc7gWvZf5tEj")
                            .url("https://fcm.googleapis.com/fcm/send")
                            .post(body)
                            .build();
                    Response response = client.newCall(request).execute();
                    String finalResponse = response.body().string();
                }catch (Exception e){
                    Log.d("error", e+"");
                }
                return  null;
            }
        }.execute();
    }
}

 

 

2. 다음 클래스를 하나 생성해주는데 저는 안에다가 static으로 구현하고 여러군데에서 바로바로 가져다가 사용할 수 있게끔 구현하였습니다. 그리고 refToken(알림을받아야하는사람의 토큰)과 제가 보내는데 추가로 필요한 정보인 title, message를 매개변수를 추가로만들고 JsonObject에 put해주어 보냈습니다

그리고 Authorization에서 서버키를 적어야하는데 저는 보안을 위해서 코드에는 제가 멋대로 짤라서(주작해서) 포스팅에 올렸는데 서버키는 위와같이 파이어베이스 콘솔에서 볼 수 있습니다. (좀 키가 깁니다, 가장위에것)

<발신을위한 코드>

 

 

  private void sendGson() {
        mRootDatabaseReference.child("UserList").child(mFriendUid).child("PushToken").addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
               Map<String,String> map= (Map<String, String>) dataSnapshot.getValue(); //상대유저의 토큰
                mPushToken = map.get("pushToken");



                Log.d(TAG, "상대방의 토큰 : " + mPushToken);
                mRootDatabaseReference.child("UserList").child(mFriendUid).addListenerForSingleValueEvent(new ValueEventListener() {
                    @Override
                    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                        Profile profile = dataSnapshot.getValue(Profile.class);
                        SendNotification.sendNotification(mPushToken, profile.getNickName(), mFcmMessage);
                    }

                    @Override
                    public void onCancelled(@NonNull DatabaseError databaseError) {

                    }
                });
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }

3. 이제 2번에서 만든 클래스를 사용하여 sendNotification을 하면됩니다. 저 같은 경우는 DB에서 토큰과 메세지내용 및 닉네임을 가져와야하기떄문에 리얼타임디비 코드가 섞여있는데 SendNotification.sendNotification(mPushToken, profile.getNickName(), mFcmMessage); 부분만 보시면 될 것 같습니다. 

<2번에서 만들것을 사용해서 보내자>

 

 


 

 

 

 

 

 

결과로 포어그라운드(앱이 켜져있을때) 백그라운드일때(앱이 꺼져있을때) 모두 알림이 잘 수신됨을 확인할 수 있습니다.

 

이상포스팅 마치겠습니다.

공감과 댓글은 큰 힘이됩니다. 감사함니다.

 

 

https://youngest-programming.tistory.com/393
추가 2020 업데이트 글 남깁니다.

 

[안드로이드] 상대방에게 FCM 전송하여 노티피케이션 띄우기 (feat. Retrofit2, 이전글 업데이트)

youngest-programming.tistory.com/103 [안드로이드] 노티피케이션 FCM 정리 ( 누르면 해당 액티비티와 내용 불러올 수 있도록) 단순 알림을 주고 알림을 누르면 런처액티비티로 이동하는 것은 예전에 해봤��

youngest-programming.tistory.com

 

 

참고:

https://stackoverflow.com/questions/37435750/how-to-send-device-to-device-messages-using-firebase-cloud-messaging

 

How to send device to device messages using Firebase Cloud Messaging?

After searching the docs I could not find any info on how to send device to device messages using FCM without the use of an external server. For example, if I was creating a chat application I would

stackoverflow.com

https://firebase.google.com/docs/cloud-messaging/android/client?hl=ko

 

Android에서 Firebase 클라우드 메시징 클라이언트 앱 설정  |  Firebase

Firebase 클라우드 메시징 Android 클라이언트 앱을 작성하려면 FirebaseMessaging API와 Gradle이 있는 Android 스튜디오 1.4 이상을 사용합니다. 이 페이지에서는 Android 프로젝트에 Firebase를 추가하는 단계를 완료했다고 가정하고 안내합니다. FCM 클라이언트에 Android 4.1 이상을 실행하며 Google Play 스토어 앱도 설치되어 있는 기기 또는 Google API로 Android 4.1을 실행하

firebase.google.com

 

728x90
Comments