PWA를 앱처럼 구현

프로그레시브 웹 앱을 웹사이트가 아닌 '실제' 앱처럼 만듭니다.

프로그레시브 웹 앱 유행어 빙고를 플레이할 때 'PWA는 그냥 웹사이트입니다'로 설정하는 것이 안전합니다. Microsoft의 PWA 문서도 동의하고 바로 이 사이트에서 발표하며 PWA 후보인 프랜시스 베리만과 알렉스 러셀도 그렇습니다. 예, PWA는 웹사이트일 뿐이지만 그 이상입니다. 제대로 만든다면 PWA가 웹사이트처럼 느껴지지 않고 '실제' 앱처럼 느껴질 것입니다. 그렇다면 PWA가 실제 앱처럼 느껴진다는 것은 어떤 의미일까요?

이 질문에 답하기 위해 Apple Podcasts 앱을 예로 들어보겠습니다. 데스크톱의 macOS와 모바일의 iOS (및 iPadOS)에서 각각 사용할 수 있습니다. 팟캐스트는 미디어 애플리케이션이지만, 제가 설명하는 핵심 아이디어는 다른 카테고리의 앱에도 적용됩니다.

팟캐스트 애플리케이션을 실행 중인 iPhone과 MacBook이 나란히 놓여 있습니다.
iPhone 및 macOS용 Apple 팟캐스트 (출처)

오프라인 실행 가능

한 걸음 물러서서 휴대폰이나 데스크톱 컴퓨터에 설치된 플랫폼별 애플리케이션을 생각해보면, 한 가지 명백한 것이 눈에 띕니다. 바로 아무것도 얻는 것이 없다는 것입니다. 팟캐스트 앱에는 오프라인일 때도 항상 뭔가가 있습니다. 네트워크에 연결되어 있지 않아도 앱이 자연스럽게 열립니다. 인기 차트 섹션에는 콘텐츠가 표시되지 않고 대신 다시 시도 버튼과 페어링된 지금은 연결할 수 없음 메시지가 표시됩니다. 가장 반가운 경험이 아닐 수도 있지만 저는 무언가가 있습니다.

네트워크에 연결할 수 없을 때 팟캐스트 앱에 '지금은 연결할 수 없습니다' 정보 메시지가 표시됩니다.
네트워크에 연결되지 않은 팟캐스트 앱

팟캐스트 앱은 소위 앱 셸 모델을 따릅니다. 왼쪽 메뉴 아이콘 및 핵심 플레이어 UI 아이콘과 같은 장식 이미지를 포함하여 핵심 앱을 표시하는 데 필요한 모든 정적 콘텐츠는 로컬에 캐시됩니다. 인기 차트 데이터와 같은 동적 콘텐츠는 요청 시에만 로드되며 로드에 실패할 경우 로컬에 캐시된 대체 콘텐츠를 사용할 수 있습니다. 이 아키텍처 모델을 웹 앱에 적용하는 방법을 알아보려면 앱 셸 모델 문서를 읽어보세요.

오프라인 콘텐츠 사용 가능 및 미디어 재생 가능

오프라인 상태에서도 왼쪽 창을 통해 오프라인 저장됨 섹션으로 이동하여 재생할 준비가 되고 아트워크 및 설명과 같은 모든 메타데이터와 함께 표시되는 다운로드된 팟캐스트 에피소드를 즐길 수 있습니다.

재생 중인 팟캐스트 에피소드가 다운로드된 팟캐스트 앱
다운로드한 팟캐스트 에피소드는 네트워크 연결 없이도 재생할 수 있습니다.

예를 들어 Workbox 라이브러리의 캐시된 오디오 및 동영상 제공 레시피를 사용하여 이전에 다운로드한 미디어 콘텐츠를 캐시에서 제공할 수 있습니다. 다른 콘텐츠는 항상 캐시 또는 IndexedDB에 저장할 수 있습니다. 자세한 내용과 언제 어떤 스토리지 기술을 사용해야 하는지 알아보려면 웹용 스토리지 문서를 참고하세요. 사용 가능한 메모리 양이 부족해질 때 영구 삭제될 위험 없이 데이터를 영구 저장해야 하는 경우 Persistent Storage API를 사용할 수 있습니다.

선제적 백그라운드 다운로드

