Android Watchdog 기능 추가하기(OS 9)

2024. 11. 25. 23:53·Android
728x90
반응형

이번 글은 기능에 대해 소개하기 전, 먼저 OS 9(Pie)을 타겟으로 만든 기능임을 알린다.

 

기능 및 배경 소개

우리가 어떤 프로그램이 지속 실행되어야하는 상황에 만약을 대비해 넣는 기능 중에 하나가

한번쯤은 봤을만한 꺼지면 재실행하는 기능이다.

 

이 기능은 보통 Watchdog(와치독, 워치독)이라 불린다.

 

이번에 안드로이드 셋톱박스에 맞추어 앱을 제작하게 됐는데

이 때, 꺼지지 않는 앱이 필요했고 만에 하나를 대비해 이 기능을 준비하게 되었다.

 

Manifest 수정하기

먼저 Foreground Service 권한을 설정해야 한다.

 

갑자기 무슨 Foreground Service인가 싶을 수 있다.

 

Background Service에서 Activity를 실행할 수는 있지만(하위 OS이기에 가능하지만)

OS에서 Service 자체를 날려버리면 다시 실행시킬 방법이 없다.

 

또한 Foreground Service가 OS에서 가지는 우선순위가 높으므로 웬만한 상황에서는

종료되지 않을 것이라는 기대를 가질 수 있다.

 

아무튼 서론이 길었는데 바로 수정해보자.

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

먼저 이 두 가지 권한이 필요하다.

 

첫번째 권한은 일반적인 권한처럼 보이지만

두번째 권한은 앱이 Foreground Service 타입을 명시한 것이라고 할 수 있다.

 

그리고 우리가 사용할 Service가 Manifest에 등록될 것인데

여기에 그 타입을 권한에 명시한 것과 동일하게 설정한다.

<service
            android:name=".WatchDogService"
            android:enabled="true"
            android:exported="true"
            android:foregroundServiceType="specialUse"
            android:process=":watchdogProcess" />

여기서 process는 서비스가 실행될 프로세스를 의미한다.

 

내가 명시한 것처럼 process값이 ":"으로 시작되면 앱 전용 새로운 프로세스가 만들어지고 여기서 서비스가 실행된다.

 

현재 OS(9, Pie)에서 빠진 속성이 하나 있다면 POST_NOTIFICATIONS라고 할 수 있다.

 

OS 13미만은 해당 권한이 자동 부여되기 때문이다.

 

Service 구성하기

class WatchDogService : Service() {

    override fun onCreate() {
        super.onCreate()

        val notificationChannel = NotificationChannel("Watchdog", "Watchdog", NotificationManager.IMPORTANCE_HIGH)
        val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(notificationChannel)

        val notificationBuilder = Notification.Builder(this, "Watchdog").apply {
            setSmallIcon(R.mipmap.icon_launcher_round)
            setContentTitle("Watchdog")
            setContentText("Watchdog is running")
        }

        startForeground(100, notificationBuilder.build())

        val activityManager = getSystemService(ACTIVITY_SERVICE) as ActivityManager
        CoroutineScope(Dispatchers.Main).launch {
            while (true) {
                println("Watchdog is still running")
                if (!isForeground(activityManager)) {
                    val intent = Intent(this@WatchDogService, MainActivity::class.java).apply {
                        addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                    }
                    startActivity(intent)
                }
                delay(10_000L)
            }
        }
    }

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

    override fun onDestroy() {
        super.onDestroy()
    }

    private fun isForeground(activityManager: ActivityManager) : Boolean {
        val runningAppProcessInfo = activityManager.runningAppProcesses
        runningAppProcessInfo.forEach { process ->
            if (process.processName.equals(packageName) && process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) return true
        }
        return false
    }
}

먼저 서비스가 만들어지면 알림을 상태바에 만들어두고 Foreground Service를 시작한다.

 

그리고 AcitivityManager를 통해 현재 앱이 Foreground 상태에 있는지 확인한다.

 

만약 Foreground 상태에 앱이 없는 경우 MainActivity를 실행하는 코드이다.

 

여기서 Intent.FLAG_ACTIVITY_NEW_TASK를 설정해주었는데, 이를 지정하지 않는 경우 에러가 발생한다.

Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

 

액티비티 외부에서 startActivity를 호출하는 경우,

Intent.FLAG_ACTIVITY_NEW_TASK를 설정해주어야 한다는 에러이다.

 

결과

이렇게 되는 경우, 뒤로가기 버튼을 통해 앱을 종료하거나

OOM, 처리하지 않은 Exception 때문에 앱이 크래시가 발생하는 경우 앱을 다시 실행시킨다.

728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'Android' 카테고리의 다른 글

Android add library using toml  (0) 2024.11.27
Android QR Code Generation  (0) 2024.11.26
Android Phone Number Format(자동 하이픈 추가)  (0) 2024.11.24
Android Compose WebView PullToRefresh 기능 구현하기  (0) 2024.11.19
Android Fold Device 대응하기  (6) 2024.11.08
'Android' 카테고리의 다른 글
  • Android add library using toml
  • Android QR Code Generation
  • Android Phone Number Format(자동 하이픈 추가)
  • Android Compose WebView PullToRefresh 기능 구현하기
BonusTrack02.dev
BonusTrack02.dev
공부, 일상
  • BonusTrack02.dev
    BonusTrack02.dev
    BonusTrack02.dev
  • 전체
    오늘
    어제
    • 분류 전체보기 (237)
      • Android (84)
      • Language (63)
        • Java (19)
        • Kotlin (27)
        • Swift (17)
      • 프로그래머스 (68)
      • 주저리주저리 (22)
        • 카페 (5)
        • 음식점 (4)
        • 컨퍼런스 (1)
        • 팝업스토어 (4)
        • 해외여행 (0)
        • 전시회 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    자바
    배열
    PCCE
    viewModelScope
    안드로이드
    코루틴
    코틀린
    오블완
    ios
    daterangepicker
    android
    티스토리챌린지
    Kotlin
    CodeLab
    프로그래머스
    MVVM
    programmers
    aac
    getNumericValue
    Observer
    Material
    SWIFT
    room
    스위프트
    ViewModel
    coroutines
    Java
    databinding
    jetpack
    LiveData
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
BonusTrack02.dev
Android Watchdog 기능 추가하기(OS 9)
상단으로

티스토리툴바