iOS Background Mode

강동희
cashwalk
Published in
10 min readAug 20, 2018

이번 스토리에서는 iOS Background Mode에 대해서 설명해보겠습니다.

iOS App인 UIKit App들의 상태는 4가지로 나뉘게 됩니다.

  1. Not Running
  2. Foreground (Inactive, Active)
  3. Background
  4. Suspend
iOS App State

1. Not Running

  • App을 실행하지 않은 상태로서, App이 실행되기전 상태 또는 실행되었지만 System에 의해 종료된 상태입니다.

2. Foreground

  • App이 실행되어 사용자에게 보여지고 있는 상태입니다.
  • 오직 하나의 App만 Foreground 상태를 가지며 inActive와 Active의 두가지 상태로 나뉘어집니다.
  • InActive : Foreground 상태에서 전화가 왔을때, 잠금상태, 멀티태스킹 스크린에서는 InActive 상태를 가집니다.
  • Active : inActive 상태가 아닌 상태에 해당합니다.

3. Background

  • Foreground 상태에서 HomeScreen으로 이동한 상태입니다.
  • Background 상태로 전환되기 전에 호출된 Task가 끝나지 않은 경우 Background 상태에서도 여전히 실행됩니다.
  • Background 상태로 전환된 후 호출된 Task는 App이 Foreground 상태로 전환된 후에 실행됩니다.

4. Suspend

  • App이 Background 상태로 전환된 후 더 이상 작업을 수행하지 않으면 System에서 App을 Suspend 상태로 바꾸게 됩니다.
  • App은 여전히 메모리에 존재하며 Suspend 상태가 될 당시의 상태를 저장하고 있지만, CPU나 배터리를 소모하지 않습니다.
  • Suspend 상태의 App은 Foreground 상태의 App을 위해 메모리 부족 등의 이유로 System에 의해 언제든지 종료됩니다. 이후 App을 실행하면 이전 상태의 화면은 나오지 않고 App이 재시작됩니다.

Background Modes

Xcode Capabilities에서 Background Modes는 Background 상태에서 App을 시작하거나 다시 시작하여 이벤트를 처리할 수 있도록 지원해줍니다.

Background Execution

위와 같이 Audio, Location, Newsstand, iOS Based 외부 악세사리, Bluetooth, PushNotification, BackgroundFetch 등 의 기능들을 Background 상태에서도 동작할 수 있도록 해줍니다.

위의 기능 중 몇가지에 대해서만 소개하도록 하겠습니다.

1. Audio, AirPlay and Picture in Picture

  • Audio를 지속적으로 실행할 수 있습니다.
  • 주의사항으로는 음악, 영상 관련앱이 아닌 경우 이 기능을 체크하면 AppStore 심사시 Reject을 받게 됩니다.

2. Location updates

  • GPS가 변할 때마다 Event를 처리할 수 있습니다.

3. Remote notifications

  • FCM payload에 “content-available”: true가 포함된 경우 App을 깨워 Event를 처리할 수 있습니다.

4. Background Fetch

  • System이 사용자의 App 사용패턴을 익혀서 Fetch 동작의 스케줄링을 하게 됩니다.

Background Fetch

Background Fetch에 대해서 좀 더 자세하게 설명해보겠습니다.

Background Fetch는 사용자의 App 사용패턴을 익혀서 Fetch를 합니다. 예를 들어 App이 매일 1시와 5시에 주로 실행된다고 System에서 파악하면 App은 해당 시간에 Background에 있는 App을 깨워서 AppDelegate에 application(_:performFetchWithCompletionHandler:)를 호출하게 됩니다.

위와 같이 setMinimumBackgroundFetchInterval 를 이용하여 Background Fetch 간에 최소시간을 설정합니다. 하지만 System에 권장설정일 뿐 정확하게 동작하지는 않습니다.

그리고 application(_:performFetchWithCompletionHandler:) 에 Background Fetch를 이용하여 처리할 작업을 추가하면 됩니다.

Background Fetch Debugging

Background Fetch는 System에서 실행하기 때문에 Xcode에서는 디버그할 수 있는 두가지 방법을 제공합니다.

1. Launch due to a background fetch event

Product -> Scheme -> Edit Scheme… 에서 해당하는 Target의 Run -> Options -> Launch due to a background fetch event 옵션을 활성화 해준후 Simulator를 Run하게 되면 App Foreground 상태로 실행되지 않고 Background 상태에서 Background Fetch를 실행하게 됩니다.

