마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

Android Studio 푸시알림 기능 관련 질문 드립니다.

0 추천

저는 토이프로젝트로 생일알림어플을 만들고 있습니다.

MysqlDB로부터 값을 받아 RecyclerView에 이름,양력생일,음력생일 등을 담고, 이 사람의 생일의 3일전, 하루전, 당일 푸시알림을 주고 싶습니다. 백그라운드 상태에서도 푸시 알림이 올 수 있도록이요.

현재 RecyclerView 작업은 다 끝난 상태이고 알림작업만 남은 상태입니다.

구글링을 통해 Alarmmanager를 통한 방법을 알고, 간단하게 당일 특정 시간만(hour,minut만) 설정해서 알림이 오는 테스트는 성공을 했습니다.

mainAcvitity Code

//알람매니저에 알람등록 처리
    public void setNotice(int year,int month,int day,int hour,int minute,int id,String content,int requestCode) {

        //알람을 수신할 수 있도록 하는 리시버로 인텐트 요청
        Intent receiverIntent = new Intent(this, NotificationReceiver.class);
        receiverIntent.putExtra("content", content);
        receiverIntent.putExtra("requestCode", requestCode);
        receiverIntent.putExtra("id",id);

        /**
         * PendingIntent란?
         * - Notification으로 작업을 수행할 때 인텐트가 실행되도록 합니다.
         * Notification은 안드로이드 시스템의 NotificationManager가 Intent를 실행합니다.
         * 즉 다른 프로세스에서 수행하기 때문에 Notification으로 Intent수행시 PendingIntent의 사용이 필수 입니다.
         */

        /**
         * 브로드캐스트로 실행될 pendingIntent선언 한다.
         * Intent가 새로 생성될때마다(알람을 등록할 때마다) intent값을 업데이트 시키기 위해, FLAG_UPDATE_CURRENT 플래그를 준다
         * 이전 알람을 취소시키지 않으려면 requestCode를 다르게 줘야 한다.
         * */

        PendingIntent pendingIntent;
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
            pendingIntent= PendingIntent.getBroadcast(this, requestCode, receiverIntent, PendingIntent.FLAG_UPDATE_CURRENT|PendingIntent.FLAG_MUTABLE);
        } else {
            pendingIntent= PendingIntent.getBroadcast(this, requestCode, receiverIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        }

        //date타입으로 변경된 알람시간을 캘린더 타임에 등록
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR,year);
        calendar.set(Calendar.MONTH,month);
        calendar.set(Calendar.DATE,day);
        calendar.set(Calendar.HOUR_OF_DAY,hour);
        calendar.set(Calendar.MINUTE,minute);

        //알람시간 설정
        //param 1)알람의 타입
        //param 2)알람이 울려야 하는 시간(밀리초)을 나타낸다.
        //param 3)알람이 울릴 때 수행할 작업을 나타냄
        alarmManager.set(AlarmManager.RTC, calendar.getTimeInMillis(), pendingIntent);

    }
setNotice(2023,2,8,16,17,1,"안녕",1);
NotificationReceiver

public class NotificationReceiver extends BroadcastReceiver {

    private String TAG = this.getClass().getSimpleName();

    NotificationManager manager;
    NotificationCompat.Builder builder;

    //오레오 이상은 반드시 채널을 설정해줘야 Notification이 작동함
    private static String CHANNEL_ID = "channel1";
    private static String CHANNEL_NAME = "Channel1";

    //수신되는 인텐트 - The Intent being received.
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.e(TAG, "onReceive 알람이 들어옴!!");

        String contentValue = intent.getStringExtra("content");
        int requestCode = intent.getIntExtra("requestCode",0);
        int id = intent.getIntExtra("id",0);
        Log.e(TAG, "onReceive contentValue값 확인 : " + contentValue);

        builder = null;