다시 온라인 상태가 되면 http 203와 같은 쿼리로 콘텐츠를 검색할 수 있습니다. 검색결과를 구독하기로 결정하면 시리즈의 최신 에피소드인 HTTP 203 팟캐스트가 즉시 다운로드되며 어떠한 질문도 하지 않습니다.

구독 직후 팟캐스트의 최신 에피소드를 다운로드하는 팟캐스트 앱
팟캐스트를 구독하면 최신 에피소드가 즉시 다운로드됩니다.

팟캐스트 에피소드를 다운로드하는 작업은 시간이 더 오래 걸릴 수 있는 작업입니다. Background Fetch API를 사용하면 브라우저에 다운로드를 위임할 수 있으며, 이 경우 백그라운드에서 다운로드가 처리됩니다. Android에서는 브라우저가 이러한 다운로드 항목을 운영체제에 위임할 수도 있으므로 브라우저를 계속 실행할 필요가 없습니다. 다운로드가 완료되면 앱의 서비스 워커가 활성화되어 응답을 어떻게 처리할지 결정할 수 있습니다.

다른 애플리케이션과 공유 및 상호작용

팟캐스트 앱은 다른 애플리케이션과 자연스럽게 통합됩니다. 예를 들어 좋아하는 에피소드를 마우스 오른쪽 버튼으로 클릭하면 메시지 앱과 같은 기기의 다른 앱에 공유할 수 있습니다. 또한 시스템 클립보드와 자연스럽게 통합됩니다. 에피소드를 마우스 오른쪽 버튼으로 클릭하고 링크를 복사하겠습니다.

'에피소드 공유 → 메시지' 옵션이 선택된 팟캐스트 에피소드에서 호출된 팟캐스트 앱의 컨텍스트 메뉴
메시지 앱에 팟캐스트 에피소드 공유

Web Share APIWeb Share Target API를 사용하면 앱에서 기기의 다른 애플리케이션과 텍스트, 파일, 링크를 공유하고 수신할 수 있습니다. 아직 웹 앱이 운영체제의 내장된 마우스 오른쪽 버튼 클릭 메뉴에 메뉴 항목을 추가할 수 없지만, 기기의 다른 앱에 연결하거나 이러한 앱 간에 연결할 수 있는 다른 방법이 많이 있습니다. Async Clipboard API를 사용하면 시스템 클립보드에 텍스트 및 이미지 데이터 (PNG 이미지)를 프로그래매틱 방식으로 읽고 쓸 수 있습니다. Android에서는 Contact Picker API를 사용하여 기기의 연락처 관리자에서 항목을 선택할 수 있습니다. 플랫폼별 앱과 PWA를 모두 제공하는 경우 Get Installed Related Apps API를 사용하여 플랫폼별 앱이 설치되어 있는지 확인할 수 있습니다. 이 경우 사용자에게 PWA를 설치하거나 웹 푸시 알림을 수락하도록 유도할 필요가 없습니다.

백그라운드 앱 새로고침 중

팟캐스트 앱 설정에서 새 에피소드를 자동으로 다운로드하도록 앱을 구성할 수 있습니다. 신경 쓰지 않아도 됩니다. 업데이트된 콘텐츠는 언제나 그대로 유지됩니다. 매직이죠.

'일반' 섹션에 있는 팟캐스트 앱의 설정 메뉴. 여기에서 '팟캐스트 새로고침' 옵션이 '매시간'으로 설정되어 있습니다.
매시간 새 팟캐스트 에피소드를 확인하도록 구성된 팟캐스트입니다.

Periodic Background Sync API를 사용하면 앱이 실행되지 않아도 백그라운드에서 정기적으로 콘텐츠를 새로고침할 수 있습니다. 즉, 새로운 콘텐츠를 적극적으로 사용할 수 있기 때문에 사용자가 원할 때마다 바로 콘텐츠를 살펴볼 수 있습니다.

클라우드를 통해 동기화된 상태

동시에 내 구독은 내가 소유한 모든 기기에서 동기화됩니다. 원활한 세상에서는 팟캐스트 구독 정보를 수동으로 동기화하느냐에 대해 걱정할 필요가 없습니다. 마찬가지로 데스크톱에서 이미 들은 에피소드가 휴대기기의 메모리를 차지할까 봐 두려워할 필요가 없습니다. 재생 상태는 동기화된 상태로 유지되며 청취한 에피소드는 자동으로 삭제됩니다.

