관리 메뉴

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

[안드로이드] 노티피케이션 FCM 정리 ( 누르면 해당 액티비티와 내용 불러올 수 있도록) 본문

안드로이드/자바 & Previous

[안드로이드] 노티피케이션 FCM 정리 ( 누르면 해당 액티비티와 내용 불러올 수 있도록)

막무가내막내 2019. 8. 5. 19:22
728x90

 

 

단순 알림을 주고 알림을 누르면 런처액티비티로 이동하는 것은 예전에 해봤으나 알림을 누르면 채팅방이나 게시물로 이동하고 해당 내용들을 보여주게 하는 것은 이번에 처음 해봤다.

 

그에 대해 다시는 까먹지 않도록 코드와 간단한 설명을 기록하기위해 포스팅한다.

 

DA

 

먼저 위 문서를 보면 Data는  포어그라운드와 백그라운드일 때 둘다 onMessageReceived를 통해 전달이 되나 Notification은 백그라운드에서는 onMessageReceived로 받을 수 없음을 알 수 있다.

 

그래서 두가지 경우에 대해 해봤다.

 

먼저 노티피케이션으로 감싸보냈을 때와 Data로 감싸보넀을 때 중 전자를 먼저 작성해보겠다.

예를들어 전자는 이러한 페이로드로

{
  from:,
  to:,
  notification: {
    title:,
    body:
  },
  data: {
    type:,
    index:
  }
}

후자는 이렇게 보내는 거다. 

{
  from:,
  to:,
  data: {
    title:,
    body:,
    type:,
    index:
  }
}

 

 

 

전자 :

public class SendNotification {
    final static String TAG = "SendNotificationT";
    public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    public static void sendNotification(String regToken, String title, String messsage, Object object){
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... parms) {
                try {
                    Log.d(TAG, "상대방토큰 : " + regToken);
                    Log.d(TAG, "제목 : " + title);
                    Log.d(TAG, "메세지 : " + messsage);
                    String type = "";
                    OkHttpClient client = new OkHttpClient();
                    JSONObject json = new JSONObject();
                    //데이터 필드 담기
                    JSONObject dataJson = new JSONObject();
                    Gson gson =new Gson();
                    String data = gson.toJson(object); //객체JSON으로 변형해서 전달할거
                    dataJson.put("data", data);

                    //type담을 예정
                    if(object instanceof Meeting){
                        type = "meeting";
                        dataJson.put("type",type );
                    }else if(object instanceof CommunityPost){
                        type = "communityPost";
                        dataJson.put("type",type );
                    }

                    json.put("data", dataJson); //이건 데이터필드니깐 키필드값을 data로 해주어야한다.
                    Log.d(TAG, "노티 데이터 페이로드===> " + data);
                    Log.d(TAG, "노티  데이터타입 페이로드===> " + type);

                    //노티 필드 담기
                    JSONObject notiJson = new JSONObject();
                    notiJson.put("smallIcon", R.drawable.ic_rose_pink);
                    notiJson.put("body", messsage);
                    notiJson.put("title", title);
                    json.put("notification", notiJson);

                    //토큰 필드 담기
                    json.put("to", regToken);
                    RequestBody body = RequestBody.create(JSON, json.toString());
                    Request request = new Request.Builder()
                            .header("Authorization", "key=" + "서버키")
                            .url("https://fcm.googleapis.com/fcm/send")
                            .post(body)
                            .build();
                    Response response = client.newCall(request).execute();
                    String finalResponse = response.body().string();
                    Log.d("TAG", finalResponse);
                }catch (Exception e){
                    Log.d("error", e+"");
                }
                return  null;
            }
        }.execute();
    }
}
public class MyFirebaseMessagingService extends FirebaseMessagingService {
    private static final String TAG = "MyFirebaseMsgService";

