[ 강연 기록 ] 웹뷰를 이용해 웹 서비스를 앱으로 빠르게 구현하기 - 인프콘 2023

모아나·2025년 1월 2일
0

1. 앱을 고려하기

웹 앱과 모바일 앱

  • 웹앱: 모바일 화면’도’ 구성한 웹
    • HTML, CSS, JS로 개발
    • 모바일 기기의 웹 브라우저로 앱처럼 사용
    • 다양한 모바일 플랫폼의 지원이 가능
    • 유지보수가 쉽고 스스로 업데이트 할 수 있음
    • 네이티브 앱보다 생산 비용이 저렴
  • 모바일 앱: 모바일 화면’만’ 구성한 앱
    • SDK 개발이 필요
    • 모바일 기기에 앱을 다운해 사용
    • 다양한 모바일 기기의 기능과 호환됨
    • 스토어의 승인을 통해 안전성을 보장
    • 인터넷 연결 없이 동작

웹 뷰

앱이 웹 컨텐츠를 표시하는 데 사용할 수 있는 내장형 브라우저

  • 웹 뷰 내에서 실행되는 자바스크립트는 기본 시스템 API를 호출할 수 있습니다.
  • 웹뷰는 js를 통해 네이티브 기능과 통합할 수 있다.

이러한 통신방식을 브릿지라고 함.

브릿지 Bridge

  • 네이티브와 웹뷰의 통신을 위해 제공되는 자바스크립트 인터페이스
  • 웹뷰가 직접 네이티브 API를 호출할 수 없으므로 반드시 브릿지를 통해 호출
  • 즉, 브릿지는 웹뷰 인터페이스의 구현체

대표적인 웹뷰의 통신 객체

  • Window 오브젝트 사이에서 안전하게 Cross-Origin 통신이 가능
  • 대중적으로 페이지와 팝업, 페이지 내부의 페이지 iframe 간의 통신에 사용 (예: 유튜브)
  • Window.postMessage를 통해 전달되는 인자는 이벤트 객체를 통해서만 사용 가능
    - Window.addEventListener("message", callback)으로 핸들링 가능

웹뷰가 좋은 이유

  • 웹과 앱을 한번에 개발 가능
  • 앱을 배포하지 않아도 웹뷰를 수정하면 반영 가능 => 한번 심사를 받으면 그 이후 앱스토어 심사 불필요

기술적으로 좋은 이유

  • 런타임 시 발생하는 웹 코드 격리 ⏩ 개발자가 로드되는 컨텐츠를 추가적으로 제어 가능
  • 웹에 종속적이나 앱에 종속적이지 않음 ⏩ 웹뷰의 보안/부수적인 기능에 대해 재정의 가능
  • 웹과 앱의 통신 방법을 다양하게 적용 가능 ⏩ 특정 플랫폼에 종속 되지 않고 통신이 가능

생기는 선택지

  • 센서(GPS, 자이로..), 알림, 카메라 등 사용 가능
  • 모바일 저장소 사용 가능
  • 일정, 연락처 접근 가능
  • 앱 대 앱 공유 가능
  • 그 외 여러 네이티브 시스템과 깊이 통합 가능

2. 앱을 준비하기

React Native vs Flutter

RN

  • 아직까지도 메이저 버전이 릴리즈 되지 않음
  • 메타가 사실상 포기

Flutter

  • 구글에서 관리하고 꾸준히 업데이트를 통해 발전하는 중

정리

  • 웹 없이 앱을 시작하되, 네이티브 개발 리소스가 없다면 => 플러터
  • 리액트를 사용하여 웹서비스를 개발 중이라면 => 리액트 네이티브

리액트 네이티브 웹뷰가 제공하는 브릿지 웨이

리액트 네이티브 -> 웹

  • injectedJavaScript 프로퍼티
  • injectJavaScript 메서드
    웹 -> 리엑트 네이티브
  • onMessage 프로퍼티
  • postMessage 메서드

3. 앱을 설정하기

리액트가 네이티브 앱으로 통합되는 과정

  • 결국 리액트 네이티브에서 자바스크립트로 한번은 컴파일 되어야 함.

React Native CLI (직접 요리)

  • 리액트 네이티브 팀과 커뮤니티 가 제공한 툴
  • 기초적인 개발 설정을 제공하지만 추가 구성 및 설정 필요
  • 자바스크립트 코드와 네이티브 기기 소스 코드를 합쳐야 한다면 React Native CLI가 좋음

Expo CLI (간편 밀키트)

  • 정리된 앱 개발 워크플로우로서 프로젝트 생성 및 코드 작성과 네이티브 기능 통합이 쉬움
  • React Native CLI를 사용하는 것보다 훨씬 쉽고 간단해 언제는 React Native CLI로 전환 가능
  • EAS: Expo 관리 장치에서 앱을 빌드하고 앱 스토어에 제출하는 프리미엄 서비스
  • React Native를 처음 시작하거나, 빠르고 쉽게 앱을 만들어보고 싶을 때 사용. (하지만 기능 확장이 제한될 수 있음)