'고급' 섹션에 있는 '기기 간 구독 동기화' 옵션이 활성화된 팟캐스트 앱 설정 메뉴
클라우드를 통해 상태가 동기화됩니다.

앱 상태 데이터 동기화는 Background Sync API에 위임할 수 있는 작업입니다. 동기화 작업 자체는 즉시 발생하지 않아도 되며 결과적으로 발생하며, 사용자가 이미 앱을 다시 닫은 경우에도 발생할 수 있습니다.

하드웨어 미디어 키 컨트롤

Chrome 브라우저에서 뉴스 페이지를 읽는 등 다른 애플리케이션을 사용할 때도 노트북의 미디어 키로 팟캐스트 앱을 제어할 수 있습니다. 앞으로 또는 뒤로 건너뛰기 위해 앱으로 전환할 필요는 없습니다.

주석이 달린 미디어 키가 있는 Apple MacBook Pro 매직 키보드
미디어 키를 사용하여 팟캐스트 앱을 제어할 수 있습니다 (출처).

미디어 키는 Media Session API에서 지원됩니다. 이와 같이 사용자는 물리적 키보드나 헤드폰의 하드웨어 미디어 키를 활용하거나 스마트시계의 소프트웨어 미디어 키로 웹 앱을 제어할 수도 있습니다. 원활한 탐색 작업을 위한 또 다른 아이디어는 사용자가 콘텐츠의 상당 부분을 탐색할 때(예: 시작 크레딧 또는 챕터 경계를 전달) 진동 패턴을 전송하는 것입니다.

멀티태스킹 및 앱 바로가기

물론 언제 어디서나 팟캐스트 앱으로 다시 멀티태스킹할 수 있습니다. 앱에 명확하게 구분되는 아이콘이 있어서 원하는 경우 팟캐스트를 바로 실행할 수 있도록 데스크톱이나 애플리케이션 도크에 배치할 수도 있습니다.

macOS 작업 전환기에 여러 앱 아이콘 중 하나를 선택할 수 있으며 이 중 하나는 팟캐스트 앱입니다.
팟캐스트 앱으로 다시 멀티태스킹하기

데스크톱과 모바일의 프로그레시브 웹 앱은 홈 화면, 시작 메뉴 또는 애플리케이션 도크에 설치할 수 있습니다. 설치는 사전 메시지에 따라 진행될 수도 있고 앱 개발자가 전적으로 제어할 수도 있습니다. 설치 가능하려면 무엇이 필요한가요? 도움말에서는 알아야 할 모든 사항을 다룹니다. 멀티태스킹 시 PWA는 브라우저와 독립적으로 표시됩니다.

컨텍스트 메뉴의 빠른 작업

가장 일반적인 앱 작업인 새 콘텐츠 검색새 에피소드 확인은 도크에 있는 앱의 컨텍스트 메뉴에서 바로 사용할 수 있습니다. 옵션 메뉴를 통해 로그인 시 앱을 열 수도 있습니다.

'검색' 및 '새 에피소드 확인' 옵션이 표시된 팟캐스트 앱 아이콘 컨텍스트 메뉴
앱 아이콘에서 바로 빠른 작업을 사용할 수 있습니다.

PWA의 웹 앱 매니페스트에서 앱 아이콘 바로가기를 지정하여 사용자가 앱 아이콘에서 직접 액세스할 수 있는 일반적인 작업의 빠른 경로를 등록할 수 있습니다. macOS와 같은 운영체제에서는 사용자가 앱 아이콘을 마우스 오른쪽 버튼으로 클릭하고 로그인 시 앱이 실행되도록 설정할 수도 있습니다. 로그인 시 실행하도록 제안하는 작업이 진행 중입니다.

기본 앱으로 작업

podcasts:// URL 스키마를 활용하면 다른 iOS 애플리케이션은 물론 웹사이트 또는 이메일까지도 팟캐스트 앱과 통합할 수 있습니다. 브라우저에서 podcasts://podcasts.apple.com/podcast/the-css-podcast/id1042283903와 같은 링크를 클릭하면 팟캐스트 앱으로 바로 연결되어 팟캐스트를 구독하거나 들을 수 있습니다.

