[PWA] beforeinstallprompt로 설치 메세지 보여주기. + iOS 환경에서의 처리

Rachaen·2023년 5월 21일
1

[Frontend] 이것저것

목록 보기
6/7


사용자가 웹 사이트를 방문했을 때 다운로드를 받을 수 있는 사이트인지 잘 모르는 경향이 있습니다.
그래서 설치를 유도하는 것이 중요하다고 생각해서 찾아보다 나온 beforeinstallprompt!

PWA 설치 촉진 패턴

beforeinstallprompt 이벤트

beforeinstallprompt 이벤트는 웹사이트가 사용자에게 앱을 설치할 수 있다는 메세지를 표시하기 전에 발생합니다.
그렇기 때문에 사용자에게 설치 버튼을 표시할 수 있고, 설치 안내를 제공할 수 있고, 설치 프로세를 생략할 수도 있게합니다.

window.addEventListener('beforeinstallprompt', (e) => {
  e.preventDefault();
  deferredPrompt = e;
});

Safari에서는 beforeinstallpromt가 안된다고?!

고려해야 할 상황도 있었습니다.
왜냐하면 safari에서는 beforeinstallprompt가 지원하지 않는다는 사실..
iOS에서는 PWA에대해 안드로이드만큼 지원을 잘 안해줍니다ㅠ

MDN BeforeInstallPrompt

그래서 애플 기기인지 파악을 하여 다른 배너를 보여주여야 겠다고 생각하였습니다.

기기 파악하기

const isDeviceIOS =
  /iPad|iPhone|iPod/.test(window.navigator.userAgent) && !window.MSStream;
setIsIOS(isDeviceIOS);

브라우저의 userAgent를 이용해 현재 사용 중인 기기가 iOS 기반 장치인지 확인하는 코드입니다.
정규식을 이용해서 userAgent 문자열에서 'iPad', 'iPhone' 또는 'iPod' 단어가 있는지 확인합니다.
윈도우 기반 장치에서 iOS를 모방하는 경우도 있기 때문에 !window.MSStream도 추가해줍니다. 현재 환경이 윈도우 환경인지를 확인합니다.

Mozilla/5.0 (iPhone; CPU iPhone OS 16_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.4 Mobile/15E148 Safari/604.1

InstallPrompt

const InstallPrompt = () => {
  const [isShown, setIsShown] = useState(false);
  const [isIOS, setIsIOS] = useState(false);
  const [deferredPrompt, setDeferredPrompt] = useState(null);

  useEffect(() => {
    const isDeviceIOS =
      /iPad|iPhone|iPod/.test(window.navigator.userAgent) && !window.MSStream;
    setIsIOS(isDeviceIOS);

    const handleBeforeInstallPrompt = e => {
      e.preventDefault();
      setDeferredPrompt(e);
      setIsShown(true);
    };

    window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt);

    return () => {
      window.removeEventListener(
        'beforeinstallprompt',
        handleBeforeInstallPrompt,
      );
    };
  }, []);

  // ... 코드 생략 ...

  if (!isIOS && !isShown) {
    return null;
  }

  return (
    /* 설치 프롬프트 컴포넌트 */
  );
};

export default InstallPrompt;

최종적으로 위와 같이 코드를 작성하였습니다.
beforeinstall 이벤트가 발생하면 이를 캐치하여 사용자에게 설치 프롬프트를 보여줍니다.
또한 iOS와 같은 환경에서 다른 메세지를 보여줍니다.

Install App 버튼을 클릭했을 때

  const handleClick = async () => {
    setIsShown(false);
    if (!deferredPrompt) {
      return;
    }
    deferredPrompt.prompt();
    const { outcome } = await deferredPrompt.userChoice;
    setDeferredPrompt(null);
  };
  1. setIsShown(false): 설치 프롬프트를 숨깁니다.
  2. if (!deferredPrompt) { return; }: deferredPrompt 객체가 있는지 확인합니다. (웹앱을 설치하지 못하는 상태이면 종료되도록합니다)
  3. deferredPrompt.prompt(): 웹 앱 설치를 요청하는 프롬프트를 표시합니다.
  4. const { outcome } = await deferredPrompt.userChoice;: 사용자가 설치 프롬프트에 어떻게 응답했는지를 기다린 후, 그 결과를 받습니다.
  5. setDeferredPrompt(null) : deferredPrompt를 초기화합니다. 웹앱 설치를 요청한 후에는 이 객체를 더이상 사용할 수 없기 때문입니다.

현재 기기가 iOS가 아니고, 설치 프롬프트가 표시되지 않아야 할 때

  if (!isIOS && !isShown) {
    return null;
  }

결과

chrome, android

iOS

profile
개발을 잘하자!

0개의 댓글