    //putExtra
    final static String EXTRA_MEETING = "EXTRA_MEETING"; //미팅
    final String EXTRA_COMMUNITY_POST = "EXTRA_COMMUNITY_POST"; //커뮤니티
    /**
     * 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);
        // if(!isAppRunning(getApplicationContext())) { //백그라운드일떄만 보낸다.
        //json 데이터 페이로드
        String dataJson = remoteMessage.getData().get("data");
        String type = remoteMessage.getData().get("type"); //type필드 없으면 null반환됨
        Gson gson = new Gson();
        Log.d(TAG, "노티 타입 => "+type);
        if (type.equals("meeting")) {
            Meeting meeting = gson.fromJson(dataJson, Meeting.class);
            sendNotification(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody(), meeting);
        }else if(type.equals("communityPost")){
            CommunityPost communityPost = gson.fromJson(dataJson , CommunityPost.class);
            sendNotification(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody(), communityPost);
        }else{

        }

        //  }
    }
    // [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, Object object) {
        PendingIntent pendingIntent = null;
        if (object instanceof Meeting) {
            Log.d(TAG, " 미팅 노티 전송");
            Intent intent = new Intent(this, MeetingCardActivity.class);
            Meeting meeting = (Meeting) object;
            intent.putExtra(EXTRA_MEETING, meeting);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                    PendingIntent.FLAG_ONE_SHOT);
        }else if(object instanceof CommunityPost){
            Log.d(TAG, " 커뮤니티 노티 전송");
            Intent intent = new Intent(this, CommunityFullActivity.class);
            CommunityPost communityPost = (CommunityPost) object;
            intent.putExtra(EXTRA_COMMUNITY_POST, communityPost);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                    PendingIntent.FLAG_ONE_SHOT);
        }
       /* Intent intent = new Intent(this, Splash.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.ic_rose_pink)
                        .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());
    }

    //백그라운드일떄만 푸시메세지 보내고싶을 때 사용
    private boolean isAppRunning(Context context) {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> procInfos = activityManager.getRunningAppProcesses();
        for (int i = 0; i < procInfos.size(); i++) {
            if (procInfos.get(i).processName.equals(context.getPackageName())) {
                return true;
            }
        }

        return false;
    }


}

 

 

 

후자 : (데이터페이로드로 감싼다) , 백그라운드에서도 getIntent()로 받고 이동 할 수 있다. 위에서와 달리 노티피케이션 페이로드는 없에고 데이터페이로드에 다함께 담는다고 생각하면 될 것 같다. 백그라운드에서 알림을 누르면 해당액티비티로 이동을 하고 내용을 인텐트에서 받아와서 불러줄 수 가 있다. 근데 문제는 거기서 뒤로가기를 하면 액티비티스택에 액티비티가 없기 떄문에 앱이 꺼진다. 그러므로 처음 나오는 화면이나 중심화면인 메인액티비티로 가게끔 pendingIntent를 해준다음에 메인액티비티에서 노티인 경우를 판단하여 해당 액티비티를 띄워주는 로직을 하면 좋을 것 같다.

 

public class SendNotification {
    final static String TAG = "SendNotificationT";
    public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    public static void sendNotification(String regToken, String title, String messsage, Object object){
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... parms) {
                try {
                    Log.d(TAG, "상대방토큰 : " + regToken);
                    Log.d(TAG, "제목 : " + title);
                    Log.d(TAG, "메세지 : " + messsage);
                    String type = "";
                    OkHttpClient client = new OkHttpClient();
                    JSONObject json = new JSONObject();
                    //데이터 필드 담기
                    JSONObject dataJson = new JSONObject();
                    Gson gson =new Gson();
                    String data = gson.toJson(object); //객체JSON으로 변형해서 전달할거
                    dataJson.put("data", data);

                    //type담을 예정
                    if(object instanceof Meeting){
                        type = "meeting";
                        dataJson.put("type",type );
                    }else if(object instanceof CommunityPost){
                        type = "communityPost";
                        dataJson.put("type",type );
                    }
                    //title, body 담을 예정
                    dataJson.put("title", title);
                    dataJson.put("body", messsage);
                    //json에 puy
                    json.put("data", dataJson); //이건 데이터필드니깐 키필드값을 data로 해주어야한다.
                    Log.d(TAG, "노티 데이터 페이로드===> " + data);
                    Log.d(TAG, "노티  데이터타입 페이로드===> " + type);
                    Log.d("JSON" , json.toString());

                    //토큰 필드 담기
                    json.put("to", regToken);
                    RequestBody body = RequestBody.create(JSON, json.toString());
                    Request request = new Request.Builder()
                            .header("Authorization", "key=" + "AAAAZrRF5os:APA91bHb-iU8RFQJQSJvCMP79nzh4eeRmWvZDMQQg6-335WWN8aK1I9KeGEp74x-1bq-K_toStweUQ1L2hVjkK_IIbLg17X8Ft0vuo2aHgZ6eyr5ZIA_CKChFZ56IcsgLzDL6H_Lh5X5")
                            .url("https://fcm.googleapis.com/fcm/send")
                            .post(body)
                            .build();
                    Response response = client.newCall(request).execute();
                    String finalResponse = response.body().string();
                    Log.d("TAG", finalResponse);
                }catch (Exception e){
                    Log.d("error", e+"");
                }
                return  null;
            }
        }.execute();
    }
}
public class MyFirebaseMessagingService extends FirebaseMessagingService {
    private static final String TAG = "MyFirebaseMsgService";

    //putExtra
    final static String EXTRA_MEETING = "EXTRA_MEETING"; //미팅
    final String EXTRA_COMMUNITY_POST = "EXTRA_COMMUNITY_POST"; //커뮤니티
    /**
     * 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);
        // if(!isAppRunning(getApplicationContext())) { //백그라운드일떄만 보낸다.
        //json 데이터 페이로드
        String title = remoteMessage.getData().get("title");
        String message = remoteMessage.getData().get("body");
        String dataJson = remoteMessage.getData().get("data");
        String type = remoteMessage.getData().get("type"); //type필드 없으면 null반환됨
        Log.d(TAG, title);
        Log.d(TAG, message);
        Gson gson = new Gson();
        Log.d(TAG, "노티 타입 => "+type);
        if (type.equals("meeting")) {
            Meeting meeting = gson.fromJson(dataJson, Meeting.class);
            sendNotification(title, message, meeting);
        }else if(type.equals("communityPost")){
            CommunityPost communityPost = gson.fromJson(dataJson , CommunityPost.class);
            sendNotification(title,message, communityPost);
        }else{

        }

        //  }
    }
    // [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, Object object) {
        int notifyId = 0; //노티피케이션 아이디 값이 서로 다르면 각각 구분되어 알림이뜬다. (ex 댓글알림을 1로 설정한 경우 댓글알림이 여러개오면 하나의알림이 새로고침되는형식이고, 커뮤니티게시물은 1인 경우 댓글알림과 커뮤니티게시물 알림은 구분되어 보여진다.)
        PendingIntent pendingIntent = null;
        if (object instanceof Meeting) {
            Log.d(TAG, " 미팅 노티 전송");
            Intent intent = new Intent(this, MeetingCardActivity.class);
            Meeting meeting = (Meeting) object;
            intent.putExtra(EXTRA_MEETING, meeting);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                    PendingIntent.FLAG_ONE_SHOT);
            notifyId = 1;
        }else if(object instanceof CommunityPost){
            Log.d(TAG, " 커뮤니티 노티 전송");
            Intent intent = new Intent(this, CommunityFullActivity.class);
            CommunityPost communityPost = (CommunityPost) object;
            intent.putExtra(EXTRA_COMMUNITY_POST, communityPost);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                    PendingIntent.FLAG_ONE_SHOT);
            notifyId = 2;
        }


        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.ic_rose_pink)
                        .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(notifyId /* ID of notification */, notificationBuilder.build());
    }

    //백그라운드일떄만 푸시메세지 보내고싶을 때 사용
    private boolean isAppRunning(Context context) {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> procInfos = activityManager.getRunningAppProcesses();
        for (int i = 0; i < procInfos.size(); i++) {
            if (procInfos.get(i).processName.equals(context.getPackageName())) {
                return true;
            }
        }

        return false;
    }


}

 

 

