[nextJs] <InAppBanner> 작업 (feat. device check, deep link , pageProps)

해달·2023년 2월 21일
0

개요

웹에서 앱으로 유저를 인입시키기 위해 앱으로 보기 작업 해야했음

예시 (farfetch)


요구사항

  1. 모바일 환경에서만 보여주어야 함
  2. 딥링크
  3. 쿠키로 유효기간 설정
  4. 저장되어 있는 쿠키를 바라보고 화면에 띄워줄지 말지 정해야 함

구현

1. device 체크 (UserAgent, getLayout)

요구사항

  1. 웹을 데스크탑으로 이용하는 유저에게 노출시키지 않는다

유저가 접속 한 디바이스 종류를 알 수 있는 userAgent 값을 사용한다.
이 값은 header에 정보가 담겨있다.

nextJs를 사용하면 getInitailProps를 이용하여 header에 있는 값을 추출 할 수 있다.

_app.tsx


MyApp.getInitialProps = async (appContext) => {
  
  //userAgent
  const userAgent = appContext.ctx.req?.headers['user-agent']

  //Mobile
  const mobile = await userAgent?.indexOf('Mobi');
  const isMobile = // mobile check
        
  appProps.pageProps.device =  ? 'M' : 'W';


  return { ...appProps };
};

모바일 체크

개발자도구에서 기기 툴바 전환을 이용해 모바일 형태로
페이지에 접속해서 요청헤더를 확인해보면 아래와 같이 Mobile 이라는 값이 들어있는 걸 확인할 수 있다

  1. userAgent에서 모바일인지 아닌지를 확인한다
  2. 판별한 값을 pageProps에 device 라는 이름으로 저장한다.
  3. 내려받은 값을 getLayout에서 페이지를 랜더링 할 때 pageProps에서 꺼내어 사용한다
  • getLayout으로 모든 레이아웃을 정의해놓으면 페이지마다 균일하게 레이아웃을 적용시켜 줄 수 있다
Page.getLayout = function getLayout(page: ReactElement) {
  const { device } = page.props;
  
  console.log(device) // "W" | "M"
 
  return (
      <Layout>
        {page}
      </Layout>
  );
};

2. 딥링크 firebase 생성

요구사항

  1. 이미 앱이 설치되어 있는 유저는 앱을 켜주어야 한다
  2. 앱이 설치되어 있지 않은 유저는 android/ios 에 맞추어서 스토어 설치 페이지로 보내주어야 한다.

위와 같은 요구사항을 편리하게 도와주는 firebase deeplink 기능을 사용하였다.

dynamic link (동적링크)라고 표현되지만 파이어베이스에서는 deeplink라는 용어를 사용한다.

⛔️ 발생했던 문제 ⛔️

안드로이드, IOS 시뮬레이터에서 적용한 딥링크를 이용해서 페이지를 넘어가니
유효하지 않은 주소 라고 계속 에러가 발생해서
메인 배포 이전에 stating 환경에 올려서 실제 기기로 테스트하니까 잘 되었다.
시뮬레이터에서는 딥링크 안되는 이슈가 있었다.
(엄청 헤맴 ..)

딥링크 생성 참고 게시글
다른분들이 블로그로 생성방법과 적용 방법을 상세하게 기재해두어 참고해서 사용했다
https://ios-development.tistory.com/726

생성 후 아래와 같이 Link 태그로 적용시켜주면 된다.

const deepLink = `생성한 짧은 동적 링크`

<Link href={deepLink}>
  <button>앱으로 보기</button>
</Link>

3. 쿠키로 유효기간 설정

요구사항

유저가 휴대폰 웹으로 접속했어도 앱으로 보기 배너를 보고 싶지 않은 경우
일정기간 동안 노출 시키지 않아야 했다.

클라이언트에서 쿠키를 직접 건드는 일은 없지만 1.정해진 기간동안 2.보지 않겠다는 유저의 정보를 저장해 놓아야 해서 cookie를 세팅해주었다.

