안녕하세요. IT 엘도라도 에 오신 것을 환영합니다.
글을 쓰는 것은 귀찮지만 다시 찾아보는 것은 더 귀찮습니다.
완전한 나만의 것으로 만들기 위해 지식을 차곡차곡 저장해 보아요.   포스팅 둘러보기 ▼

웹, 앱 (Web, Application)

[App] PWA (Progressive Web Apps) 개념 및 구현 (feat. WWDC22)

피그브라더 2022. 10. 22. 00:01

1. PWA (Progressive Web Apps)

PWA는 웹사이트를 모바일 앱처럼 활용할 수 있도록 하는 기술이다. 즉, 모바일 앱처럼 홈 화면에 아이콘을 추가하여 간편하게 접근할 수 있고 JavaScript로 푸시 알림이나 오프라인 동작과 같은 기능도 구현할 수 있으며 UI도 브라우저 주소 창 없이 모바일 앱처럼 보이게 할 수 있는 웹사이트를 말한다. 또한, 어쨌든 웹사이트이기 때문에 설치 없이 URL만으로 접근할 수 있고 플레이 스토어나 앱 스토어의 심사가 필요 없다는 장점도 그대로 지닌다. 결국 웹사이트와 모바일 앱의 장점을 합친 것이라 볼 수 있다.

 

물론 아직까지는 Android 또는 iOS 자체에 제공하는 깊숙한 기능들까지 전부 다 그대로 구현하지는 못하는 것이 사실이다. 그러나 지금까지 JavaScript가 발전한 속도를 고려해보면, 일반적인 모바일 앱에서 필요로 하는 기능까지 지원되는 건 먼 미래가 아닐 듯싶다.

그밖에 다양한 종류의 모바일 앱(네이티브 앱, 모바일 웹 (앱), 하이브리드 앱, 크로스-플랫폼 앱)의 개념에 대해 알아보고 싶다면 이 포스팅의 내용을 참고하기 바란다.

 

2. PWA에 대한 지원 (Android, iOS)

위에서 설명한 바와 같이 PWA는 웹사이트를 모바일 앱처럼 사용할 수 있게 한다는 강력한 장점을 지니는데, 실제로 게임을 제외한 많은 종류의 모바일 앱은 굳이 모바일 앱이 아닌 PWA로 구현해도 괜찮은 경우가 많다. 구글은 이러한 사실을 일찍부터 인식하여 PWA를 강력하게 지원했고, 그 결과 Android 기기에서는 PWA가 아주 잘 동작한다.

 

하지만 iOS 기기에서는 PWA가 잘 동작하지 않는다. 왜냐하면 애플은 상당량의 수익을 앱 스토어에서 개발자들에게 부과하는 수수료로부터 얻고 있는데, PWA를 강력하게 지원하면 모바일 앱보다 PWA의 개발이 인기를 얻으면서 수익이 줄어들 가능성이 있어서일 것이다. 그래서 iOS의 제어를 받는 여러 브라우저(EX. Safari)에서는 PWA가 제대로 동작하지 않았다. 예를 들어, 모바일 앱의 근본이라고 할 수 있는 푸시 알림 기능은 iOS 기반의 브라우저에서 구현하는 데 제한이 있었다.

 

 

하지만 올해(2022년) 6월에 개최된 애플의 WWDC(Worldwide Developers Conference, 세계 개발자 컨퍼런스)에 따르면, 마침내 애플도 이제 PWA를 지원하는 API를 개발할 것이라 발표했다. 정확한 시기는 예측할 수 없지만, 2023년 이후로 개발될 것으로 보고 있다. 따라서 앞으로 웹 개발자들이 PWA를 공부하는 것은 거의 필수가 되지 않을까 감히 추측해본다. 필자도 그런 맥락에서 이론으로만 알고 있던 PWA를 실제로 구현해보았고, 이 글을 통해 그 구현 과정에 대해 기술해보려 한다. PWA를 구현해보고 싶은 많은 사람에게 도움이 되길 바란다.

 

3. PWA 구현하기 - ① 이미지 준비

그러면 이제 본격적으로 PWA의 구현 절차를 알아보자. 우선, 가장 먼저 해야 할 작업은 PWA의 구현을 위해 필요한 이미지들부터 준비하는 것이다. 두 종류의 이미지가 필요한데, 하나는 아이콘이고 다른 하나는 스크린샷이다.

 