출처 및 참고:

https://developer.android.com/guide/topics/ui/notifiers/notifications?hl=ko

 

알림 개요  |  Android Developers

알림은 사용자에게 알림, 다른 사용자로부터의 메시지 또는 앱의 기타 실시간 정보를 제공하도록 Android가 앱의 UI 외부에 표시하는 메시지입니다. 사용자는 알림을 탭하여 앱을 열거나 알림에서 바로 작업할 수 있습니다. 이 페이지에서는 알림이 표시되는 위치와 사용할 수 있는 기능을 간략하게 알아봅니다. 알림을 빌드하려면 대신 알림 만들기를 참조하세요. 디자인과 상호작용 패턴에 관한 자세한 내용은 알림 디자인 가이드를 참조하세요. 또한 Android 알림

developer.android.com

https://firebase.google.com/docs/cloud-messaging/android/receive#handling_messages

 

Android 앱에서 메시지 수신  |  Firebase

Firebase 알림의 동작은 수신하는 앱의 포그라운드/백그라운드 상태에 따라 달라집니다. 포그라운드 상태인 앱에서 알림 메시지 또는 데이터 메시지를 수신하려면 onMessageReceived 콜백을 처리하는 코드를 작성해야 합니다. 알림과 데이터 메시지의 차이점에 대한 설명은 메시지 유형을 참조하세요. 메시지 처리 메시지를 수신하려면 FirebaseMessagingService를 확장하는 서비스를 사용하세요. 서비스에서 onMessageReceived

firebase.google.com

 

 

 

 

 

 

 

 

 

 

 

 

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

 

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

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

youngest-programming.tistory.com

 

 

도움이 되셨다면 공감과 댓글 구독 부탁드립니다.!!

728x90
Comments