PWA 페이지에서 앱 설치를 유도해보기 (feat. React)
2023년 02월 15일
beforeinstallprompt는 무엇일까?
beforeinstallprompt
사용자가 디바이스에 설치할 수 있는 프로그레시브 웹 앱(PWA)을 방문할 때 브라우저에서 실행되는 이벤트입니다. 이 이벤트는 앱이 사용자에게 앱을 디바이스에 독립 실행형 애플리케이션으로 설치하라는 메시지를 표시할 기회를 제공합니다.
이벤트가 트리거 되면 브라우저는 일반적으로 사용자에게 앱을 설치할지 여부를 묻는 메시지를 표시합니다. 이벤트는 앱당 한 번만 트리거 되며, 앱의 자바스크립트 코드에서
window.addEventListener()
메소드를 사용하여 이벤트를 캡처하고 처리할 수 있습니다.
간단하게 말해서 사용자가 pwa로 만들어진 웹 페이지를 방문했을 때 기존에 설치하려면 크롬 같은 경우에는 따로 설정을 눌러서 앱 설치 버튼을 눌러야 하지만 beforeinstallprompt를 사용하면 브라우저가 설치를 안 한 사용자 여부를 판단해 설치 버튼을 띄워주는 기능을 해줍니다. 저도 PWA 프로젝트 하나를 만들었는데 이 기능을 집어넣었습니다.
React에 적용해보기
addEventListener에 등록하기
useEffect(() => {
window.addEventListener("beforeinstallprompt", handleBeforeInstallPrompt);
return () => {
window.removeEventListener(
"beforeinstallprompt",
handleBeforeInstallPrompt
);
};
}, []);
useEffect에 의존성에 빈 배열을 넣음으로써 마운트시 한 번만 실행되도록 설정합니다. 또한 메모리 누수를 방지하기 위해서 언 마운트시에는 이벤트리스너를 지워줍니다. 여기서 beforeinstallprompt는 사용자가 해당 앱 설치를 하지 않았을 때만 발생하는 리스너입니다.
const [deferredPrompt, setDeferredPrompt] = useState(null);
const handleBeforeInstallPrompt = (event) => {
event.preventDefault();
setDeferredPrompt(event);
};
beforeinstallprompt 리스너가 발동할 때 handleBeforeInstallPrompt 함수가 실행되면서 event를 억제하고 deferredPrompt state에 event 객체를 저장합니다. 이제 deferredPrompt 객체를 활용하면 사용자한테 설치 프롬프트를 띄워줄 수가 있습니다.
return (
<div>
{deferredPrompt && <button onClick={handleInstall}>Install</button>}
</div>
);
deferredPrompt 객체가 존재할 때 null 상태가 아닐 때만 사용자한테 앱 설치 버튼을 띄워 줄 수 있습니다. 또한 button 태그의 onclick event를 handleInstall함수로 받게 합니다.
const handleInstall = () => {
if (deferredPrompt) {
deferredPrompt.prompt();
deferredPrompt.userChoice.then((choiceResult) => {
if (choiceResult.outcome === "accepted") {
console.log("사용자가 앱 설치를 동의했습니다.");
} else {
console.log("사용자가 앱 설치를 동의하지 않았습니다.");
}
setDeferredPrompt(null);
});
}
};
handleInstall 함수에서는 우선 deferredPrompt event 객체가 존재하는지 여부를 판단 후 deferredPrompt.prompt()
를 사용해 실제로 사용자한테 설치할지를 물어봅니다.
만약 설치한다고 응답을 보내면 앱을 설치하도록 실행합니다. deferredPrompt.userChoice.then()
을 사용해서 사용자의 응답 여부를 기다립니다. choiceResult.outcome 값이 accepted일 경우 설치 동의했다는 뜻입니다. 마지막으로 deferredPrompt값을 비워줌으로써 앱 설치를 다시 띄워주지 않습니다.
실제 제 프로젝트에 적용
import React, { useEffect, useState } from "react";
import Button from "../UIElements/Button";
import { RiInstallLine } from "react-icons/ri";
const PWAInstallPrompt = () => {
const [deferredPrompt, setDeferredPrompt] = useState<any>(null);
useEffect(() => {
window.addEventListener("beforeinstallprompt", handleBeforeInstallPrompt);
return () => {
window.removeEventListener(
"beforeinstallprompt",
handleBeforeInstallPrompt
);
};
}, []);
const handleBeforeInstallPrompt = (event: Event) => {
event.preventDefault();
setDeferredPrompt(event);
};
const handleInstallClick = () => {
if (deferredPrompt) {
deferredPrompt.prompt();
deferredPrompt.userChoice.then((choiceResult: { outcome: string }) => {
if (choiceResult.outcome === "accepted") {
console.log("사용자가 설치 프롬프트에 동의했습니다.");
} else {
console.log("사용자가 설치 프롬프트를 무시했습니다.");
}
setDeferredPrompt(null);
});
}
};
return (
<React.Fragment>
{deferredPrompt && (
<Button size="large" onClick={handleInstallClick}>
<RiInstallLine />
</Button>
)}
</React.Fragment>
);
};
export default PWAInstallPrompt;
위 코드는 제가 만든 프로젝트에 실제로 적용을 한 코드 전체입니다.
제가 만든 프로젝트 Click ME!!
참고 문서
자신만의 인앱 설치 경험을 제공하는 방법