분류 html

프로그레시브 웹 앱 이해: 모바일 경험 제공 - 2021년 HTML5 및 JavaScript 서비스 작업자

컨텐츠 정보

  • 조회 558 (작성일 )

본문

PWA 란 무엇입니까? 


PWA(Progressive Web Application)는 웹을 통해 제공되는 일종의 앱 소프트웨어입니다. PWA는 HTML, CSS 및 JavaScript와 같은 일반적인 기술을 사용하여 구축됩니다. 데스크톱 또는 모바일 장치에서 W3C 호환 웹 브라우저를 사용하는 모든 플랫폼에 설치하고 작동할 수 있습니다.

브라우저는 보안 연결(SSL 암호화 기술 사용) 또는 로컬 호스트에서만 웹 애플리케이션이 PWA가 되도록 허용한다는 점에 유의해야 합니다.


누가 PWA를 설치할 수 있습니까? 


PWA에 대한 지원은 대부분 모바일 브라우저에 중점을 두고 있지만 일부 데스크톱 브라우저에 대한 지원도 제한적입니다.


2021년 8월 지원: 

Mobile:

KaiOS를 제외한 거의 모든 모바일 브라우저는 PWA를 지원합니다.


Desktop:

  • Chrome 39 & UP
  • Edge 79 & UP
  • IOS Safari/Chrome 11.3 & UP - Partial Support
  • Firefox - Deprecated as of January 2021

Progressive Web App Browser Support Table 


왜 PWA를 개발해야 합니까? 


목적:

PWA를 사용하면 모든 장치에 설치할 수 있고 기본 앱과 구별할 수 없는 방식으로 작동하는 웹 응용 프로그램을 제공할 수 있습니다. 특정 기준을 충족하면 웹사이트나 웹 애플리케이션도 쉽게 PWA로 전환될 수 있습니다.


필요한 기술:

  • HTML 
  • CSS 
  • 자바스크립트 
  • NodeJS(여기서 사용할 선택적 패키지)


혜택:

  • 애플리케이션 스토어 등록
  • 오프라인 폴백
  • 네트워크 또는 캐시 우선 리소스 가져오기
  • 푸시 알림
  • 백그라운드 동기화
  • 그리고 더

시작하는 데 많은 시간이 필요하지 않습니다!


파일 구조

    -root/
      -index.html
      -manifest.json
      -service-worker.js
      -logo.[png, jpg, etc...]


index.html 


개발은 기본 HTML5 상용구로 시작할 수 있습니다.


HTML5 상용구 

<html lang="en">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>TechSnack Simple PWA</title>
      </head>
      <body>
        <h1>Hello World!</h1>
      </body>
    <html>


manifest.json 


사용자의 장치가 웹 응용 프로그램으로 무엇을 해야 하는지 알 수 있도록 몇 가지 세부 정보를 제공해야 합니다. 이러한 세부 사항은 상당히 자명합니다.


지금은 아이콘 배열을 비워 둡니다. 이에 대한 자세한 내용은 곧.


{
      "name": "TechSnack Simple PWA",
      "short_name": "TechSnack",
      "start_url": "/?home=true",
      "icons": [],
      "theme_color": "#000000",
      "background_color": "#FFFFFF",
      "display": "fullscreen",
      "orientation": "portrait"
    }


이 정보를 사용하여 사용자의 장치는 다음을 수행할 수 있습니다.


  • 애플리케이션 설치
  • 앱 실행을 위한 사용자 지정 아이콘 적용
  • 시작 시 사용자 지정 시작 화면 표시
  • 응용 프로그램 창 및 동작 사용자 지정 허용
  • 네이티브 애플리케이션 동작 모방
  • GPS 및 푸시 알림과 같은 기본 기능에 대한 액세스 허용
  • 인기 있는 앱 스토어에 애플리케이션 등록

manifest.json 연결 


