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에서 자동으로 제공됩니다. iOS 및 iPadOS에 설치된 PWA의 URL은 Safari에서 캡처할 수 없습니다.

데스크톱 브라우저의 경우 웹브라우저 커뮤니티에서 새 사양을 만들었습니다. 이 사양은 현재 실험용이며 새 매니페스트 파일 멤버 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 스키마를 알아볼 수 있습니다.

웹 공유

Browser Support

  • Chrome: 89.
  • 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로 확인되거나 예외와 함께 거부되는 Promise를 반환합니다.

웹 공유 덕분에 Android의 Chrome과 iOS의 Safari에서 공유 시트를 여는 모습.

웹 공유 타겟

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

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

웹 공유 타겟 초안 사양에 정의된 share_target 구성원으로 매니페스트에서 웹 공유 타겟을 설정합니다. share_target는 다음과 같은 속성이 있는 객체로 설정됩니다.

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

예를 들어 매니페스트에 다음을 추가하여 공유 데이터 (제목 및 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

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

Contact Picker 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.
   }
}

리소스