[React Native] iOS 위젯 - 설계

Jiwoo JEONG·2023년 4월 8일
9

React Native iOS Widget

목록 보기
1/2
post-thumbnail

React Native에서 위젯을 개발해야한다

사내 React Native(이하 RN)으로 개발된 앱에서 위젯 개발 feature가 생겼다. 나는 내심 iOS Native 개발을 해보고 싶던 터라 1순위로 해당 feature를 개발을 희망했고, 다른 개발자분들도 1순위로 원해서 사다리 타기를 통해 해당 feature를 내가 개발할 수 있게 되었다.
원했던 것이지만 RN의 Native Module도 한 번 만들어 본 적 없던 나에게 큰 챌린지가 될 것 같았고 꼭 해내고 싶었다.

해당 포스트는 사내 앱 위젯 개발 경험을 예시로, 간단한 React Native에서의 iOS위젯 개발을 소개하는 글입니다.
1. 설계
2. 구현
으로 나누어 포스팅합니다.

설계

큰 틀

  1. React Native에서는 Native에서 작성된 함수를 실행하기 위해서 Native Module을 Objective-C로 개발하여 RCTBridgeModule을 통해 React Native에서 호출 할 수 있다. (iOS Native Modules RN 공식문서)
  2. iOS에서 UserDefaults라는 저장소가 있는데, 이것을 통해 앱 어디에서나 데이터 CRUD가 가능하다.
  3. 1번과 2번을 종합하여 UserDefaults를 CRUD하는 Native Module을 작성하여 React Native에서 iOS의 Native단에 존재하는 UserDefaults 저장소에 CRUD 한다.
  4. UserDefaults는 어디서나 쓸 수 있기 때문에 해당 저장소의 값을 위젯에서 사용하여 data를 그려주면 될 것이다.

❗️하지만

어떻게 위젯의 값을 refresh 할 것인가?

위 질문에 나에게 던져졌다. 나에게 떠오른 3가지의 방법

1. iOS 위젯에 있는 Timeline을 사용

  • iOS 위젯은 TimelineProvider를 통해 언제 위젯을 업데이트하고 싶은지 제공할 수 있다.
    - 특정 시간에 WidgetKit에서 TimelineProvider의 method를 호출해 새로운 Timeline을 요구하고 이 때 method에서 받아오는 데이터로 위젯을 render한다
  • WidgetKit은 다음과 같은 생애주기를 가진다
    - 사용자가 위젯을 추가할 때는 getSnapshot request를 통해 snapshot 데이터를 보여준다
    - 사용자가 위젯을 추가한 이후로는 timeline request를 통해 실제 데이터를 보여준다
    - Timeline을 만들 때 각각 TimelineReloadPolicy를 지정해주어야한다.(Apple 공식문서)

    간단하게 설명하면 다음과 같다

    .atEnd : 모든 timeline의 요청이 끝나고 요청 (default)
    .after(Date) : 첫 after policy timeline 요청으로부터 next timeline 요청까지의 date를 정할 수 있음, 이후의 timeline은 버려짐.
    .never : 요청 안함 (static한 위젯에 필요할 것 같음)

    자세한 설명은 Apple 공식문서에 그림과 함께 나와 있어요 !

❗️그런데 말입니다...

우리는 RN에서 상태값이 변할 때마다 위젯의 새로운 Timeline을 만들고 싶어! 시간을 예측할 수 없어!
그래서 해당 방법은 탈락 ❌

2. Observable 객체를 만들고 해당 객체를 위젯에서 구독

  • RXJS에서 Observable을 사용해보았기 때문에 위젯에서 Observable 객체를 구독하고, RN에서 또 하나의 Native Module을 만들어서 Observable 객체의 값을 변경해주면 구독하고 있던 위젯의 Timeline이 새롭게 만들어지지 않을까?

❗️그런데 말입니다...

위젯에서 Observable을 구독해도 의미가 없다라는 글을 읽었다 😳
그리고 굳이 2개의 객체를 같은 동작을 위해 만들면 유지보수 측면에서도 나중에 다른 개발자가 Observable은 왜 필요하지?라고 생각할 것 같아서 탈락 ❌

3. WidgetCenter.shared.reloadAllTimelines() 사용

Apple 공식문서 발췌

Requesting a Reload of Your Widget’s Timeline

Changes in your app’s state may affect a widget’s timeline. When this happens, you can tell WidgetKit to reload the timeline for either a specific kind of widget or all widgets. For example, your app might register for push notifications based on the widgets the user has configured. When your app receives a push notification that changes the state for one or more of your widgets, requesting a reload of their timelines updates their display.

If you only need to reload a certain kind of widget, you can request a reload for only that kind. For example, in response to a push notification about a change in a game’s status, you could request a reload for only the game status widgets:

WidgetCenter.shared.reloadTimelines(ofKind: "com.mygame.gamestatus")

To request a reload for all of your widgets:

WidgetCenter.shared.reloadAllTimelines()

(번역)

위젯의 타임라인 다시 로드 요청

앱의 상태가 변경되면 위젯의 Timeline에 영향을 줄 수 있습니다. 이 경우 WidgetKit에 특정 종류의 위젯 또는 모든 위젯에 대한 Timeline을 다시 로드하도록 지시할 수 있습니다. 예를 들어 사용자가 구성한 위젯에 따라 앱이 푸시 알림을 등록할 수 있습니다. 앱이 하나 이상의 위젯 상태를 변경하는 푸시 알림을 수신하면 위젯 timeline을 다시 로드하도록 요청하면 위젯의 값이 업데이트됩니다.

특정 종류의 위젯만 다시 로드해야 하는 경우 해당 종류에 대해서만 다시 로드를 요청할 수 있습니다. 예를 들어 게임 상태 변경에 대한 푸시 알림에 응답하여 게임 상태 위젯에 대해서만 다시 로드를 요청할 수 있습니다:

WidgetCenter.shared.reloadTimelines(ofKind: "com.mygame.gamestatus")

모든 위젯에 대해 다시 로드를 요청하는 방법:

WidgetCenter.shared.reloadAllTimelines()

우선 우리 앱의 위젯은 하나 뿐이라 reloadAllTimelines()를 RN Native Module에서 UserDefaults를 Write 할 때 함께 호출하여 값이 변하면 새로운 Timeline을 가져올 수 있도록 하였다!

profile
FE Developer as Efficiency Maker

0개의 댓글