사용자에게 팟캐스트 앱을 열 것인지 묻는 확인 대화상자가 표시된 Chrome 브라우저
브라우저에서 바로 팟캐스트 앱을 열 수 있습니다.

완전한 맞춤 URL 스킴을 아직 처리할 수는 없지만 PWA를 위한 URL 프로토콜 처리 제안을 위한 작업이 진행 중입니다. 현재는 web+ 스키마 접두사가 있는 registerProtocolHandler()를 사용하는 것이 가장 좋습니다.

로컬 파일 시스템 통합

당장 떠오르지 않을 수도 있지만 팟캐스트 앱은 자연스럽게 로컬 파일 시스템과 통합됩니다. 팟캐스트 에피소드를 다운로드하면 노트북에 ~/Library/Group Containers/243LU875E5.groups.com.apple.podcasts/Library/Cache에 저장됩니다. ~/Documents와 달리 이 디렉터리는 물론 일반 사용자가 직접 액세스하도록 만들어진 것이 아니라 액세스할 수 있습니다. 파일이 아닌 다른 저장 메커니즘은 오프라인 콘텐츠 섹션에서 참조됩니다.

macOS Finder가 팟캐스트 앱의 시스템 디렉터리로 이동했습니다.
팟캐스트 에피소드는 특수 시스템 앱 폴더에 저장됩니다.

File System Access API를 사용하면 개발자가 기기의 로컬 파일 시스템에 액세스할 수 있습니다. API를 직접 사용하거나 API를 지원하지 않는 브라우저에 대체 기능을 투명하게 제공하는 browser-fs-access 지원 라이브러리를 통해 사용할 수 있습니다. 보안상의 이유로 시스템 디렉토리는 웹에서 액세스할 수 없습니다.

플랫폼 디자인

팟캐스트와 같은 iOS 애플리케이션의 경우 더 미묘한 점이 있습니다. 텍스트 라벨을 선택할 수 없고 모든 텍스트가 컴퓨터의 시스템 글꼴과 혼합된다는 것입니다. 또한 내가 선택한 시스템 색상 테마 (어두운 모드)도 적용됩니다.

어두운 모드의 팟캐스트 앱
팟캐스트 앱은 밝은 모드와 어두운 모드를 지원합니다.
밝은 모드의 팟캐스트 앱
앱에서 기본 시스템 글꼴을 사용합니다.

none 값이 있는 user-select CSS 속성을 활용하여 UI 요소가 실수로 선택되지 않도록 보호할 수 있습니다. 하지만 이 속성을 악용하여 앱 콘텐츠를 선택할 수 없게 만들지 않도록 주의하세요. 버튼 텍스트와 같은 UI 요소에만 사용해야 합니다. font-family CSS 속성의 system-ui 값을 사용하면 앱에 사용할 시스템의 기본 UI 글꼴을 지정할 수 있습니다. 마지막으로 앱은 prefers-color-scheme 선택을 존중하여 사용자의 색 구성표 환경설정을 준수할 수 있습니다. 또한 어두운 모드 전환 옵션을 사용하여 재정의할 수 있습니다. 또한 스크롤 영역의 경계에 도달할 때 브라우저가 해야 할 작업을 결정해야 할 수도 있습니다. 예를 들어 맞춤 당겨서 새로고침을 구현할 수 있습니다. overscroll-behavior CSS 속성을 사용하면 됩니다.

맞춤설정된 제목 표시줄

팟캐스트 앱 창을 보면 Safari 브라우저 창과 같이 기존의 통합된 제목 표시줄과 툴바가 없지만 기본 플레이어 창에 도킹된 사이드바처럼 보이는 맞춤설정된 환경이 있는 것을 확인할 수 있습니다.

Safari 브라우저에 통합된 타일 바 및 툴바
팟캐스트 앱의 맞춤설정된 분할 맞춤 제목 표시줄
Safari 및 팟캐스트의 맞춤설정된 제목 표시줄

현재는 불가능하지만 현재 제목 표시줄 맞춤설정 작업을 진행 중입니다. 하지만 개발자는 웹 앱 매니페스트의 displaytheme-color 속성을 지정하여 애플리케이션 창의 디자인을 결정하고 어떤 기본 브라우저 컨트롤을 표시할지 결정할 수 있습니다.

Snappy 애니메이션