3-1. 아이콘 이미지 준비

먼저, 홈 화면에 추가할 때 보이는 아이콘을 위한 이미지들을 준비하자. 이를 위해 Maskable.app 웹사이트에 접속하자. 이는 아이콘으로 사용할 이미지들을 간편하게 생성할 수 있도록 도와주는 서비스이다. 해당 웹사이트에 접속한 뒤, [Editor] 탭을 선택하고 우측의 [Upload] 버튼을 클릭하여 아이콘으로 사용할 이미지를 선택하자. (웬만하면 512x512 이상의 정사각 이미지를 권장한다.)

 

 

이미지를 업로드하고 나면 우측 영역에 있는 여러 편집 도구를 이용하여 이미지를 편집할 수 있다. [Masks] 부분에서 여러 모양을 선택해 보면서 각 모양에서 현재 편집된 이미지가 어떻게 보이는지 확인해보자. 편집이 끝나면 [Export] 버튼을 클릭하여 아이콘으로 사용할 이미지들을 다운로드하자. 아래와 같이 모든 사이즈를 선택하여 사이즈별로 아이콘 이미지를 다운로드하자.

 

 

이후 다운로드한 아이콘 이미지들을 프로젝트 폴더로 옮기자. 어떤 폴더에 둬야 하는지 정해진 규칙은 없지만, 뒤에서 manifest.json 파일을 작성할 때 해당 아이콘 이미지들의 경로를 작성해야 하므로 어딘지는 기억해두도록 하자.

 

3-2. 스크린샷 이미지 준비

다음으로, PWA 스토어에서 해당 PWA를 설명하기 위해 사용할 스크린샷 이미지들을 준비해야 한다. 개인적으로 조사해봤을 때 굳이 권장되는 이미지의 비율은 딱히 없었기에, 대략적으로 PC와 모바일 사이즈 각각에 대해 본인의 웹사이트에서 중요하다고 생각되는 페이지들을 캡처하여 이미지들을 준비하면 된다.

 

이후 그 이미지들을 앞에서와 마찬가지로 프로젝트 폴더로 옮기자. 이것 역시 어떤 폴더에 둬야 하는지 정해진 규칙은 없지만, 뒤에서 manifest.json 파일을 작성할 때 해당 스크린샷 이미지들의 경로를 작성해야 하므로 어딘지는 기억해두도록 하자.

참고로, 크롬의 경우 개발자 도구(F12)에서 [Ctrl+Shift+P]를 입력하면 [실행] 패널이 뜨는데, 여기서 [원본 크기 스크린샷 캡처]를 선택하면 현재 페이지의 전체 스크린샷을 찍을 수 있다. 그밖에 더 편한 방법이 있다면 그것을 사용해도 된다.

 

4. PWA 구현하기 - ② Manifest

이미지들의 준비를 마쳤으면, 본격적으로 PWA를 구현하기 위해 필요한 파일들을 작성해보자. 그 첫 번째는 바로 manifest.json 파일이다. 이는 해당 PWA가 기기에 설치되었을 때 어떻게 동작해야 하는지에 대한 정보를 알려주는 역할을 수행한다. 구체적으로 어떤 정보들이 이곳에 명시되는지는 아래의 코드를 참고하자.

 

자신이 원하는 어떤 URL(/manifest.json이라 가정)로 접근할 수 있도록 하는 폴더에 manifest.json 파일을 만들고 대략 다음과 같은 내용을 작성하자. 단, 본인의 상황에 맞춰서 각 프로퍼티의 값을 적절히 수정해주자. 각 프로퍼티에 대한 자세한 설명은 MDN 문서에서 확인하면 되고, 개인적으로 필요 없다고 생각하는 선택적인 프로퍼티는 지워도 된다.

