3줄 요약:
Flutter의 AppLifecycle은 native OS의 작동 방식에 의존합니다.
따라서 각 OS의 AppLifecycle을 잘 알아두면, 이를 다루는 기능을 개발하는데 용이합니다.
Flutter를 사용해 여러 기능을 개발하다 보면, 종종 앱의 생애주기를 다루어야 할 일이 생깁니다.
예를 들자면 백그라운드로 앱이 내려갈 때도 계산을 이어 해야 한다던지, 백그라운드에서 포어그라운드로 복귀할 때 마다 상태를 확인해야 한다든지, 앱 종료 직전에 서버에게 이를 알려야 할 때가 대표적인 상황일 겁니다.
다행히 Flutter에서 AppLifecycleState를 관측할 수 있도록 방법을 제공해줍니다!
class ExampleWidget extends StatefulWidget {
const ExampleWidget({Key? key}): super(key: key);
State<ExampleWidget> createState() => _ExampleWidgetState();
}
class _ExampleWidgetState extends State<ExampleWidget>
with WidgetsBindingObserver {
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
void didChangeAppLifecycleState(AppLifecycleState state) async {
print("didChangeAppLifecycleState: $state");
super.didChangeAppLifecycleState(state);
}
Widget build(BuildContext context) => Placeholder();
}
WidgetsBindingObserver를 mixin으로 활용하면, StatefulWidget의 State에서 didChangeAppLifecycleState 핸들러를 사용해 AppLifcycleState의 변화를 감지할 수 있습니다.
문제는, 열심히 로직을 작성한 뒤 실기기에서 테스트해보면 IOS와 Android에서 AppLifecycleState 의 동작이 다르다는 걸 확인할수 있을 겁니다.
두 플렛폼 간의 차이를 정리하자면 아래의 다이어그램과 같은데요,
Android AppLifecycle
IOS AppLifecycle
이를 관찰할 수 있는 간단한 예제 어플을 작성해보았습니다. github repo
이 예제 어플을 실행시켜 상태의 변화를 관찰해보면,
minimize 의 경우
Android의 경우, 별다른 상태 변화를 관찰할 수 없는데반해, IOS의 경우 minimize 되는 순간 inactive 상태에 진입하고, 복귀할때 resume 상태를 갖는 것을 관찰 할수 있습니다.
background 의 경우
안드로이드의 경우 inactive -> paused -> resumed의 차례로 상태가 변화함을 관찰 할 수 있습니다.
IOS 의 경우 minimize 된 이후 background에 갔다가 다시 foreground로 복귀하므로 inactive - paused - inactive -resumed의 차례로 상태가 변화함을 관찰 할 수 있습니다.
background 도중 AppKill 이 일어날 경우
Android
IOS
Android의 경우 별도의 상태를 수신하지 못한 채 앱이 종료됬지만, IOS의 경우에는 앱이 종료되기 직전 detached 상태를 수신받을 수 있습니다.
이렇게 같은 어플을 실행하는데, 실행환경에 따라 상태전이가 다른 이유는 Flutter는 Native OS 의 AppLifecycle에 의존하기 때문입니다.
IOS 의 Lifecycle
위의 상태전이도는 IOS의 AppLifecycle을 표현한 다이어그램입니다.
이전에 보여드렸던 Flutter의 IOS AppLifecycle과 모습이 비슷한 것을 확인할 수 있습니다!
Android 의 Lifecycle
Android의 경우 minimize때는 아직 App을 볼 수 있으므로 별도의 상태전이가 일어나지 않다가, background로 전환될 때, onPause()와 onStop() 상태로 전환되고 이가 flutter 상태로는 inactive, paused로 표현되는것을 알 수 있습니다.
이후 foreground로 복귀할 때 거치게 되는 onRestart(), onstart(), onResume()이 세 단계는 resumed으로 축약해서 표현되네요.
하지만, 아직 Background App kill이 일어나는 상황에 dechted상태를 잘 수신받지 못하는 부분은 잘 설명되지 않습니다.
이는 Flutter의 본질이 UI Framework 이기 때문입니다.
Native method channel등을 통해 따로 설정해주지 않는 이상, UI 가 더 이상 존재하지 않는 상황에서는 Flutter 또한 존재하지 않기 때문에, 내부에 작성되는 dart 코드 또한 실행되기가 어려운 것이죠.
Flutter는 강력한 크로스플랫폼 UI FrameWork이지만, "크로스플랫폼 UI Framework"이기 때문에 실행되는 환경과, UI 상태에 종속적이라는 한계 또한 가지고 있습니다.
강력한 기능을 지원하는 소프트웨어를 개발하기 위해서는 결국 실행되는 Native OS에 대한 지식이 동반되어야 함을 알 수 있습니다.