앱이 꺼졌을 때 푸쉬알림을 터치하면 원하는화면으로 이동하지 않았던 이유

이승훈·2023년 11월 1일
1

시행착오

목록 보기
18/23
post-thumbnail

0. 환경

  • React Native 어플리케이션 개발
  • OneSignal SDK 사용하여 푸쉬 알림 기능 구현
  • @react-navigation/native 라이브러리를 사용하여 네비게이팅

1. 문제

푸쉬 알림이 발생했을 때 어플리케이션이 스마트폰에서 완전히 종료된 상태에서는 푸쉬알림 터치 시 원하는 화면으로 정확하게 이동되지 않는 문제가 발생하였습니다.

예시)
1. 내가 작성한 게시글에 댓글이 달렸다는 푸쉬알림 발생
2. 푸쉬알림 터치 시 내가 작성한 게시글 화면으로 이동해야하나 어플리케이션이 실행된 후 홈화면에 그대로 유지됨

특이사항

어플리케이션을 이용중이거나 백그라운드에서 어플리케이션이 실행중인 상황에서는 푸쉬알림 터치 시 원하는 화면으로 정확하게 이동

2. 원인

아래의 커스텀훅은 OneSIgnal SDK에서 제공해주는 메소드를 사용하여 푸쉬알림 선택시의 스크린 이동에 대한 행동의 정의해주는 커스텀훅입니다.

export const useOneSignalPushAlarmInit = () => {
  const { navigate } = useAppNavigation();

  useEffect(() => {
    // Method for handling notifications opened
    OneSignal.setNotificationOpenedHandler(({ notification }) => {
      const additionalData = notification.additionalData as AdditionalData;

      switch (additionalData.type) {
        case PushAlarmTypes.SOME_STATE0:
           navigate(어디론가 슈슝 이동~)
          break;
        case PushAlarmTypes.SOME_STATE1:
        case PushAlarmTypes.SOME_STATE2:
        case PushAlarmTypes.SOME_STATE3:
        case PushAlarmTypes.SOME_STATE4:
        case PushAlarmTypes.SOME_STATE5:
           navigate(어디론가 슈슝 이동~)
          break;
        case PushAlarmTypes.SOME_STATE6:
           navigate(어디론가 슈슝 이동~)
          break;
        case PushAlarmTypes.SOME_STATE7:
           navigate(어디론가 슈슝 이동~)
          break;
        default:
          return;
      }
    });
  }, [navigate]);
};

이 커스텀훅의 navigate 함수를 실행시키기 위해선 이미 네비게이션 구조와 설정이 모두 완성되어있어야 합니다.

허나 문제의 상황에선 네비게이션 설정이 모두 완료되기 전 푸쉬알림이 의도하는 스크린으로 이동시키고자 하였고 그로인해 홈스크린에서 머무르게 된 것입니다.

ERROR The action 'NAVIGATE' with payload {"name":"CommunityPostScreen","params":{"feedPostCode":"codecodecodecodecode"}} was not handled by any navigator.

Do you have a screen named 'CommunityPostScreen'?

If you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.

This is a development-only warning and won't be shown in production.

3. 해결

NavigationContainer는 리액트 네비게이션의 루트 컴포넌트로, 네비게이션의 상태와 구조를 관리합니다. NavigationContainer가 마운트 될 때, 내부의 네비게이션 구조 (예: Stack Navigator, Tab Navigator 등)와 설정은 초기화됩니다.

즉, NavigationContainer가 마운트 완료된 후 navigate 함수를 실행해주니 문제는 해결되었습니다.

기존

useOneSignalPushAlarmInit 커스텀훅은 기존 useAppInitializationCheckEffect라는 커스텀훅 안에서 실행되었고 useAppInitializationCheckEffect 커스텀훅은 총 2군데위치에서 실행되었습니다.

그 2곳의 위치는 로그인 스크린 + 홈 스크린 이었습니다.

허나 우리의 네비게이트 구조상 로그인이 완료되기 전 스크린들과 로그인이 완료된 후의 스크린들은 각기 다른 Stack Group에 소속되어있고 로그인 상태에 따라 마운트 여부를 결정합니다.

  <RootStack.Navigator
      screenOptions={{
        statusBarColor: isAndroid ? background.main : undefined,
        statusBarStyle: 'dark',
      }}
    >
      {isLoggedIn ? (
        <RootStack.Group>
          <RootStack.Screen
            name={BottomNavigatorScreenNames.Root}
            component={BottomNavigator}
            options={{ headerShown: false }}
          />
          {getConsultationStackGroup()}
          {getTranslationStackGroup()}
          {getHealthScreeningStackGroup()}
          {getCommunityStackGroup()}
          {getSettingStackGroup()}
          {getUserStackGroup()}
        </RootStack.Group>
      ) : (
        <>{getAuthStackGroup()}</>
      )}
    </RootStack.Navigator>

하여 로그인 스크린에서 navigate(결과지해석스크린) 함수를 실행할 경우 네비게이션 설정에는 없는 스크린으로 이동하라는 명령이 전달되기에 올바르게 명령이 실행되지 않았습니다.

개선

useOneSignalPushAlarmInit 함수를 useAppInitializationCheckEffect 커스텀훅안에서 제거한 후
홈스크린에서만 초기화를 실행해주는 useHomeScreenEffect라는 커스텀훅으로 이동시켜주었습니다.

export const useHomeScreenEffect = () => {
  useAppInitializationCheckEffect();

  useCheckHasNicknameEffect();

  useHomePrefetchingEffect();

  useOneSignalPushAlarmInit();
};

푸쉬알림 초기화 함수는 로그인 전 단계에서는 실행시킬 필요가 없기에
로그인 완료된 후 첫 이니셜 라우트인 홈스크린에서만 실행되면 됩니다.

하여 로그인 스크린에서도 사용되는 useAppInitializationCheckEffect 커스텀훅에서 제거해주고
별도의 홈스크린만을 위한 초기화 커스텀훅인 useHomeScreenEffect 커스텀훅으로 옮겨주었습니다.

결과

로그인 후 스택그룹안에서 navigate(결과지해석)을 실행하게되면 이제는 네비게이션 구조안에 결과지해석 스크린이 존재하므로 에러없이 정상동작함을 확인하였습니다.

profile
Beyond the wall

0개의 댓글