{
  "name": "PWA 이름",
  "short_name": "PWA 짧은 이름",
  "description": "PWA 설명",
  "background_color": "#FFFFFF",
  "theme_color": "#FFFFFF",
  "start_url": "/",
  "scope": "/",
  "shortcuts": [
    {
      "name": "중요한 페이지1 이름",
      "short_name": "중요한 페이지1 짧은 이름",
      "url": "/page1",
      "description": "중요한 페이지1 설명",
      "icons": [
        {
          "src": "icon/maskable_icon_x96.png",
          "sizes": "96x96",
          "type": "image/png"
        }
      ]
    },
    {
      "name": "중요한 페이지2 이름",
      "short_name": "중요한 페이지2 짧은 이름",
      "url": "/page2",
      "description": "중요한 페이지2 설명",
      "icons": [
        {
          "src": "icon/maskable_icon_x96.png",
          "sizes": "96x96",
          "type": "image/png"
        }
      ]
    },
    ...
  ],
  "orientation": "any",
  "display": "standalone",
  "categories": ["entertainment", ...],
  "icons": [
    {
      "src": "icon/maskable_icon_x48.png",
      "sizes": "48x48",
      "type": "image/png"
    },
    {
      "src": "icon/maskable_icon_x72.png",
      "sizes": "72x72",
      "type": "image/png"
    },
    {
      "src": "icon/maskable_icon_x96.png",
      "sizes": "96x96",
      "type": "image/png"
    },
    {
      "src": "icon/maskable_icon_x128.png",
      "sizes": "128x128",
      "type": "image/png"
    },
    {
      "src": "icon/maskable_icon_x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "icon/maskable_icon_x384.png",
      "sizes": "384x384",
      "type": "image/png"
    },
    {
      "src": "icon/maskable_icon_x512.png",
      "sizes": "512x512",
      "type": "image/png"
    },
    {
      "src": "icon/maskable_icon_x512.png",
      "sizes": "any",
      "type": "image/png"
    }
  ],
  "screenshots": [
    {
      "src": "screenshot/pc.png",
      "sizes": "1920x1280",
      "type": "image/png",
      "platform": "wide",
      "label": "Main Page (PC)"
    },
    {
      "src": "screenshot/mobile.png",
      "sizes": "720x2048",
      "type": "image/png",
      "platform": "narrow",
      "label": "Main Page (Mobile)"
    }
  ],
  "lang": "ko"
}
각 프로퍼티에 대한 설명을 일일이 다 하면 너무 길어질 것 같아 MDN 문서로 설명을 대체하였는데, 그중에서도 필자가 주의해야 한다고 생각하는 부분은 바로 이미지 파일의 경로이다. icons, screenshots 프로퍼티에서 이미지 파일의 경로를 적을 때 위와 같이 상대 경로로 적는 경우, 기준 경로가 manifest.json 파일이 위치한 경로라는 것에 주의하도록 하자.

 

manifest.json 파일의 작성을 마치고 나면, <link rel="manifest" href="/manifest.json" /> 태그를 <head> 태그 안에 작성해주도록 하자. 여기까지 하고 나면 manifest.json 파일의 준비는 끝이다.

여기서 href 어트리뷰트의 값에는 해당 manifest.json 파일에 접근하기 위한 URL에 기반하여 적어주면 되고, 해당 태그를 작성해주는 위치는 프로젝트가 어떤 프레임워크 기반이냐에 따라 다르다. 모든 경우를 설명할 수는 없으니 이건 자신의 상황에 따라 적절히 판단해주기 바란다.

 

이제 PWABuilder에 접속하고 본인 웹사이트의 URL을 입력하여 PWA 적합성을 검사해보도록 하자. (이를 위해서는 먼저 HTTPS가 설정된 외부 URL로 배포가 되어 있는 상태여야 하는데, 만약 아직 로컬 개발 단계라면 ngrok을 활용해보도록 하자. 이에 대한 설명은 생략.) 그러면 Manifest, Service Worker, Security 세 가지의 측면에서 검사가 이뤄지는데, 지금까지 잘 따라왔다면 Manifest는 (100점은 아니겠지만) PWA 조건이 충족되어 있을 것이고, Security는 100점일 것이다.

 

아래 그림에서 볼 수 있듯이, 필자의 경우 뒤에서 진행할 Service Worker 설정도 이미 마쳤기 때문에 Service Worker도 PWA 조건이 충족된 걸로 나오는데, 아마 이 과정을 따라오고 있는 여러분은 Service Worker 설정이 아예 안 되어 있다고 뜰 것이다. (참고로 Manifest의 경우 any 사이즈의 아이콘 이미지를 등록하지 않았다는 이유로 현재 워닝을 띄우고 있는데, 실제로는 등록이 잘 되어 있다. 그런데 왜 워닝이 뜨는지는 아직 모르겠다.)

 

 

