React Native) react native로 webview앱 만들기(1)

2ast·2023년 1월 23일
10

react-native project 만들기

react native 프로젝트를 만드는 두 가지 방법

react native webview app을 만들기 위해서는 가장 먼저 react native project를 생성해야한다. react native 앱을 만드는 방법에는 크게 두가지가 있는데, expo를 사용하는 방법과 react-native cli를 이용하는 방법이 있다.

두가지 방법의 가장 큰 차이점은 ios/android 네이티브 단의 코드가 노출되어 있느냐 아니냐이다. react native는 js코드를 기반으로 ios/android 단의 네이티브 단을 제어하는 형태로 구성되어 있다. 따라서 경우에 따라 네이티브 단의 코드 셋팅을 변경하거나 새로운 기능 추가를 위해 네이티브 코드를 추가해야하는 상황이 생기기도 한다. 이런 특징은 잘만 사용한다면 자유도를 크게 높여 크로스플랫폼의 한계를 어느정도 극복하게 해주기도 하지만, 숙련도가 높지 않다면 큰 부담으로 다가올 수 있고, 숙련도가 높다고 하더라도 귀찮은 작업이 될 확률이 높다.

이런 문제를 해결하고자 등장한 것이 expo이다. expo로 프로젝트를 생성하면 native 폴더가 노출되어 있지 않다는 것을 확인할 수 있다. 또한 기본적으로 앱 개발에 필요한 많은 기능들이 내장되어 있기도 하고, 외부 라이브러리를 설치하더라도 native 단의 코드 셋팅이 불필요해지기 때문에 생산성이 크게 향상될 수 있다. 그리고 expo를 사용하면 window로도 ios 앱을 개발할 수 있다는 점이 큰 장점이 될 수도 있다. 하지만 react native cli보다 비교적 자유도가 떨어질 수 있다는 점과, 일부 라이브러리 설치에 제한이 생길 수 있다는 점, react native cli와 비교해 앱의 용량이 크게 증가할 수 있다는 점을 단점으로 꼽을 수 있다.

이번에는 두가지 방법 중에서 react-native cli를 이용한 방법으로 진행해보려고 한다.

project init

reat native 공식문서를 보면 가장먼저 react naitve 개발을 하기 위한 셋팅을 여러가지 케이스에 맞춰 상세한 가이드를 제공해주고 있다. 가이드를 따라 셋팅을 이미 마쳤다는 가정 하에 터미널에서 프로젝트를 생성할 경로로 이동한 후 아래 커맨드를 입력해 프로젝트를 만들 수 있다.

npx react-native init YourProjectName

(0.71버전부터 기본 설정이 typescript가 되었기 때문에 별도의 템플릿 지정 없이 ts로 프로젝트를 생성할 수 있다.)

stack navigation

처음부터 app으로 만들 목적이 있는 경우가 아니라면 웹자체에서 네비게이션을 지원해주지 않을 가능성이 높다. 따라서 webview앱을 만들기 위해서는 네비게이션 셋팅이 필요할 수 있다. 꼭 웹 내부에서만이 아니더라도 설정과 같은 앱에서만 사용하는 페이지가 생긴다면 네비게이션이 더욱 필요해질 수 있으니 navigation 설정을 먼저 진행해보도록 하겠다.

이번에 설치할 네비게이션은 stack nativgation이다. 스택 네비게이션은 페이지들이 마치 스택과 같이 하나씩 쌓이는 형태로 구현되어 있다. 따라서 페이지 이동이 발생하면 현재 페이지 위에 다음 페이지가 쌓이는 형태이며, 뒤로가기를 누르면 위에 올라와 있는 페이지가 삭제되는 방식으로 구현된다.

installation

yarn add @react-navigation/native react-native-screens react-native-safe-area-context @react-navigation/stack react-native-gesture-handler @react-native-masked-view/masked-view && cd ios && pod install && cd ..

위 커맨드를 실행하면 네비게이션에 필요한 dependencies를 모두 설치할 수 있다.

settings

생성한 파일의 App.tsx(또는 App.jsx)파일의 기본 내용들을 모두 지우고 아래와 코드를 붙여넣으면 네비게이션 기본 셋팅은 끝이다.

import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
import Home from './src/screens/Home';
import Settings from './src/screens/Settings';

const Stack = createStackNavigator();