인앱 애니메이션은 팟캐스트에서 짧고 매끄럽게 재생됩니다. 예를 들어 오른쪽의 에피소드 메모 창을 열면 매끄럽게 미끄러져 들어옵니다. 다운로드한 에피소드에서 에피소드 하나를 삭제하면 나머지 에피소드가 떠다니며 삭제된 에피소드에서 확보된 화면 공간을 사용합니다.

'에피소드 메모' 창이 펼쳐져 있는 팟캐스트 앱
창을 열 때와 같은 인앱 애니메이션이 짧습니다.

애니메이션 및 성능 문서에 설명된 여러 권장사항을 고려한다면 웹에서 우수한 성능을 발휘할 수 있습니다. 페이지로 나눈 콘텐츠 또는 미디어 캐러셀에서 흔히 볼 수 있는 스크롤 애니메이션은 CSS 스크롤 스냅 기능을 사용하여 크게 개선할 수 있습니다. 완벽한 제어를 원하는 경우 Web Animations API를 사용할 수 있습니다.

콘텐츠가 앱 외부에 표시됨

iOS의 팟캐스트 앱은 실제 애플리케이션이 아닌 다른 위치(예: 시스템의 위젯 뷰 또는 Siri 추천 형식)에 콘텐츠를 표시할 수 있습니다. 탭 한 번으로 상호작용할 수 있는 사용 기반의 사전 예방적인 클릭 유도 문구를 사용하면 팟캐스트와 같은 앱의 재참여율을 크게 높일 수 있습니다.

팟캐스트의 새 에피소드를 추천하는 팟캐스트 앱이 표시된 iOS 위젯 뷰
앱 콘텐츠가 기본 팟캐스트 앱 외부에 표시됩니다.

Content Index API를 사용하면 애플리케이션에서 오프라인으로 사용 가능한 PWA 콘텐츠를 브라우저에 알릴 수 있습니다. 이렇게 하면 브라우저가 기본 앱 외부에 이 콘텐츠를 표시할 수 있습니다. 앱의 흥미로운 콘텐츠를 말할 수 있는 오디오 재생에 적합하도록 마크업하고 일반적으로 구조화된 마크업을 사용하여 검색엔진과 Google 어시스턴트와 같은 가상 어시스턴트가 서비스를 이상적인 방식으로 제시하는 데 도움이 될 수 있습니다.

잠금 화면 미디어 컨트롤 위젯

팟캐스트 에피소드가 재생 중일 때 팟캐스트 앱은 에피소드 아트워크, 에피소드 제목, 팟캐스트 이름 등의 메타데이터가 포함된 멋진 컨트롤 위젯을 잠금 화면에 표시합니다.

리치 메타데이터가 포함된 팟캐스트 에피소드를 보여주는 잠금 화면의 iOS 미디어 재생 위젯입니다.
앱에서 재생되는 미디어는 잠금 화면에서 제어할 수 있습니다.

Media Session API를 사용하면 아트워크, 트랙 제목 등의 메타데이터를 지정하여 브라우저의 잠금 화면, 스마트시계 또는 기타 미디어 위젯에 표시할 수 있습니다.

푸시 알림

푸시 알림은 웹에서 불편한 요소가 되었습니다 (알림 메시지가 훨씬 더 조용해졌음). 하지만 제대로 사용하기만 한다면 큰 가치를 더할 수 있습니다. 예를 들어 iOS 팟캐스트 앱에서 구독 중인 팟캐스트의 새 에피소드를 알림 또는 추천하고 새로운 앱 기능을 알릴 수 있습니다.

'알림' 설정 화면의 iOS 팟캐스트 앱에서 '새 에피소드' 알림 전환 버튼이 활성화되어 있습니다.
앱에서 푸시 알림을 전송하여 사용자에게 새로운 콘텐츠를 알릴 수 있습니다.

Push API를 사용하면 앱에서 푸시 알림을 받을 수 있으므로 PWA와 관련된 주목할 만한 이벤트를 사용자에게 알릴 수 있습니다. 향후 알려진 시간에 실행되어야 하고 네트워크 연결이 필요하지 않은 알림의 경우 Notification Triggers API를 사용할 수 있습니다.

앱 아이콘 배지 설정

