Mobile/Kotlin

[Kotlin] 포어그라운드(Foreground) 서비스

클리엘 2021. 1. 8. 11:00
728x90

일반적으로 서비스는 백그라운드(Background)로 동작합니다. 하지만 필요에 따라서는 이 서비스를 포어그라운드(Foreground)로도 실행할 수 있습니다. 포어그라운드라면 서비스가 동작하는 것 자체를 사용자에게 표시해야 하는데 이때는 휴대폰의 상단 상태바를 활용하게 됩니다.

 

우선 서비스를 포어그라운드로 동작시키려면 해당 권한을 명시해야 합니다. app -> manifests -> AndroidManifest.xml파일에 다음과 같은 태그를 추가해 주세요.

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

그다음 app -> java -> [패키 지명]에서 마우스 오른쪽 버튼을 눌러 New -> Service -> Service를 선택합니다. 화면상의 Class Name은 MyService정도로 하고 Finish를 눌러줍니다.

 

파일이 생성되면 onBind() 메서드를 아래와 같이 수정합니다.

class MyService : Service() {
    override fun onBind(intent: Intent): IBinder {
        return Binder()
    }
}

그리고 상태바에 알림을 표시할 메서드를 작성합니다. 알림은 채널단위로 동작하기에 사용할 채널 변수(SC)를 설정하고 설정한 채널로 알림이 표시되도록 하는 것입니다.

class MyService : Service() {
    val SC = "myService"

    fun Notification() {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            val nc = NotificationChannel(SC, "My Service Channel", NotificationManager.IMPORTANCE_DEFAULT)
            val nm = getSystemService(NotificationManager::class.java)

            nm.createNotificationChannel(nc)
        } else {
            Toast.makeText(this, "알림을 실행할 수 없음", Toast.LENGTH_LONG).show()
        }
    }

    override fun onBind(intent: Intent): IBinder {
        return Binder()
    }
}

위에서 알림 채널을 생성하였으면 onStartCommand()를 오버라이드 하여 Notification() 메서드를 호출해 채널을 만들고, 알림 제목과 아이콘을 지정하여 알림을 생성한 뒤 startForeground() 메서드로 알림을 표시하도록 합니다. 이때 NotificationCompat의 setContentTitle에서는 알림의 제목을, setSmallIcon에서는 알림의 아이콘을 지정하고 있는데 이러한 설정은 생략이 가능합니다.

class MyService : Service() {
    val SC = "myService"

    fun Notification() {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            val nc = NotificationChannel(SC, "My Service Channel", NotificationManager.IMPORTANCE_DEFAULT)
            val nm = getSystemService(NotificationManager::class.java)

            nm.createNotificationChannel(nc)
        } else {
            Toast.makeText(this, "알림을 실행할 수 없음", Toast.LENGTH_LONG).show()
        }
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Notification()

        val nc: Notification = NotificationCompat.Builder(this, SC).setContentTitle("myNotify").setSmallIcon(R.mipmap.ic_launcher_round).build()
        startForeground(1, nc)

        return super.onStartCommand(intent, flags, startId)
    }

    override fun onBind(intent: Intent): IBinder {
        return Binder()
    }
}

이번에는 MainActivity.kt에서 서비스를 실행하는 ServiceStart()와 서비스를 중지하는 ServiceStop() 메서드를 작성합니다. 특히 ServiceStart() 메서드에 주목해 주세요. 서비스를 포어그라운드로 동작시키려면 ContextCompat.startForegroundService() 메서드를 사용해야 합니다.

fun ServiceStart(view: View) {
    val intent = Intent(this, MyService::class.java)
    ContextCompat.startForegroundService(this, intent)
}

fun ServiceStop(view: View) {
    val intent = Intent(this, MyService::class.java)
    stopService(intent)
}

그런 다음 MainActivity 디자인 화면에서 다음과 같이 버튼 2개를 만들고 각각 ID를 btnServiceStart와 btnServiceStop으로 지정합니다. 그리고 btnServiceStart 버튼의 onClick속성에는 ServiceStart() 메서드를 btnServiceStop 버튼의 onClick속성에는 ServiceStop() 메서드를 지정합니다. 그러면 각 버튼을 클릭할 때마다 해당 메서드를 호출하게 됩니다. 이러한 방법이 가능한 이유는 위에서 ServiceStart()와 ServiceStop() 메서드를 만들 때 매개변수로 View를 지정했기 때문입니다.

 

앱을 동작시켜 '서비스실행'버튼을 누르면 상태바에 설정한 알림이 표시되는 걸 확인할 수 있습니다.

 

728x90