        //푸시 알림을 보내기위해 시스템에 권한을 요청하여 생성
        manager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);

        //안드로이드 오레오 버전 대응
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
            manager.createNotificationChannel(
                    new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT)
            );
            builder = new NotificationCompat.Builder(context, CHANNEL_ID);
        } else {
            builder = new NotificationCompat.Builder(context);
        }

        //알림창 클릭 시 지정된 activity 화면으로 이동
        Intent intent2 = new Intent(context, HomeFragment.class);

        // FLAG_UPDATE_CURRENT ->
        // 설명된 PendingIntent가 이미 존재하는 경우 유지하되, 추가 데이터를 이 새 Intent에 있는 것으로 대체함을 나타내는 플래그입니다.
        // getActivity, getBroadcast 및 getService와 함께 사용
        PendingIntent pendingIntent;
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
            pendingIntent = PendingIntent.getActivity(context,requestCode,intent2,
                    PendingIntent.FLAG_UPDATE_CURRENT|PendingIntent.FLAG_MUTABLE);
        } else {
            pendingIntent = PendingIntent.getActivity(context,requestCode,intent2,
                    PendingIntent.FLAG_UPDATE_CURRENT);
        }


        //알림창 제목
        builder.setContentTitle(contentValue); //회의명노출
        //builder.setContentText(intent.getStringExtra("content")); //회의 내용
        //알림창 아이콘
        builder.setSmallIcon(R.drawable.cake_alarm_icon);
        //알림창 터치시 자동 삭제
        builder.setAutoCancel(true);

        builder.setContentIntent(pendingIntent);

        //푸시알림 빌드
        Notification notification = builder.build();

        //NotificationManager를 이용하여 푸시 알림 보내기
        manager.notify(id,notification);
    }
}

 

하지만 연도, 월, 일, 시간을 설정을 하고나서 테스트를 했을 땐 작동을 하지 않습니다.
 

 Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR,year);
        calendar.set(Calendar.MONTH,month);
        calendar.set(Calendar.DATE,day);
        calendar.set(Calendar.HOUR_OF_DAY,hour);
        calendar.set(Calendar.MINUTE,minute);

이 상태에서 year,month,day를 제외하고 테스트를 했을 땐 알림이 왔습니다.

어떤 문제가 있는지 도저히 모르겠습니다..

그리고 알림을 여러개 설정하기 위해선 requestCode를 다르게 부여해줘야 한다고 알고 있는데,

한사람의 생일 알림을 주기 위해서 3일전,하루전,당일분의 requestCode에 음력까지 생각하면 총 6개의 requestCode를 부여해야하는 번거로움이 있을것으로 예상되는데 이게 맞는건가요?

또 만약 이 사람이 recyclerView에서 삭제되면 알림도 삭제해줘야하는데 그럴경우 해당 requestCode를 삭제해야하는게 맞다면 너무 번거로울것 같기도 하고 이게 맞는 방법인가 의문점이 들어서 질문 드립니다.

다른 방법이 있다면 알려주시면 감사하겠습니다! 정말 이 문제가 항상 해결이 안돼서 다른 작업들을 우선적으로하다가 최종적으로 막혀서 이곳에 질문드립니다.. 답변 부탁드립니다!

류승민 (270 포인트) 님이 2023년 2월 8일 질문
류승민님이 2023년 2월 8일 수정

1개의 답변

+1 추천
 
채택된 답변

Calendar의 MONTH는 0부터 시작합니다. January(0), ....,  December(11) (https://docs.oracle.com/javase/7/docs/api/constant-values.html#java.util.Calendar.JANUARY) 
따라서 아래처럼 -1을 해주어야 제대로 설정이 될 것 같네요.

calendar.set(Calendar.MONTH, month - 1);

3일전 부터 매일 알람을 울리게 되므로, 이건 "3일간 매일 반복적으로" 알람이 울리는 것으로도 볼 수 있으므로 알람을 음력/양력  생일 3일전부터 매일 반복하도록 하시면 되지 않을까요? 이렇게 하면 알람을 양력, 음력 두개만 반복설정하시면 될 것 같아요.

알람의 삭제는 서버에 데이터가 존재하므로 앱에서 삭제요청을 보내서 처리하는 API가 필요할  것으로 보이네요. 요구사항에 따라서는 조회, 추가, 수정, 삭제 API 다 필요할 수도 있겠네요. 알림 리스트에는 각 항목에 서버  DB의 키값과 일치하는 값을 가지고 있도록 하고 삭제요청시에는 이 키값을 보내면 되겠죠. 알람테이블의 레코드를 나타낼 수 있는 클래스를 만드셔서 사용하시면 됩니다.

 

spark (224,800 포인트) 님이 2023년 2월 8일 답변
류승민님이 2023년 2월 8일 채택됨
아 명쾌한 해답 감사합니다! 말씀하신 방법으로 다시 시도 해봐야겠네요!
...