구독 중인 팟캐스트의 새 에피소드가 제공될 때마다 팟캐스트 홈 화면 아이콘에 앱 아이콘 배지가 표시되어 방해가 되지 않는 방식으로 앱을 다시 이용하도록 유도합니다.

'배지' 전환 버튼이 활성화된 iOS 설정 화면
배지는 애플리케이션에서 사용자에게 새 콘텐츠를 알리는 간소한 방법입니다.

Badging API로 앱 아이콘 배지를 설정할 수 있습니다. 이는 PWA에 '읽지 않은' 항목이라는 개념이 있거나 눈에 거슬리지 않게 사용자의 관심을 앱으로 다시 유도하는 수단이 필요할 때 특히 유용합니다.

미디어 재생이 에너지 절약 모드 설정보다 우선합니다.

팟캐스트 미디어가 재생 중일 때 화면이 꺼질 수 있지만 시스템이 대기 모드로 전환되지는 않습니다. 앱은 선택적으로 가사나 자막을 표시하는 등 화면을 켜진 상태로 유지할 수 있습니다.

'에너지 절약 모드' 섹션에 있는 macOS 환경설정
앱이 화면을 켜진 상태로 유지할 수 있습니다.

Screen Wake Lock API를 사용하면 화면이 꺼지지 않도록 할 수 있습니다. 웹에서 미디어를 재생하면 시스템이 대기 모드로 전환되지 않도록 자동으로 방지할 수 있습니다.

앱 스토어를 통한 앱 검색

팟캐스트 앱은 macOS 데스크톱 환경의 일부이지만 iOS의 경우 App Store에서 설치해야 합니다. podcast, podcasts 또는 apple podcasts를 빠르게 검색하면 App Store에서 앱이 즉시 켜집니다.

iOS App Store에서 '팟캐스트'를 검색하면 팟캐스트 앱이 표시됩니다.
사용자는 앱 스토어에서 앱을 발견하는 방법을 배웠습니다.

Apple에서는 App Store에서 PWA를 허용하지 않지만 Android에서는 신뢰할 수 있는 웹 활동으로 래핑된 PWA를 제출할 수 있습니다. bubblewrap 스크립트를 사용하면 이 작업이 쉬워집니다. 이 스크립트는 PWABuilder의 Android 앱 내보내기 기능을 내부적으로 지원하는 것으로, 명령줄을 터치하지 않고도 이 기능을 사용할 수 있습니다.

기능 요약

아래 표에는 모든 기능에 대한 간략한 개요와 웹에서 이러한 기능을 구현하는 데 유용한 리소스 목록이 나와 있습니다.

특성 웹에서 이 작업을 수행하는 데 유용한 리소스
오프라인 실행 가능
오프라인 콘텐츠 사용 가능 및 미디어 재생 가능
사전 예방적 백그라운드 다운로드
다른 애플리케이션과 공유 및 상호작용
백그라운드 앱 새로고침
클라우드를 통해 동기화된 상태
하드웨어 미디어 키 컨트롤
멀티태스킹 및 앱 바로가기
컨텍스트 메뉴의 빠른 작업
기본 앱으로 활동
로컬 파일 시스템 통합
플랫폼의 디자인과 분위기
맞춤 제목 표시줄
깔끔한 애니메이션
앱 외부에 표시되는 콘텐츠
잠금 화면 미디어 제어 위젯
푸시 알림
앱 아이콘 배지
미디어 재생이 에너지 절약 모드 설정보다 우선함
앱 스토어를 통한 앱 검색

결론

PWA는 2015년에 도입된 이후 많은 발전을 이루었습니다. Project Fugu 🐡와 관련하여 회사 간 Chromium팀은 남은 마지막 격차를 해소하기 위해 노력하고 있습니다. 이 도움말에서 제공하는 조언 중 일부만 따르면 조금씩만 따라 해도 앱과 같은 느낌에 가까워지고 사용자가 '단순한 웹사이트'라는 사실을 잊게 할 수 있습니다. 솔직히 대부분의 사용자는 실제 앱처럼 느껴지는 경우 앱의 빌드 방법과 사용해야 하는 이유에 관심이 없기 때문입니다.

감사의 말

이 자료는 Kayce Basques, Joe Medley, Joshua Bell, Dion Almaer, Ade Oshineye, Pete LePage, Sam Thorogood, Reilly}, J 및 Grante가 검토했습니다.{/15