export const setCookie = (name: string, value: string, day: number = 1) => {
  //유효기간 설정
  const date = new Date();
  date.setTime(date.getTime() + day * 24 * 60 * 60 * 1000);

  const expires = 'expires=' + date.toUTCString();

  //쿠키세팅
  document.cookie = `${name}=${value};` + expires + '; path=/';
};

util 함수로 빼내어서 유저가 배너를 껏을 때 (정해진 기간)동안
배너를 띄우지 않는 값을 저장해서 활용했다.


4. ⛔️저장되어 있는 쿠키를 바라보고 화면에 띄워줄지 말지 정해야 함

요구사항

  1. cookie를 확인해서 유저가 앱을 보지 않겠다고 한 경우 banner를 쿠키 값이 존재할 때 까지는 노출시키지 않는다

구현방식

device를 저장한 것과 같이 pageProps에 값을 내려주어 사용
getInitialProps에서 내려주는 값은 첫 빌드 될때의 쿠키값이 유지가 되어서 아래와 같은 경우 배너가 유지되는 현상이 발생했다.

⛔️발생한 문제❌

_app.tsx 에서 값 확인해서 props로 내려주는데 처음 빌드 된 document를 바라보고 있어서
close button을 누르고 다른 페이지로 이동했다가 뒤로가기 했을 때
초기에 빌드 된 페이지를 읽어서 cookie 값이 갱신이 되지 않아
제일 초기화면에서 계속 배너가 뜨는 현상이 발생
1. 홈탭 (배너닫기)
2. 다른 페이지 이동(cookie 업데이트 된 상태)
3. (뒤로가기) 홈탭 => 배너 유지

현재 서비스에서 첫 페이지 index.tsx 파일에서
아래와 같이 기본 페이지를 지정해 export 하고 있었다.

export { default } from './home';

뒤로가기로 접속했을 때에도 페이지가 cookie 값을 업데이트 시키고 싶어 찾아본 결과
공식홈페이지에서 export 방식에서도 getServerSideProps를 export 할 수 있었다.

export { default, getServerSideProps } from './home';

⚠️ 아닐수도 있음

위 방식이 동작한 까닭은 공식문서에서 찾아본 내용으로는 serverSideProps를 사용하게되면 페이지를 요청별로 렌더링 한다고 나와있다.
serverSideProps를 같이 내보내지 않았을 때는 초기에 빌드되어서 받아온 정적 페이지가 (cookie에 값이 없는 첫 페이지) 렌더링되어서 발생한 문제인거 같다.
serverSideProps를 사용해 페이지를 다시 불러왔을 때 다시 렌더링을 하게 되어 값을 잘 읽어 올수 있었다고 이해했다.

공식문서

If getServerSideProps or getInitialProps is present in a page, Next.js will switch to render the page on-demand, per-request (meaning Server-Side Rendering).
If the above is not the case, Next.js will statically optimize your page automatically by prerendering the page to static HTML.


마치며,

그 외에도 InAppBanner를 세팅하면서 cookie 저장되기 이전에 action이 발생했을 때 바로 배너를 끄기위해 state도 사용해야 했고,
Layout마다 값을 내려주면서 적용시켜주어야 했는데 이 부분을 간략화 하고 싶어서 찾아봤으나 결국 찾지 못했다.

처음에는 nextJs에서 지원해주는 server api를 사용해볼까 했는데,
생각보다 복잡하고 시간이 많이 소요될 거 같아서 작업하다가 멈추었고 (이미 시간씀..)

금방 마무리 할 수 있는 작업이라고 생각했는데
요구사항에 맞게 작업을 하다보니 (아주 간단한)일은 아니고 고려해야 할 상황이 많았던거 같다.
요구사항을 처음에 제대로 정의하지 않아서 발생했던 문제들도 있었기에
다음부터 무언가를 하게된다면 우선적으로 요구사항들을 꼼꼼히 검토해야겠다는 생각을 했다 😌

하나의 작업에 많은 여러가지 일들을 해서 기록해 놓아야겠다고 생각해서 오랜만에 블로깅 ..!


reference

0개의 댓글