간단한 CLI 설정

# Expo CLI 설치
sudo npm install -g expo-cli

# 원하는 프로젝트로 변경
cd {원하는 프로젝트 경로}

# Expo 프로젝트 생성
npx create-expo-app --template {Example}
npm create expo-app

# WebView 라이브러리 설치
yarn add react-native-webview

4. 앱을 개발하기

필수적으로 알아야 하는 개념

앱에서는 브라우저가 아니기 때문에 라우팅이 없다! 대신 네비게이션이 있다.

  • 네비게이션: 화면 중첩과 보호
  • 네이티브 기기와 통신: 권한 획득

네비게이션이란?

  • 웹은 앵커 태그 (< a >)
    - 웹의 URL이 브라우저 히스토리에 스택으로 푸시

  • 앱은 네비게이터

    • 네비게이션은 정의한 화면을 렌더링하는 방법을 결정하는 리액트 컴포넌트
    • 앱이 화면을 전환하고 탐색 기록을 관리할 수 있는 방법
    • 메모리에서 스크린을 스택으로 관리
  • 차이점은 스택이 변경될 때 제스쳐와 애니메이션을 제공한다는 것

네비게이션을 구성하는 방법

  • 네비게이션 컨테이너

    	- 탐색 트리를 관리하고 상태를 포함하는 루트 컴포넌트
    • 모든 네비게이터 구조는 여기에 래핑
  • 화면 구성을 정의하기 위한 스크린 컴포넌트를 자식으로 포함

스택

  • 새 화면이 스택 위에 배치
  • 화면 간 앱이 전환하는 방법 제공
  • iOS, Android 기본 애니메이션이 적용되나 커스텀 가능
import { createNativeStackNavigator } from '@react-navigation/native-stack';

const Stack= createNativeStackNavigator();

const StackNavigator = ()=>(
  <Stack.Navigator>
  	<Stack.screen name="Home" component={HomeScreen} />
  </Stack.Navigator>
);

드로어

  • 이것 또한 네비게이션
  • 제스처를 통해 열고 닫을 수 있는 화면을 렌더링

바텀 탭

  • 다른 영역을 전환할 수 있는 화면 하단의 탭 모음
  • 영역은 천천히 초기화 되고, 처음 열리기 전까지 마운트 되지 않음

네비게이션들은 전부 스크린에 컴포넌트 props로 navigation, route를 주입함. 이를 이용해 웹뷰에서 넘어오는 코드를 효율적으로 핸들링 할 수 있다.

스크린 컴포넌트

  • navigation

    	- navigate: 스크린 이름을 입력해서 이동 (다른 화면으로 이동)
    • reset: 유저 정보 등 민감한 정보를 제어한 후 스택 제어 (네비게이터 상태를 지우고 새로 교체)
    • goBack: 웹 컴포넌트의 "뒤로가기"를 직접 구현 가능 (활성 화면을 닫고 스택의 뒤로 이동)
    • dispatch: 절대 url 경로를 스택으로 푸시 가능 (탐색 상태 업데이트를 위한 객체 전송)
  • route

    	- params: 초기 데이터 또는 스크린에 `initialParams`로 추가 정의 가능 (매개변수 전달)

풀스크린 웹뷰가 아니라면..?

  • 훅으로 제공하고 있다 !
  • useNavigation(), useRoute()

앱을 개발해보기: Hello, Real World!

앱 구현과 기본적인 설계는 어떻게?

  • 모바일 웹과 앱에서의 컴포넌트를 어떻게 구분해 제어할까?
    • 앱(웹뷰)인지 여부를 판단해서 조건문으로 컴포넌트를 렌더링하자!
  • 페이지 라우팅은 어떻게 제어할까?
    • router 이벤트를 발생시키지 않고 postMessage로 웹뷰에 보내자!
  • 로그인 여부에 따라 다른 화면을 보여줄 수 있을까?
    • 쿠키, 로컬 스토리지에 저장된 유저 정보를 전송하고 네비게이션을 충첩해보자
  • 유저 정보를 어떻게 저장해둘까?
    • 리액트 네이티브 저장소 라이브러리를 적용해보자!

앱, 웹뷰, 모바일 웹 어떻게 판단하죠?

  • 윈도우 객체 정보로 판단하기: window navigator 객체의 userAgent & window.ReactNativeWebView
  • 스크린 넓이로 판단하기
    - 반응형인데 웹뷰인지 체크해야할 경우 윈도우 객체 정보와 결합해 판단

라우트 이벤트 제공?

  • 웹뷰에게 메시지를 전달하기 위한 함수
    : 윈도우 객체가 가지고 있는 브릿지 이용. 윈도우 postMessage를 이용해 웹뷰에 전달하면 웹뷰가 핸들링해서 제어.

  • 라우팅 발생 시 웹뷰일 때 sendMessage, 웹뷰가 아닐 때 router.push

