OS 통합

웹 앱은 도달범위가 넓습니다. 여러 플랫폼에서 실행됩니다. 링크를 통해 쉽게 공유할 수 있습니다. 하지만 기존에는 운영체제와의 통합이 부족했습니다. 얼마 전까지만 해도 설치할 수 없었습니다. 다행히도 이제 이러한 통합을 활용하여 PWA에 유용한 기능을 추가할 수 있습니다. 이러한 옵션을 살펴보겠습니다.

파일 시스템 작업

파일을 사용하는 일반적인 사용자 워크플로는 다음과 같습니다.

  • 기기에서 파일 또는 폴더를 선택하고 바로 엽니다.
  • 이러한 파일 또는 폴더를 변경하고 변경사항을 직접 다시 저장합니다.
  • 새 파일 및 폴더를 만듭니다.

File System Access API가 도입되기 전에는 웹 앱에서 이 작업을 할 수 없었습니다. 파일을 열려면 파일을 업로드해야 했고, 변경사항을 저장하려면 사용자가 파일을 다운로드해야 했으며, 웹에서는 사용자의 파일 시스템에 새 파일과 폴더를 만들 수 없었습니다.

파일 열기

파일을 열려면 window.showOpenFilePicker() 메서드를 사용합니다. 이 메서드에는 버튼 클릭과 같은 사용자 동작이 필요합니다. 파일을 여는 나머지 설정은 다음과 같습니다.

  1. 파일 시스템 액세스의 파일 선택기 API에서 파일 핸들을 캡처합니다. 파일에 관한 기본 정보가 표시됩니다.
  2. 핸들의 getFile() 메서드를 사용하면 파일에 관한 추가 읽기 전용 속성 (예: 이름 및 마지막 수정 날짜)이 포함된 File라는 특수한 종류의 Blob이 반환됩니다. Blob이므로 text()와 같은 Blob 메서드를 호출하여 콘텐츠를 가져올 수 있습니다.
// Have the user select a file.
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();

변경사항 저장 중

파일의 변경사항을 저장하려면 사용자 동작도 필요합니다.

  1. 파일 핸들을 사용하여 FileSystemWritableFileStream를 만듭니다.
  2. 스트림을 변경합니다. 이 경우 파일이 제자리에서 업데이트되지 않고 일반적으로 임시 파일이 생성됩니다.
  3. 마지막으로 변경을 완료하면 스트림을 닫아 변경사항이 임시에서 영구로 이동합니다.

코드를 살펴보겠습니다.

// Make a writable stream from the handle.
const writable = await handle.createWritable();
// Write the contents of the file to the stream.
await writable.write(contents);
// Close the file and write the contents to disk.
await writable.close();

파일 처리

File System Access API를 사용하면 앱 내에서 파일을 열 수 있지만 그 반대의 경우는 어떻게 될까요? 사용자는 파일을 열 때 즐겨 사용하는 앱을 기본값으로 설정하려고 합니다. 파일 처리 API는 설치된 PWA가 다음 작업을 할 수 있도록 지원하는 실험적 API입니다. 웹 앱 매니페스트에서 PWA가 지원하는 MIME 유형과 파일 확장자를 지정하여 사용자 기기에 파일 핸들러로 등록 지원되는 확장 프로그램의 맞춤 파일 아이콘을 지정할 수 있습니다.

등록되면 설치된 PWA가 사용자의 파일 시스템에 옵션으로 표시되어 사용자가 파일을 직접 열 수 있습니다. 다음은 텍스트 파일을 읽는 PWA의 매니페스트 설정의 예입니다.

...
"file_handlers": [
     {
         "action": "/open-file",
         "accept": {
             "text/*": [".txt"]
         }
     }
]
...

URL 처리

URL 처리를 사용하면 PWA가 운영체제에서 범위에 속하는 링크를 캡처하고 기본 브라우저 탭 대신 PWA 창 내에서 렌더링할 수 있습니다. 예를 들어 PWA로 연결되는 메시지를 받거나 PWA에서 딥 링크 (특정 콘텐츠를 가리키는 URL)를 클릭하면 콘텐츠가 독립형 창에서 열립니다.