그럼 이제 프로젝트에 Service Worker 파일을 작성할 차례이다. [Generate Service Worker] 버튼을 클릭하여 Service Worker 파일을 다운로드할 수 있는 창을 띄우고 다음 섹션의 설명을 이어서 읽자.

 

5. PWA 구현하기 - ③ Service Worker

아래 그림과 같이 [Offline Pages] 탭이 선택되어 있는 상태에서, 아래의 [Download Service Worker] 버튼을 클릭하여 Service Worker 파일을 프로젝트 폴더에 다운로드하자. 웬만하면 manifest.json 파일과 같은 경로에 두는 것이 좋은데, 아래에서 Service Worker 파일을 등록할 때 해당 파일에 접근하기 위한 URL을 알아야 하므로 이건 기억해두도록 하자.

 

간단하게 얘기하자면, Service Worker 파일은 푸시 알림이나 오프라인에서의 동작과 같은 기능을 지원하는 역할을 수행한다. 자세한 역할에 대해서는 직접 한 번 찾아보기 바란다.

 

그리고 [Register your Service Worker] 링크를 클릭하면 방금 다운로드한 Service Worker 파일을 프로젝트에 등록하는 방법이 나올 것이다. 이 글을 작성하는 2022.10.22 기준으로는 대략 다음과 같은 <script> 태그를 <body> 태그에 추가하도록 안내되어 있다. 그대로 따라 하면 되는데, /service-worker.js 부분은 아까 다운로드한 파일에 접근하기 위한 URL에 기반하여 적어주면 된다.

<script>
  if (typeof navigator.serviceWorker !== 'undefined') {
    navigator.serviceWorker.register('/service-worker.js');
  }
</script>

마지막으로, Service Worker 파일을 열어보면 TODO로 표시되어 있는 부분이 있을 것이다. 그건 네트워크 연결이 끊긴 오프라인 상황에서 대신 보여줄 페이지의 HTML 파일 경로를 지정하는 부분이다. 원하는 이름으로(EX. offline.html) 대략 다음과 같은(혹은 더 예쁜) HTML 파일을 작성하고, 그 파일의 경로로 TODO 부분을 수정하면 된다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>인터넷 연결이 끊김</title>
  </head>
  <body>
    <p>인터넷 연결이 끊겨 있습니다. 네트워크 상태를 확인해주세요.</p>
  </body>
</html>
해당 HTML 파일의 경로를 명시할 때도 상대 경로(EX. offline.html)로 적는다면 그 기준 경로가 Service Worker 파일이 위치한 경로라는 것에 주의하도록 하자.

 

여기까지 하고 나면 Service Worker 파일의 준비도 끝이다. 이제 아까 방문했던 PWABuilder에 다시 접속하여 PWA 적합성을 검사해보면, Service Worker도 PWA 조건이 충족되었음을 확인할 수 있을 것이다.

 

PWA 구현은 여기까지가 끝이다. 이제 모바일로 해당 웹사이트에 접속한 뒤, 메뉴 바에 있는 [앱 설치]를 진행하여 홈 화면에 아이콘을 추가해보자. 이제 해당 아이콘은 마치 모바일 앱처럼 기능하게 될 것이다.

 

6. PWA 구현하기 - ④ 스토어에 패키지 등록하기 (선택)

PWABuilder에 본인 웹사이트의 URL을 입력하면 다음과 같이 PWA 스토어에 패키지를 업로드하기 위한 기능을 볼 수 있을 것이다. 여기서 [Package for stores] 버튼을 클릭하면 각 환경별로 패키지를 만들어서 PWA 스토어에 업로드할 수 있는 기능이 제공된다.

 

 

다만, 필자의 경우 단순히 웹사이트에 접속하여 [앱 설치]를 하는 방식으로 홈 화면에 아이콘을 추가해서 사용하면 그만이기 때문에 굳이 이 과정까지 진행하지는 않았다. 필요한 사람은 한 번 진행해보기 바란다.