로그인 유저를 어떻게 구분?

두 가지 케이스: 중첩 네비게이션,

  • 중첩 네비게이션
- 다른 네비게이션에 중첩 렌더링
- 상위 네비게이터에서 하위 네비게이터로 디스패치 가능
  • 정보 저장 - 로컬스토리지

    	- `@react-native-async-storage/async-storage` : 리액트 네이티브 커뮤니티에서 개선과 유지보수를 담당하는 라이브러리
    • 리액트 네이티브를 위한 암호화되지 않은 키-값 저장소로 비동기 동작
    • 다중 플랫폼 지원
    • 직렬화를 통한 string 데이터 저장, localStorage와 같은 방법

    푸시알림

    알림의 종류

    • 로컬 알림: 앱이 설치된 기기에서 설치된 앱이 트리거하는 알림 (리마인더, 알람 시계, 할일 앱 등
    • 푸시 알림: 내 기기에 설치된 앱에서 트리거된 알림을 다른 기기에 설치된 앱으로 전송

    로컬알림

  • expo-notifications 설치

  • 코드: https://github.com/pagers-org/webview-app/blob/local-notification/App.js

    리액트 네이티브의 코어 컴포넌트

  • HTML이 아니기 때문에 div, h2 태그 등 HTML요소 사용 불가

  • 컴파일된 네이티브 코드가 자바스크립트에 의해 번들링 됨

존재하지 않는 CSS

  • 브라우저가 아니기 때문에 제어 및 사용 불가
  • DOM 구조가 아니므로 스타일 상속이 존재하지 않음
  • 프로퍼티를 이용한 인라인 스타일과 StyleSheet객체로 작성 가능

웹과 다른 이벤트

  • Click 이벤트 대신 pressable 컴포넌트로 감싸서 이벤트 핸들링
  • DOM 이벤트 객체가 없으므로 event.nativeEvent 객체를 활용한 핸들링
  • DOM의 스크롤이 없으므로 ScrollView 컴포넌트로 스크롤을 핸들링

앱의 빌드는 EAS의 도움을 받는다

  • eas build
  • ios 번들은 유료임.

정리

목표는 최소한의 개발, 최대한 빠른 릴리즈

  • 화면에 대한 설계: 각 화면의 연결을 어떻게 관리할 것인지 네비게이션 고려
  • 웹, 모바일웹, 앱을 구분하는 함수를 만들고 웹과 앱이 통신하는 브릿지 작성
  • 유저의 사용성을 개선하기 위한 저장소 추가
  • 앱이 배포되기 위한 필요 최저한의 네이티브 개발
    - 푸시알림

개발 완료된 웹과 앱

앱 출시는?

계정 준비

  • 구글 개발자 계정, 애플 개발자 계정을 각각 등록

에셋 준비

웹뷰만 사용한 앱출시?

  • 앱 심사 거절 내용 중 일부

    귀하의 앱이 제공하는 경험은 기본 ios기능을 통합해 제공하는 웹 브라우징 경험과 충분히 다르지 않습니다. 특정 사용자 또는 틈새 사용자 그룹을 위해 웹 속성에 대한 편리한 액세스를 제공하고 푸시 알림과 같은 기능으로 해당 경험을 향상시킬 수 있습니다. 그러나 이러한 앱에는 앱 스토어에 적합할 만큼 충분한 기본 ios 기능이 포함되어있지 않습니다.

  • 웹과 똑같은데 꼭 앱이어야할 이유가 있는가?

앱을 확장하기

  • 스플래시 이미지, 앱 아이콘을 쉽게 등록할 수 있는 app.json
  • 상태 표시줄 디자인을 도와주는 statusBar 컴포넌트
  • 기기의 모서리, 상단 노치 등의 간격을 조절해주는 SafeAreaView 컴포넌트
  • 앱의 테마를 설정할 수 있는 여러 수단: app.json, useTheme, StyleSheet
  • 유저 인터랙션 UI에 대한 핸들링
  • 리액트 네이티브에서 제공하는 컴포넌트만으로는 더 예뻐질 수 없는 우리의 서비스

나머지 고려사항

  • 브릿지 인터페이스의 확장

  • 스토어에 배포하기 전 앱의 안정성 관리
    - 릴리즈 버저닝, 테스트 및 사용자 앱 버전 관리

  • 화면 보호하기

    • 웹뷰 URL 노출 숨기기
    • 네비게이션 중첩을 활용해 어떻게 사용성을 증가시킬지
  • 이벤트 수집: 앰플리튜드, GA, 파이어베이스

  • 서비스 로그 수집: 앱, 서버, 인프라 모니터링 수단 강구

  • 네트워크 상태가 불안정해도 흔들리지 않는 사용자 경험 제공

    • 캐싱 적용
    • 웹뷰와 네이티브 컴포넌트의 종속성을 분리해 구성
profile
Make things

0개의 댓글