게시일: 2020년 12월 2일
신뢰할 수 있는 웹 활동이 도입된 이후 Chrome팀은 Bubblewrap에서 더 쉽게 사용할 수 있도록 했습니다. Google Play 결제 통합과 같은 기능이 추가되었으며 ChromeOS와 같은 더 많은 플랫폼에서 작동하도록 지원되었습니다.
Bubblewrap 및 신뢰할 수 있는 웹 활동 기능
Bubblewrap을 사용하면 플랫폼별 도구에 대한 지식이 없어도 신뢰할 수 있는 웹 활동 내에서 PWA를 실행하는 앱을 만들 수 있습니다.
간소화된 설정 흐름
이전에는 Bubblewrap을 사용하려면 오류가 발생하기 쉬운 Java 개발 키트와 Android SDK를 수동으로 설정해야 했습니다. 이제 이 도구는 처음 실행할 때 외부 종속 항목을 자동으로 다운로드할 수 있는 옵션을 제공합니다.
원하는 경우 기존 종속 항목 설치를 계속 사용할 수 있으며, 새 doctor
명령어는 문제를 찾고 구성 수정사항을 추천하는 데 도움이 됩니다. 이제 updateConfig
명령어를 사용하여 명령줄에서 구성을 업데이트할 수 있습니다.
마법사 개선
init
로 프로젝트를 만들 때 Bubblewrap에는 Android 앱을 생성하는 데 필요한 정보가 필요합니다. 이 도구는 웹 앱 매니페스트에서 값을 추출하고 가능한 경우 기본값을 제공합니다.
새 프로젝트를 만들 때 이러한 값을 변경할 수 있지만 이전에는 각 필드의 의미가 명확하지 않았습니다. 각 입력란에 관한 설명과 유효성 검사가 개선된 초기화 대화상자가 다시 빌드되었습니다.
전체 화면 및 방향 지원 표시
경우에 따라 애플리케이션이 화면을 최대한 많이 사용하도록 할 수 있으며, PWA를 빌드할 때는 웹 앱 매니페스트의 display
필드를 fullscreen
로 설정하여 이를 구현합니다.
Bubblewrap은 웹 앱 매니페스트에서 전체 화면 옵션을 감지하면 Android용 용어로 전체 화면 또는 몰입형 모드로 실행되도록 Android 애플리케이션을 구성합니다.
웹 앱 매니페스트의 orientation
필드는 애플리케이션을 세로 모드, 가로 모드 또는 기기가 현재 사용 중인 방향으로 시작해야 하는지 정의합니다. 이제 Bubblewrap은 웹 앱 매니페스트 필드를 읽고 Android 앱을 만들 때 이를 기본값으로 사용합니다.
bubblewrap init
흐름의 일부로 두 구성을 모두 맞춤설정할 수 있습니다.
AppBundles 출력
App Bundle은 최종 APK 생성 및 서명을 Play에 위임하는 앱의 게시 형식입니다. 실제로 이렇게 하면 스토어에서 앱을 다운로드할 때 더 작은 파일이 사용자에게 제공될 수 있습니다.
이제 Bubblewrap은 애플리케이션을 app-release-bundle.aab
라는 파일의 앱 번들로 패키징합니다. 2021년부터 스토어에서 요구하므로 Play 스토어에 앱을 게시할 때는 이 형식을 사용하는 것이 좋습니다.
위치정보 위임
사용자는 기기에 설치된 애플리케이션이 기술과 관계없이 일관되게 동작하기를 기대합니다. 이제 신뢰할 수 있는 웹 활동 내에서 사용하면 GeoLocation 권한을 운영체제에 위임할 수 있으며, 사용 설정하면 사용자에게 Kotlin 또는 Java로 빌드된 앱과 동일한 대화상자가 표시되고 동일한 위치에서 권한을 관리하는 컨트롤을 찾을 수 있습니다.
이 기능은 Bubblewrap을 통해 추가할 수 있으며 Android 프로젝트에 추가 종속 항목을 추가하므로 웹 앱에서 위치 정보 액세스 권한을 사용하는 경우에만 사용 설정해야 합니다.
최적화된 바이너리
저장용량이 제한된 기기는 특정 지역에서 흔하며 이러한 기기의 소유자는 소형 애플리케이션을 선호하는 경우가 많습니다. 신뢰할 수 있는 웹 활동을 사용하는 애플리케이션은 작은 바이너리를 생성하므로 이러한 사용자의 불안을 일부 해소할 수 있습니다.
필요한 Android 라이브러리 목록을 줄여 Bubblewrap을 최적화하여 생성된 바이너리의 크기가 80만 배 줄었습니다. 실제로는 이전 버전에서 생성된 평균 크기의 절반도 되지 않습니다. 더 작은 바이너리를 활용하려면 최신 버전의 Bubblewrap을 사용하여 앱을 업데이트하기만 하면 됩니다.
기존 앱을 업데이트하는 방법
Bubblewrap에서 생성된 애플리케이션은 웹 애플리케이션과 PWA를 여는 경량 Android 래퍼로 구성됩니다. 신뢰할 수 있는 웹 활동 내에서 열린 PWA는 다른 웹 앱과 동일한 업데이트 주기를 따르지만 네이티브 래퍼는 업데이트할 수 있고 업데이트해야 합니다.
최신 버그 수정 및 기능이 포함된 최신 버전의 래퍼를 사용하도록 앱을 업데이트해야 합니다. 최신 버전의 Bubblewrap이 설치된 경우 update
명령어는 기존 프로젝트에 최신 버전의 래퍼를 적용합니다.
npm update -g @bubblewrap/cli
bubblewrap update
bubblewrap build
이러한 애플리케이션을 업데이트하는 또 다른 이유는 웹 매니페스트의 변경사항이 애플리케이션에 적용되도록 하기 위해서입니다. 새 merge
명령어를 사용합니다.
bubblewrap merge
bubblewrap update
bubblewrap build
품질 기준 업데이트
Chrome 86에서는 신뢰할 수 있는 웹 활동 품질 기준에 변경사항이 도입되었습니다. 자세한 내용은 신뢰할 수 있는 웹 활동을 사용하는 PWA의 품질 기준 변경사항을 참고하세요.
간단히 요약하면 애플리케이션이 비정상 종료를 방지하려면 다음 시나리오를 처리해야 합니다.
- 애플리케이션 실행 시 디지털 애셋 링크 확인 실패
- 오프라인 네트워크 리소스 요청에 HTTP 200을 반환하지 않음
- 애플리케이션에서 HTTP 404 또는 5xx 오류가 반환됩니다.
애플리케이션이 디지털 애셋 링크 유효성 검사를 통과하는지 확인하는 것 외에도 나머지 시나리오는 서비스 워커에서 처리할 수 있습니다.
self.addEventListener('fetch', event => {
event.respondWith((async () => {
try {
return await fetchAndHandleError(event.request);
} catch {
// Failed to load from the network. User is offline or the response
// has a status code that triggers the Quality Criteria.
// Try loading from cache.
const cachedResponse = await caches.match(event.request);
if (cachedResponse) {
return cachedResponse;
}
// Response was not found on the cache. Send the error / offline
// page. OFFLINE_PAGE should be pre-cached when the service worker
// is activated.
return await caches.match(OFFLINE_PAGE);
}
})());
});
async function fetchAndHandleError(request) {
const cache = await caches.open(RUNTIME_CACHE);
const response = await fetch(request);
// Throw an error if the response returns one of the status
// that trigger the Quality Criteria.
if (response.status === 404 ||
response.status >= 500 && response.status < 600) {
throw new Error(`Server responded with status: ${response.status}`);
}
// Cache the response if the request is successful.
cache.put(request, response.clone());
return response;
}
Workbox는 권장사항을 베이킹하고 서비스 워커를 사용할 때 불필요한 코드를 삭제합니다. 또는 Workbox 플러그인을 사용하여 이러한 시나리오를 처리하는 것이 좋습니다.
export class FallbackOnErrorPlugin {
constructor(offlineFallbackUrl, notFoundFallbackUrl, serverErrorFallbackUrl) {
this.notFoundFallbackUrl = notFoundFallbackUrl;
this.offlineFallbackUrl = offlineFallbackUrl;
this.serverErrorFallbackUrl = serverErrorFallbackUrl;
}
checkTrustedWebActivityCrash(response) {
if (response.status === 404 || response.status >= 500 && response.status <= 600) {
const type = response.status === 404 ? 'E_NOT_FOUND' : 'E_SERVER_ERROR';
const error = new Error(`Invalid response status (${response.status})`);
error.type = type;
throw error;
}
}
// This is called whenever there's a network response,
// but we want special behavior for 404 and 5**.
fetchDidSucceed({response}) {
// Cause a crash if this is a Trusted Web Activity crash.
this.checkTrustedWebActivityCrash(response);
// If it's a good response, it can be used as-is.
return response;
}
// This callback is new in Workbox v6, and is triggered whenever
// an error (including a NetworkError) is thrown when a handler runs.
handlerDidError(details) {
let fallbackURL;
switch (details.error.details.error.type) {
case 'E_NOT_FOUND': fallbackURL = this.notFoundFallbackUrl; break;
case 'E_SERVER_ERROR': fallbackURL = this.serverErrorFallbackUrl; break;
default: fallbackURL = this.offlineFallbackUrl;
}
return caches.match(fallbackURL, {
// Use ignoreSearch as a shortcut to work with precached URLs
// that have _WB_REVISION parameters.
ignoreSearch: true,
});
}
}