front-end / / 2024. 4. 30. 16:42

[pwa] 유용한 기능

PWA에서 유용하게 사용할 수 있는 여러가지 기능의 사용법을 모아둔 것이다.

설치 버튼 추가

웹 앱 매니페스트 파일을 만든다. (manifest.json)

{
  "short_name": "Demo App",
  "name": "Demo App",
  "icons": [
    {
      "src": "logo.png",
      "type": "image/png",
      "sizes": "192x192"
    }
  ],
  "start_url": ".",
  "display": "standalone",
  "orientation": "portrait-primary",
  "theme_color": "#000000",
  "background_color": "#ffffff",
  "description": "Demo App 입니다.",
  "dir": "ltr",
  "lang": "ko-KR"
}

설치 버튼 추가

  const [deferredPrompt, setDeferredPrompt] = useState(null);

  const handleInstallBanner = () => {
    if (deferredPrompt) {
      deferredPrompt.prompt();
    }
  };

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

  useEffect(() => {
    window.addEventListener("beforeinstallprompt", handleBeforeInstallPrompt);

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

return (
      <button onClick={handleInstallBanner}>
        홈화면에 추가
      </button>
)

Chrome에서 프로그레시브 웹 앱은 beforeinstallprompt 이벤트를 실행하고 브라우저 내 설치 프로모션을 표시하려면 먼저 다음 기준을 충족해야 합니다.

  • 웹 앱이 아직 설치되지 않았습니다.
  • 사용자 참여 휴리스틱을 충족합니다.
    • 사용자가 페이지를 한 번 이상 클릭하거나 탭했어야 합니다 (이전 페이지가 로드 중일 때 포함).
    • 사용자가 언제든지 페이지를 30초 이상 보는 데 머물러야 합니다.
  • HTTPS를 통해 제공
  • 다음을 포함하는 웹 앱 매니페스트 를 포함합니다.
    • short_name 또는 name
    • icons - 192픽셀 및 512픽셀 아이콘을 포함해야 함
    • start_url
    • display - fullscreen, standalone, minimal-ui 중 하나여야 합니다.
    • prefer_related_applications 필드가 있거나 false이 아니어야 합니다.

참고: https://web.dev/articles/install-criteria?hl=ko

앱 타이틀 색상 변경

<meta name="theme-color" content="red" />

service worker 워커 변경 감지

서비스 워커가 변경되었을 경우 updatefound 이벤트를 통해 알아낼 수 있다.

self.registration.addEventListener("updatefound", (event) => {
  const newSW = self.registration.installing;
  newSW.addEventListener("statechange", (event) => {
    if (newSW.state == "installed") {
    }
  });
});

display mode 가져오기

앱을 브라우저로 띄웠는지 standalone 모드(App)로 띄웠는지 체크하는 로직

const getLaunchDisplayMode = () => {
    let displayMode = "browser";
    if (window.matchMedia("(display-mode: standalone)").matches) {
      displayMode = "standalone";
    }

    return displayMode;
}

displayMode = browser or standalone 이 나온다.

여기서 브라우저에서 standalone으로 전환을 한 경우 displayMode가 browser로 그대로 표시된다. 그래서 아래의 전송 감지 기능을 사용해야 한다.

전송 감지

브라우저와 앱 간의 전환을 감지하려면 미디어 쿼리를 사용한다.

window
        .matchMedia("(display-mode: standalone)")
        .addEventListener("change", (evt) => {
          let displayMode = "browser";
          if (evt.matches) {
            displayMode = "standalone";
          }
          // Log display mode change to analytics
          console.log("DISPLAY_MODE_CHANGED", displayMode);
        });

앱 설치 이벤트

앱 설치가 되면 app installed 이벤트가 실행된다.

window.addEventListener('appinstalled', () => {
  // If visible, hide the install promotion
  hideInAppInstallPromotion();
  // Log install to analytics
  console.log('INSTALL: Success');
});

미디어 쿼리

/* It targets only the app used within the browser */
@media (display-mode: browser) {
}
/* It targets only the app used with a system icon in standalone mode */
@media (display-mode: standalone) {
}
/* It targets only the app used with a system icon in all mode */
@media (display-mode: standalone), (display-mode: fullscreen), (display-mode: minimal-ui) {
}

파일 시스템 읽기

파일을 찾아서 파일의 내용을 읽어들인다.

[app에서만 실행 가능, 브라우저에서 실행 불가]

const openFile = async () => {
    const [handle] = await window.showOpenFilePicker();
    // Get the File object from the handle.
    const file = await handle.getFile();
    // Get the file content.
    // Also available, slice(), stream(), arrayBuffer()
    const content = await file.text();
    console.log("content", content);
};

파일 시스템 쓰기

파일의 내용을 수정한다. 위의 파일 시스템을 읽어서 내용 뒤에 modified라고 추가하자.

[app에서만 실행 가능, 브라우저에서 실행 불가]

const openFile = async () => {
    const [handle] = await window.showOpenFilePicker();
    // Get the File object from the handle.
    const file = await handle.getFile();
    // Get the file content.
    // Also available, slice(), stream(), arrayBuffer()
    const content = await file.text();
    console.log("content", content);

    const writable = await handle.createWritable();
    // Write the contents of the file to the stream.
    let contents = content + " modified";
    await writable.write(contents);
    // Close the file and write the contents to disk.
    await writable.close();
  };

연락처 정보 가져오기

const getContacts = async () => {
    const properties = ["name", "email", "tel"];
    const options = { multiple: true };
    try {
      const contacts = await navigator.contacts.select(properties, options);
      console.log(contacts);
    } catch (ex) {
      // Handle any errors here.
      console.error(ex);
    }
  };

절전 모드에 빠지지 않게 하기 (wake lock)

화면을 오래 보다 보면 절전모드로 빠질 수가 있다. 아래 스크립트를 적용하면 절전모드로 빠지지 않는다.

https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API

if ("wakeLock" in navigator) {
      try {
        console.log('"wakeLock" in navigator', "wakeLock" in navigator);
        wakeLock = await navigator.wakeLock.request("screen");
        console.log("Wake Lock is active!");

        wakeLock.addEventListener("release", () => {
          console.log(`Screen Wake Lock released: ${wakeLock.released}`);
        });
      } catch (err) {
        // The Wake Lock request has failed - usually system related, such as battery.
        console.log(`${err.name}, ${err.message}`);
      }
    }
반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유