2. Simulate Background Fetch

Simulator를 Run하고 Foreground 상태에서 Debug -> Simulate Background Fetch 메뉴를 선택하면 강제로 Background Fetch를 실행하게 됩니다.

App State에 따른 Background Mode 동작 방식

Background Execution Event가 도착했을 때, Background Mode가 App을 동작시키는 방식입니다.

1. App이 Not Running 상태인 경우

  • System이 App을 실행합니다.
  • UIKit은 AppDelegate의 applicationDidEnterBackground(_:) 메소드를 호출합니다.
  • UIKit은 Event를 전달합니다.
  • App의 snapshot이 생성됩니다.
  • App은 다시 Suspend 상태가 될 수 있습니다.

2. App이 Suspend 상태인 경우

  • System이 App을 다시 시작합니다.
  • UIKit은 AppDelegate의 applicationDidEnterBackground(_:) 메소드를 호출합니다.
  • UIKit은 Event를 전달합니다.
  • App의 snapshot이 생성됩니다.
  • App은 다시 Suspend 상태가 될 수 있습니다.

3. App이 Foreground 상태에서 Background 상태로 이동한 경우

  • 사용자가 실행중인 App을 종료합니다.
  • UIKit은 AppDelegate의 applicationWillResignActive(_:) 메소드를 호출합니다.
  • UIKit은 AppDelegate의 applicationDidEnterBackground(_:) 메소드를 호출합니다.
  • App의 snapshot이 생성됩니다.
  • App은 다시 Suspend 상태가 될 수 있습니다.

UIApplication 내장 기능

Background Modes 이외에 UIApplication에서 내장되어 있는 Background 기능에 대한 설명입니다.

BackgroundTask

  • App이 Background 상태에서 잠시동안은 Background 작업을 하지만 어느정도 시간이 지나면 Suspend 상태로 되어 Background 작업이 중단되기 때문에 Background 상태에서의 작업시간을 늘려줍니다.
  • beginBackgroundTask는 Background에서 수행할 Task를 설정할 수 있으며, endBackgroundTask에 전달해야할 식별자를 반환합니다.
  • App Extension에서는 beginBackgroundTask를 호출할 수 없고 performExpiringActivity(withReason:using:) 를 사용해야 합니다.

backgroundTimeRemaining

  • Background 상태에서 작업을 수행할 수 있는 남은 할당시간을 확인할 수 있습니다.

Apple에서는 App이 Background 상태로 갈때 몇가지의 작업을 권고합니다.

applicationDidEnterBackground(_:) 메서드가 호출된 후 어느 시점에서 UIKit은 App의 현재 Interface에 대한 Snapshot을 저장합니다. System은 저장한 Snapshot을 Multitasking Screen이나 App이 Foreground 상태로 돌아올 때 사용합니다. 이러한 이유로 Background 상태로 가기전 민감한 정보와 경고, 기타 임시 Interface는 닫고 Snapshot을 찍을수 있도록 준비합니다.

공유 시스템 리소스를 해제합니다. Foreground 상태에서는 카메라 또는 System Database와 같은 공유 서비스를 사용하는데 우선순위를 가집니다. 하지만 App이 Suspend 상태가 되는 경우 App이 공유 리소스를 보유하고 있으면 System에서 공유 리소스를 종료하기 때문입니다.

Bonjour 관련 서비스를 취소합니다. App이 Suspend 상태가 되면 요청에 ​​응답 할 수 없기 때문입니다.

이미지, 미디어 파일 및 임시 객체들은 해제합니다. 즉, 디스크에서 쉽게 다시 만들거나 다시로드 할 수있는 메모리 용량을 크게 차지하는 객체에 대한 참조를 제거합니다. System은 NSCache 객체에 의해 관리되는 데이터와 NSDiscardableContent 프로토콜을 채택하는 객체를 포함하여 시스템 관리 캐시를 자동으로 비우기 때문입니다.

App은 Background 상태에서 가능한 작은 메모리 공간을 유지해야 합니다. App이 대량의 데이터를 관리하는 경우 데이터를 디스크에 쓰고 메모리에서 제거해야 할 수 있습니다. 많은 양의 메모리를 사용하는 Background App은 메모리 사용량이 적은 App보다 먼저 종료되기 때문입니다.

--

--