링크 태그를 사용하여 manifest.json을 앱에 연결합니다.

    <head>

      ...

      <link rel="manifest" href="manifest.json">
    </head>


노드 패키지(1 - 선택 사항) 


앞서 언급했듯이 사용자의 장치는 사용자 지정 아이콘을 적용합니다. 그렇게 하려면 장치가 참조할 이미지를 하나 이상 제공해야 합니다.


여러 화면 크기 또는 해상도는 어떻습니까? 


오늘날 전 세계적으로 수많은 다양한 모바일 장치가 사용되고 있습니다. 시각적 자산의 표시를 최적화하기 위해 각 장치는 특정 차원의 로고를 선호합니다.


pwa-asset-generator 


다음 MIME 유형의 이미지 파일이 하나 이상 필요합니다.

  • PNG
  • JPEG/JPG
  • SVG
  • WebP

설치 


$ npm install --global pwa-asset-generator


이제 webroot 디렉토리에서 패키지를 실행하려고 합니다. 다음 스니펫은 우리의 목적을 위해 수행할 것입니다.


npx pwa-asset-generator [path/to/logo] [path/to/output/dir] -i [path/to/index.html] -m [path/to/manifest.json] -f
The -f flag generates favicon image/meta tag 


Execution - From webroot directory 

$ npx pwa-asset-generator logo.jpg logos -i index.html -m manifest.json -f


Command line output | pwa-asset-generator | npm 


-i, -m 및 -f 플래그를 사용하지 않고 pwa-asset-generator를 실행하면 결과가 대신 콘솔에 출력된다는 점에 주목할 가치가 있습니다.


결과를 복사하여 manifest.json 내의 아이콘 배열에 붙여넣습니다.


Command line output | pwa-asset-generator | npm 


출력을 복사하여 index.html의 head 태그에 붙여넣습니다.


Command line output | pwa-asset-generator | npm 


새 아이콘/디렉토리 


생성된 모든 이미지를 포함합니다.


Directory Structure for PWA Icon Images 


업데이트된 index.html 