이 동작은 사용자가 Chrome으로 PWA를 설치하는 등 WebAPK를 사용하는 경우 Android에서 자동으로 사용할 수 있습니다. Safari에서 iOS 및 iPadOS에 설치된 PWA에서는 URL을 캡처할 수 없습니다.

데스크톱 브라우저의 경우 웹브라우저 커뮤니티에서 새로운 사양을 만들었습니다. 이 사양은 현재 실험적이며 새로운 매니페스트 파일 멤버인 url_handlers를 추가합니다. 이 속성은 PWA가 캡처하려는 원본의 배열을 예상합니다. PWA의 출처에는 자동으로 권한이 부여되며 다른 각 출처는 web-app-origin-association라는 파일을 통해 작동하는 처리를 수락해야 합니다. 예를 들어 PWA의 매니페스트가 web.dev에 호스팅되어 있고 app.web.dev 출처를 추가하려면 다음과 같이 표시됩니다.

"url_handlers": [
    {"origin": "https://app.web.dev"},
]

이 경우 브라우저는 app.web.dev/.well-known/web-app-origin-association에 파일이 있는지 확인하고 PWA 범위 URL에서 URL 처리를 수락합니다. 개발자가 이 파일을 만들어야 합니다. 다음 예에서 파일은 다음과 같습니다.

{
    "web_apps": [
        {
            "manifest": "/mypwa/app.webmanifest",
            "details": {
                "paths": [ "/*" ]
            }
        }
    ]
}

URL 프로토콜 처리

URL 처리는 표준 https 프로토콜 URL과 함께 작동하지만 pwa://과 같은 맞춤 URI 스키마를 사용할 수 있습니다. 여러 운영체제에서 설치된 앱은 앱이 스키마를 등록하여 이 기능을 획득합니다.

PWA의 경우 이 기능은 데스크톱 기기에서만 사용할 수 있는 URL 프로토콜 핸들러 API를 사용하여 사용 설정됩니다. 앱 스토어에 PWA를 배포하여 휴대기기용 맞춤 프로토콜만 허용할 수 있습니다.

등록하려면 registerProtocolHandler() 메서드를 사용하거나 매니페스트에서 protocol_handlers 멤버를 원하는 스킴과 PWA의 컨텍스트에서 로드할 URL과 함께 사용합니다.

...
{
  "protocol_handlers": [
    {
      "protocol": "web+pwa",
      "url": "/from-protocol?value=%s"
    },
  ]
}
...

URL from-protocol를 올바른 핸들러로 라우팅하고 PWA에서 쿼리 문자열 value를 가져올 수 있습니다. %s는 작업을 트리거한 이스케이프된 URL의 자리표시자이므로 <a href="web+pwa://testing">과 같은 링크가 있으면 PWA가 /from-protocol?value=testing를 엽니다.

다른 앱 호출

URI 스키마를 사용하면 모든 플랫폼에서 사용자의 기기에 설치된 다른 앱 (PWA 여부와 관계없음)에 연결할 수 있습니다. 링크를 만들거나 navigator.href를 사용하여 원하는 URI 스킴을 가리키고 URL로 이스케이프된 형식으로 인수를 전달하면 됩니다.

전화 통화에는 tel:, 이메일 전송에는 mailto:, 문자 메시지에는 sms:와 같은 잘 알려진 표준 스키마를 사용하거나 잘 알려진 메시지, 지도, 탐색, 온라인 회의, 소셜 네트워크, 앱 스토어에서 다른 앱의 URL 스키마를 알아볼 수 있습니다.

Web Share

Browser Support

  • Chrome: 128.
  • Edge: 93.
  • Firefox: behind a flag.
  • Safari: 12.1.

Source

Web Share API를 사용하면 PWA가 공유 채널을 통해 기기에 설치된 다른 앱에 콘텐츠를 전송할 수 있습니다.

이 API는 Android, iOS, iPadOS, Windows, ChromeOS 등 share 메커니즘이 있는 운영체제에서만 사용할 수 있습니다. 다음이 포함된 객체를 공유할 수 있습니다.

  • 텍스트 (titletext 속성)
  • URL (url 속성)
  • 파일 (files 속성)

현재 기기에서 공유할 수 있는지 확인하려면 텍스트와 같은 간단한 데이터의 경우 navigator.share() 메서드가 있는지 확인하고, 파일을 공유하려면 navigator.canShare() 메서드가 있는지 확인합니다.

