Notification 생성하기

읽기 전

  • 불필요한 코드나 잘못 작성된 내용에 대한 지적은 언제나 환영합니다.
  • 개인적으로 사용해보면서 배운 점을 정리한 글입니다.
  • 전체 프로젝트 코드는 깃헙 링크 - MyNotification에 올려두겠습니다. 참고해주세요.

진행 중인 프로젝트에서 특정 시간에 맞춰 사용자에게 Notification을 보내야 하는 작업이 있어 정리하였다. 푸시알림 switch 활성화 시 정해진 시간(오전/오후 8시, 9시)에 Notification을 생성하여 사용자에게 전달하는 기능을 구현해보려 한다. 그리고 네트워크 차단 및 앱을 kill해도 백그라운드를 안정적으로 유지하여 특정 시간에 알림을 보내기위해 WorkManager를 채택하였다.

전체 구조

Android_Background_Notification_001_01

Notification 설정 및 정의

Notification Channel 생성

안드로이드 오레오 이전까지는 채널 생성을 하지 않아도 Notification을 띄울 수 있었지만 이후부턴 Channel을 생성한 뒤 Channel ID를 부여해야 한다. 앱에 대해 단 한번만 생성하면 되고 이후 재호출 해도 같은 Paramerter에 대해 어떠한 동작을 하지 않으므로 재호출해도 된다고 공식문서에 쓰여있다. 그래서 Application을 상속받는 클래스에서 호출하게 하였다.

NotificationHelper.class - 채널 생성

    // 한번 실행 시 이후 재호출해도 동작 안함
    public static void createNotificationChannel(Context context) {
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
                // NotificationChannel 초기화
                NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, context.getString(R.string.app_name), NotificationManager.IMPORTANCE_DEFAULT);

                // Configure the notification channel
                notificationChannel.setDescription("푸시알림");
                notificationChannel.enableLights(true); // 화면활성화 설정
                notificationChannel.setVibrationPattern(new long[]{0, 1000, 500}); // 진동패턴 설정
                notificationChannel.enableVibration(true); // 진동 설정
                notificationManager.createNotificationChannel(notificationChannel); // channel 생성
            }
        } catch (NullPointerException nullException) {
            // notificationManager null 오류 raise
            Toast.makeText(context, "푸시 알림 채널 생성에 실패했습니다. 앱을 재실행하거나 재설치해주세요.", Toast.LENGTH_SHORT).show();
            nullException.printStackTrace();
        }
    }

InitApplication.class - 채널 생성 메소드 호출

public class InitApplication extends Application {
    private Context mContext;
    @Override
    public void onCreate() {
        super.onCreate();
        NotificationHelper.createNotificationChannel(getApplicationContext());
    }
}

AndroidManifest.xml - InitApplication.class 등록

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.mynotification">

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

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

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

name에 등록하여 앱 시작 시 InitApplication 클래스를 거치도록 하였다.

Notification 생성 및 동작 정의

일반적으로 푸시알림을 클릭할 때 로그인 절차가 필요 없다면 해당 액티비티를 활성화하여 사용자에게 정보를 제공하겠지만 로그인 절차가 필요하다면 앱을 launch하여 의도된 페이지까지 유도하는 방식이 바람직하다고 생각한다. 그리고 앱을 kill하지 않고 단지 home을 눌러 대기열에 내려둔 상태라면 재시작이 아니라 대기열에 있는 app을 화면으로 끌어올려 로드하는 방식으로 구현하였다. 두 가지의 푸시알림을 별도로 생성하기 위해 Notification code를 다르게 설정하였다.

NotificationHelper.class - 푸시알림 생성 및 동작 정의

    private static final Integer WORK_A_NOTIFICATION_CODE = 0;
    private static final Integer WORK_B_NOTIFICATION_CODE = 1;

    public void createNotification(String workName) {
        // 클릭 시 MainActivity 호출
        Intent intent = new Intent(mContext, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); // 대기열에 이미 있다면 MainActivity가 아닌 앱 활성화
        intent.setAction(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);

        NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
        // Notificatoin을 이루는 공통 부분 정의
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_ID);
        notificationBuilder.setSmallIcon(R.drawable.smile) // 기본 제공되는 이미지
                .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE)
                .setAutoCancel(true); // 클릭 시 Notification 제거

        // A이벤트 알림을 생성한다면
        if (workName.equals(WORK_A_NAME)) {
            // Notification 클릭 시 동작할 Intent 입력, 중복 방지를 위해 FLAG_CANCEL_CURRENT로 설정, CODE를 다르게하면 개별 생성
            // Code가 같으면 같은 알림으로 인식하여 갱신작업 진행
            PendingIntent pendingIntent = PendingIntent.getActivity(mContext, WORK_A_NOTIFICATION_CODE, intent, PendingIntent.FLAG_CANCEL_CURRENT);

            // Notification 제목, 컨텐츠 설정
            notificationBuilder.setContentTitle("WorkerA Notification").setContentText("set a Notification contents")
                    .setContentIntent(pendingIntent);

            if (notificationManager != null) {
                notificationManager.notify(WORK_A_NOTIFICATION_CODE, notificationBuilder.build());
            }
        } else if (workName.equals(WORK_B_NAME)) {
            PendingIntent pendingIntent = PendingIntent.getActivity(mContext, WORK_B_NOTIFICATION_CODE, intent, PendingIntent.FLAG_CANCEL_CURRENT);

            notificationBuilder.setContentTitle("WorkerB Notification").setContentText("set a Notification contents")
                    .setContentIntent(pendingIntent);

            if (notificationManager != null) {
                notificationManager.notify(WORK_B_NOTIFICATION_CODE, notificationBuilder.build());
            }
        }
    }

이제 Notification 관련 정의는 끝났으니 사용자가 특정 액션을 취했을 때 푸시알림을 생성하게끔 연결하면 된다.

참고자료

+ Recent posts