index.html 파일은 이제 다음과 같아야 합니다.


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="theme-color" content="#000000">
    <link rel="apple-touch-icon" href="icons/apple-icon-180.png">

    <meta name="apple-mobile-web-app-capable" content="yes">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-2048-2732.jpg" media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-2732-2048.jpg" media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-1668-2388.jpg" media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-2388-1668.jpg" media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-1536-2048.jpg" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-2048-1536.jpg" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-1668-2224.jpg" media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-2224-1668.jpg" media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-1620-2160.jpg" media="(device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-2160-1620.jpg" media="(device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-1284-2778.jpg" media="(device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-2778-1284.jpg" media="(device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-1170-2532.jpg" media="(device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-2532-1170.jpg" media="(device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-1125-2436.jpg" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-2436-1125.jpg" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-1242-2688.jpg" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-2688-1242.jpg" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-828-1792.jpg" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-1792-828.jpg" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-1242-2208.jpg" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-2208-1242.jpg" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-750-1334.jpg" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-1334-750.jpg" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-640-1136.jpg" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
    <link rel="apple-touch-startup-image" href="icons/apple-splash-1136-640.jpg" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">

    <title>TechSnack | Simple PWA</title>
    <link id="favicon" rel="sortcut icon" href="favicon.ico" type="image/x-icon">
    <link rel="manifest" href="manifest.json">
  </head>
  <body>
    <h1>Hello World!</h1>
  </body>
</html>


최종 manifest.json 


이제 manifest.json 파일이 다음과 같아야 합니다.


    {
      "name": "TechSnack Simple PWA",
      "short_name": "TechSnack",
      "start_url": "/?home=true",
      "icons": [
        {
          "src": "icons/manifest-icon-192.png",
          "sizes": "192x192",
          "type": "image/png",
          "purpose": "maskable any"
        },
        {
          "src": "icons/manifest-icon-512.png",
          "sizes": "512x512",
          "type": "image/png",
          "purpose": "maskable any"
        }
      ],
      "theme_color": "#000000",
      "background_color": "#FFFFFF",
      "display": "fullscreen",
      "orientation": "portrait"
    }


Service Worker 


우리의 PWA가 앞에서 언급한 모든 멋진 일을 하기 전에 먼저 서비스 워커를 만들어야 합니다.


서비스 워커는 브라우저가 백그라운드에서 실행되는 리스너 스크립트입니다. 서비스 워커는 웹 페이지와 별도로 실행되어 웹 페이지나 사용자의 상호 작용이나 호출이 필요하지 않은 기능을 구현할 수 있습니다.

서비스 워커는 향후 주기적 동기화 또는 지오펜싱과 같은 기능을 지원할 수 있습니다.

참고: 서비스 워커는 JavaScript 파일이지만 코딩 시 추가 제한 사항이 있습니다. 서비스 워커를 통해 DOM에 액세스하지 못할 수 있습니다.


서비스 워커의 수명 주기 


일반적으로 서비스 작업자 수명 주기를 중심으로 구축해야 하는 여러 기능/특징이 있습니다. 내부 구성에 대한 걱정을 피하기 위해 workbox라는 API를 사용할 것입니다.


workbox API 


서비스 워커의 경우 workbox라는 API를 사용할 것입니다. 이 API는 자체적으로 설명하기 위해 여러 문서가 필요한 기본 기능을 제공합니다.

핵심적인 내용을 파헤치는 데 관심이 있다면 A Service Workers Lifecycle에 대해 읽을 수 있습니다.


ImportScript


service-worker.js 내부에서 workbox API를 가져올 것입니다.


importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.0.2/workbox-sw.js');


Registering Routes 


서비스 작업자는 페이지에서 네트워크 요청을 가로챌 수 있습니다. 캐시된 콘텐츠 또는 생성된 콘텐츠가 있는 페이지에 응답할 수 있습니다.


Service Worker Routing| JavaScript 

참고: (위에서)


메서드는 기본적으로 GET입니다.

이를 변경하려면 지정해야 합니다.


여러 작업자가 요청을 처리할 수 있는 경우 경로 등록 순서가 중요합니다.

먼저 생성된 작업자가 지정된 요청을 처리하는 데 우선 순위를 가집니다.


service-worker.js 


이제 service-worker.js 내에 다음 코드를 추가할 수 있습니다.


    ...

    workbox.routing.registerRoute(
      ({request}) => request.destination === 'image',
      new workbox.strategies.CacheFirst() //to search cache first
      //new workbox.strategies.NetworkFirst() //to search server first
);


그게 다야! 위의 코드는 다음을 수행합니다.


  • RegisterRoute with workbox
  • Intercept all 'image' files at the page's request

여기에서 우리는 전략을 선택합니다. CacheFirst 또는 NetworkFirst에서 페이지를 제공하시겠습니까? 이것은 우리가 관심 있는 특정 리소스가 정적인지 동적인지에 따라 결정됩니다.


  • 일반적으로 사용자가 방문하는 페이지에 대해 정적이면 캐시에서 제공하려고 합니다.
  • 그러나 어떤 종류의 백엔드에 의해 동적으로 생성되는 경우 네트워크에서 해당 파일을 대부분 가져와야 합니다.

Final service-worker.js 


    importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.0.2/workbox-sw.js');

    workbox.routing.registerRoute(
      ({request}) => request.destination === 'image',
      new workbox.strategies.CacheFirst() //to search cache first
      //new workbox.strategies.NetworkFirst() //to search server first
);


Linking service-worker.js 


이제 서비스 워커가 있고 이미지 파일에 대한 요청을 가로채므로 index.html 내에서 스크립트를 연결할 수 있습니다.


    <body>

      ...

      <script>
        if('serviceWorker' in navigator){
        navigator.serviceWorker.register('/service-worker.js');
      }
      </script>
    </body>


서비스 워커를 등록하는 것은 간단합니다!


함께 모아서 


마침내 PWA 프로젝트의 최종 코드 기반을 살펴볼 수 있습니다.


우리의 파일 구조: 


Progressive Web Application | File Structure 


index.html 


    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta name="theme-color" content="#000000">
        <link rel="apple-touch-icon" href="icons/apple-icon-180.png">

        <meta name="apple-mobile-web-app-capable" content="yes">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-2048-2732.jpg" media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-2732-2048.jpg" media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-1668-2388.jpg" media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-2388-1668.jpg" media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-1536-2048.jpg" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-2048-1536.jpg" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-1668-2224.jpg" media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-2224-1668.jpg" media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-1620-2160.jpg" media="(device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-2160-1620.jpg" media="(device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-1284-2778.jpg" media="(device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-2778-1284.jpg" media="(device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-1170-2532.jpg" media="(device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-2532-1170.jpg" media="(device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-1125-2436.jpg" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-2436-1125.jpg" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-1242-2688.jpg" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-2688-1242.jpg" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-828-1792.jpg" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-1792-828.jpg" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-1242-2208.jpg" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-2208-1242.jpg" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-750-1334.jpg" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-1334-750.jpg" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-640-1136.jpg" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
        <link rel="apple-touch-startup-image" href="icons/apple-splash-1136-640.jpg" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">

        <title>TechSnack | Simple PWA</title>
        <link id="favicon" rel="sortcut icon" href="favicon.ico" type="image/x-icon">
        <link rel="manifest" href="manifest.json">
      </head>
      <body>
        <h1>Hello World!</h1>

        <script>
          if('serviceWorker' in navigator){
            navigator.serviceWorker.register('/service-worker.js');
          }
        </script>
      </body>
    </html>


manifest.json 


    {
      "name": "TechSnack Simple PWA",
      "short_name": "TechSnack",
      "start_url": "/?home=true",
      "icons": [
        {
          "src": "icons/manifest-icon-192.png",
          "sizes": "192x192",
          "type": "image/png",
          "purpose": "maskable any"
        },
        {
          "src": "icons/manifest-icon-512.png",
          "sizes": "512x512",
          "type": "image/png",
          "purpose": "maskable any"
        }
      ],
      "theme_color": "#000000",
      "background_color": "#FFFFFF",
      "display": "fullscreen",
      "orientation": "portrait"
    }


service-worker.js 


    importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.0.2/workbox-sw.js');

    workbox.routing.registerRoute(
      ({request}) => request.destination === 'image',
      new workbox.strategies.CacheFirst() //to search cache first
    );


Serving Our Page 


이제 브라우저에서 페이지를 볼 수 있습니다.


localhost의 경우 webroot 디렉토리에서 npx serve를 실행합니다. 그런 다음 안전하게 제공된 원격 IP 또는 도메인을 방문할 수 있습니다. 장치에 대한 브라우저 지원을 염두에 두십시오.


Progressive Web App In Browser Window 

주소 표시줄에 새로운 아이콘이 생겼습니다!


Progressive Web App | Install User Action Icon 


브라우저에 PWA를 설치하려면 사용자 작업이 필요합니다. 사용자는 이 아이콘을 클릭하여 프롬프트를 볼 수 있습니다.


Progressive Web App | Install User Action Prompt 

이제 장치의 홈페이지에 설치된 아이콘을 클릭할 수 있습니다.


PWA Application Running in Program Browser Window 


PWA 개발 요약 


보시다시피 기본 앱과 동일한 기능을 모방할 수 있는 웹 응용 프로그램을 만드는 것은 매우 쉽습니다. 향후 기사에서는 이 강력한 기술을 통해 현재 액세스할 수 있는 각 기능에 대해 자세히 알아볼 것입니다.


출처 : https://dev.to/techsnack/simple-progressive-web-apps-websites-you-can-install-3k0e


PWA