navigator.share(objectToShare)를 호출하여 공유 작업을 요청합니다. 이 호출은 undefined로 확인되거나 예외로 거부되는 프로미스를 반환합니다.

Web Share 덕분에 공유 시트를 여는 Android의 Chrome과 iOS의 Safari

Web Share Target

Web Share Target API를 사용하면 PWA가 PWA인지 여부와 관계없이 기기의 다른 앱에서 공유 작업의 타겟이 될 수 있습니다. PWA가 다른 앱에서 공유한 데이터를 수신합니다.

현재 Android(WebAPK 사용) 및 ChromeOS에서 사용할 수 있으며, 사용자가 PWA를 설치한 후에만 작동합니다. 앱이 설치되면 브라우저가 운영체제 내에 공유 타겟을 등록합니다.

Web Share Target 초안 사양에 정의된 share_target 멤버를 사용하여 매니페스트에서 웹 공유 타겟을 설정합니다. share_target는 다음과 같은 속성이 있는 객체로 설정됩니다.

action
공유된 데이터를 수신할 것으로 예상되는 PWA 창에 로드될 URL입니다.
method
HTTP 동사 메서드가 작업에 사용됩니다(예: GET, POST, PUT).
enctype
(선택사항) 매개변수의 인코딩 유형입니다. 기본값은 application/x-www-form-urlencoded이지만 POST과 같은 메서드의 경우 multipart/form-data로 설정할 수도 있습니다.
params
선택한 인코딩을 사용하여 브라우저가 URL (method: 'GET') 또는 요청 본문에 전달할 인수에 공유 데이터 (웹 공유의 키: title, text, url, files)를 매핑할 객체입니다.

예를 들어 매니페스트에 다음을 추가하여 공유된 데이터 (제목 및 URL만)를 수신하도록 PWA를 정의할 수 있습니다.

...
"share_target": {
   "action": "/receive-share/",
   "method": "GET",
   "params": {
      "title": "shared_title",
      "url": "shared_url"
   }
}
...

이전 샘플에서 시스템의 앱이 제목과 함께 URL을 공유하고 사용자가 대화상자에서 PWA를 선택하면 브라우저가 원본의 /receive-share/?shared_title=AAA&shared_url=BBB에 대한 새 탐색을 만듭니다. 여기서 AAA는 공유된 제목이고 BBB는 공유된 URL입니다. JavaScript를 사용하여 URL 생성자로 파싱하여 window.location 문자열에서 해당 데이터를 읽을 수 있습니다.

브라우저는 매니페스트의 PWA 이름과 아이콘을 사용하여 운영체제의 공유 항목을 제공합니다. 이 용도로 다른 세트를 선택할 수는 없습니다.

자세한 예시와 파일을 수신하는 방법은 Web Share Target API로 공유 데이터 수신하기를 참고하세요.

연락처 선택도구

Browser Support

  • Chrome: not supported.
  • Edge: not supported.
  • Firefox: not supported.
  • Safari: not supported.

Source

연락처 선택기 API를 사용하면 사용자가 하나 이상의 연락처를 선택할 수 있도록 기기에서 모든 사용자의 연락처가 포함된 네이티브 대화상자를 렌더링하도록 요청할 수 있습니다. 그러면 PWA가 해당 연락처에서 원하는 데이터를 수신할 수 있습니다.

연락처 선택기 API는 주로 휴대기기에서 사용할 수 있으며, 호환되는 플랫폼에서 navigator.contacts 인터페이스를 통해 모든 작업이 이루어집니다.

navigator.contacts.getProperties()를 사용하여 쿼리할 수 있는 속성을 요청하고 원하는 속성 목록으로 단일 또는 다중 연락처 선택을 요청할 수 있습니다.

샘플 속성으로는 name, email, address, tel 등이 있습니다. 사용자에게 하나 이상의 연락처를 선택하도록 요청할 때 navigator.contacts.select(properties)를 호출하여 반환받을 속성 배열을 전달할 수 있습니다.

다음 샘플은 선택기에서 수신한 연락처를 나열합니다.

async function getContacts() {
   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.
   }
}

리소스