const App = () => {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={Home} />
        <Stack.Screen name="Settings" component={Settings} />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

export default App;

물론 이대로만 하면 에러가 날테니 프로젝트 src/screens 경로에 Home, Settings 컴포넌트를 만들어두면 좋다.

import React from 'react';
import {View} from 'react-native';

const Home = () => {
  return <View></View>;
};
export default Home;

더 자세한 내용은 react native navigation 공식문서에서 찾아보면 된다.

react native webview

react native webview의 기본 셋팅은 간단하다.

yarn add react-native-webview && cd ios && pod install && cd ..

위 커맨드를 입력해서 패키지를 설치해주고, webview를 보여주고 싶은 위치에 WebView component를 배치해주기만 하면 된다.

import React from 'react';
import WebView from 'react-native-webview';

const Home = () => {
  return <WebView source={{uri: 'https://naver.com'}} />;
};

export default Home;

위와 같이 웹뷰로 네이버를 띄워주면 이런 모습을 볼 수 있다.

back button setting

웹뷰를 구성하는데 이렇게만 해놓으면 사용하기에 굉장히 불편해지는데, 바로 뒤로가기 버튼 셋팅을 해주지 않았기 때문이다. 지금 현재 구성을 살펴보면 react native 앱의 Home screen에 웹뷰를 띄워놓은 상태이다. 그리고 네이버의 "메일" 메뉴를 누르면 네이버 웹의 페이지가 네이버 홈에서 메일함으로 이동하게 된다. 만약 여기서 뒤로가기 버튼을 누르면 어떻게 될까? 물론 현재는 이전페이지가 없기때문에 헤더에 뒤로가기 버튼이 노출되지도 안겠지만, 안드로이드의 물리버튼을 누르거나 webview가 홈이 아니라 다른 스크린이었다면 메일함에서 네이버홈으로 이동하는 것이 아니라 webview자체가 종료되거나 앱이 종료됐을 것이다. 왜냐하면 react native의 navigation 뒤로가기는 해당 앱스크린을 종료하는 것이기 때문이다. 네이버 웹뷰의 페이지가 넘어가는 것과 앱자체의 스크린이 넘어가는 것은 별개의 이벤트로 취급된다. webview에서는 onPress 이벤트를 정의하는 것으로 이 문제를 해결할 수 있다.

관련 블로그 글을 보면 이 문제를 해결하기 위한 해결책을 제시해주고 있다. 블로그에서 제시한 것과 같은 방법을 react native stack navigation의 뒤로가기 버튼에도 적용해주면 아래와 같은 코드가 된다.

import React, {useEffect, useRef, useState} from 'react';
import WebView from 'react-native-webview';
import {BackHandler, TouchableOpacity, View} from 'react-native';
import {WebViewNativeEvent} from 'react-native-webview/lib/WebViewTypes';
import {useNavigation} from '@react-navigation/native';
import {HeaderBackButton} from '@react-navigation/elements';

const Home = () => {
  const ref = useRef<WebView>(null);
  const [navState, setNavState] = useState<WebViewNativeEvent>();

  const navigation = useNavigation();

  useEffect(() => {
    const canGoBack = navState?.canGoBack;

    const onPress = () => {
      if (canGoBack) {
        ref?.current?.goBack();
        return true;
      } else {
        return false;
      }
    };

    navigation.setOptions({
      headerLeft: () =>
        canGoBack ? (
          <HeaderBackButton onPress={onPress} tintColor="#58595B" />
        ) : (
          null
        ),
    });

    BackHandler.addEventListener('hardwareBackPress', onPress);

    return () => {
      BackHandler.removeEventListener('hardwareBackPress', onPress);
    };
  }, [navState?.canGoBack]);

  return (
    <WebView
      source={{uri: 'https://naver.com'}}
      ref={ref}
      onNavigationStateChange={e => setNavState(e)}
    />
  );
};
export default Home;

설정 페이지로 이동

이제 아까 만들어 두었던 Settings screen으로 이동하는 작업을 할 차례다. 바로 직전에 header back button을 설정해주었던 것 처럼 useEffect 내부에서 setOptions를 해줄 거다.

const Home = () => {
	...
    useEffect(()=>{
    	...
        navigation.setOptions({
          headerLeft: () =>
            canGoBack ? (
              <HeaderBackButton onPress={onPress} tintColor="#58595B" />
            ) : null,

          headerRight: () => (    //<-----------headerRight 추가
            <TouchableOpacity
              style={{marginRight: 13}}
              onPress={() => navigation.navigate('Settings')}>
              <Text>설정</Text>
            </TouchableOpacity>
          ),
        });
		...
    },[...])
     
       ...
}

export default Home

예시로 들기위해 버튼을 "설정"이라는 텍스트로 설정했지만, 각자 취향에 맞는 아이콘을 넣어주면 좋다.

profile
React-Native 개발블로그

0개의 댓글