React

React에서 웹과 앱 환경에 따라 하단바 다르게 표시하기

solfa 2025. 1. 7. 03:57

문제 상황

웹과 앱 환경에서 하단바를 다르게 표시해야 했다

const BottomNav = () => {
  return <nav>하단 내비게이션</nav>;
};

 

이걸 어떻게 웹/앱 환경에 따라 다르게 보여줄까? 

 

1. 환경 감지 방법

1.1 User-Agent 활용

 

User-Agent 문자열을 분석하여 앱 환경인지 확인하는 방법이다.

iOS나 Android 앱의 웹뷰에서 접속 시 특정 문자열(MyCustomApp)을 추가하도록 설정해 감지한다.

const useCheckEnvironment = () => {
  const [isApp, setIsApp] = useState(false);

  useEffect(() => {
    // User-Agent 문자열 가져오기
    const userAgent = navigator.userAgent || navigator.vendor || window.opera;
    
    // 1. iOS 앱 체크
    const isIOS = userAgent.includes('iPhone') || userAgent.includes('iPad');
    // 2. 커스텀 User-Agent 체크
    const isCustomApp = userAgent.includes('MyCustomApp');
    
    setIsApp(isIOS && isCustomApp);
  }, []);

  return isApp;
};

 

 

처음에는 User-Agent로 환경을 체크했다. 이게 좋아보였는데 iOS, Android 각각 다르게 처리해야 해서 생각보다 User-Agent 처리가 까다로웠다. 물론 현재 프로젝트에서는 ios 단일이었지만 추후에 확장성을 위해 다른 방법을 찾았다.

 

 

1.2 URL 파라미터 활용

 

URL에 ?platform=app 파라미터를 추가해 환경을 감지한다.

이 방식은 명시적이고 안정적이며, User-Agent 대체 또는 보완 용도로 적합하다.

const useCheckPlatform = () => {
  const [platform, setPlatform] = useState<'web' | 'app'>('web');

  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const platformParam = params.get('platform');
    
    if (platformParam === 'app') {
      setPlatform('app');
    }
  }, []);

  return platform;
};

 

그래서 URL 파라미터 방식도 시도해봤다. 모든 URL에 파라미터를 붙여야 한다는 게 불편했지만 일단 이걸 쓰기로 했다. 이후에는 user-agent와 url을 같이 썼는데 그건 추후에 포스팅 해보겠음


2. 컴포넌트 구현

2.1 환경별 레이아웃 분기

const AppLayout = () => {
  const isApp = useCheckEnvironment();
  const platform = useCheckPlatform();
  
  // 두 가지 방법 중 선택
  const shouldShowBottomNav = !isApp || platform === 'web';

  return (
    <StyledLayout>
      <main>
        <Content />
      </main>
      
      {shouldShowBottomNav && (
        <BottomNav>
          <NavItem to="/home" icon={<HomeIcon />} />
          <NavItem to="/search" icon={<SearchIcon />} />
          <NavItem to="/profile" icon={<ProfileIcon />} />
        </BottomNav>
      )}
    </StyledLayout>
  );
};

const StyledLayout = styled.div`
  position: relative;
  min-height: 100vh;

  main {
    padding-bottom: ${({ theme }) => theme.bottomNavHeight};
  }
`;

const BottomNav = styled.nav`
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: ${({ theme }) => theme.bottomNavHeight};
  background: white;
  box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
  
  display: flex;
  justify-content: space-around;
  align-items: center;
  
  // iOS 노치 대응
  padding-bottom: env(safe-area-inset-bottom);
`;


3. iOS 앱 설정

이 부분은 iOS 개발자가 설정하는 부분으로 대충 이런 식으로 동작하는구나~ 정도만 알면 될 것 같다.

 

다음은 iOS 개발자가 웹뷰 설정에서 User-Agent와 URL 파라미터를 추가하는 방법이다.

 

3.1 Swift로 User-Agent 설정

let webView = WKWebView(frame: self.view.bounds)

// 기존 User-Agent 가져오기
webView.evaluateJavaScript("navigator.userAgent") { (result, error) in
    if let currentAgent = result as? String {
        // 커스텀 식별자 추가
        let newAgent = "\(currentAgent) MyCustomApp"
        webView.customUserAgent = newAgent
    }
}

 

3.2 URL 파라미터 추가

// URL에 platform 파라미터 추가
let baseUrl = "https://myapp.com"
let urlWithPlatform = "\(baseUrl)?platform=app"

if let url = URL(string: urlWithPlatform) {
    let request = URLRequest(url: url)
    webView.load(request)
}

 

4. iOS 개발자와 협업 과정

 

iOS 웹뷰와 웹 브라우저에서 서로 다른 동작을 구현하기 위해 iOS 개발자와 협업하며 아래와 같은 과정을 거쳤다.

 

우선 미리 iOS 개발자분과 요구사항을 정리했다.

  1. 웹뷰에서 접속 시
    • User-Agent 감지를 통해 하단바를 숨기도록 설정
    • User-Agent 문자열에 고유 값을 추가(예: MyCustomApp)하여 환경 구분
  2. 브라우저 접속 시
    • 지정된 경로(/home, /search, /profile)에서만 하단바 표시
    • 나머지 경로에서는 하단바 숨김.
  3. iOS 노치 및 화면 안전 영역 대응
    • env(safe-area-inset-bottom)를 사용하여 iOS의 노치 디자인에도 대응
    • Swift에서 하단 영역의 안정적인 렌더링을 위한 설정 요청

iOS 개발자분께 UserAgent 설정을 요청했고 테스트 시나리오는 다음과 같다.

 

1) 웹뷰에서 접속 테스트

  • UserAgent.includes('MyCustomApp')로 식별.
  • 하단바 숨김 확인:
    • 특정 경로에서 하단바가 나타나지 않아야 함.

2) 브라우저에서 접속 테스트

  • User-Agent가 기본 값일 경우 platform=web로 식별.
  • 지정된 경로에서만 하단바 표시 확인:
    • /home, /search, /profile에서 하단바 표시.
    • /other-path에서는 하단바 숨김.

3) iOS 노치 대응 테스트

  • env(safe-area-inset-bottom)이 적용되는지 확인.
  • 안전 영역 외부로 UI가 침범하지 않도록 점검.

5. 실제 적용 시 고려사항

추가로 고려해야 할 자잘한 스타일링들이다.

 

5.1 스타일링

const BottomNav = styled.nav<{ isApp: boolean }>`
  // 앱에서는 하단 여백 추가
  ${({ isApp }) => isApp && css`
    margin-bottom: env(safe-area-inset-bottom);
  `}
  
  // 웹에서는 고정 높이
  ${({ isApp }) => !isApp && css`
    height: 60px;
  `}
`;

 

 

5.2 성능 최적화

const useEnvironment = () => {
  const isApp = useMemo(() => {
    const userAgent = navigator.userAgent;
    return userAgent.includes("MyCustomApp");
  }, []);
  
  return isApp;
};

 

 

참고 문서

- [WKWebView 공식 문서](https://developer.apple.com/documentation/webkit/wkwebview)
- [safe-area-inset MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/env)
- React Router v6 문서

728x90