2018 버전에서는 앱 소스 코드를 광범위하게 다시 작성했습니다. 이 앱은 오랫동안 ContentProvider + SyncAdapter 아키텍처를 사용해왔습니다. 우리는 올해 아키텍처 컴포넌트를 사용해 앱을 다시 작성하고 최신 앱 빌드를 위한 Android 팀의 현행 권장 사항과 코드를 동기화했습니다.

아키텍처

우리는 앱의 아키텍처에 대한 결정을 내릴 때 테스트와 유지 관리가 가능한 모듈식 코드를 작성하기 위해 Guide to App Architecture에서 제시하는 권장 사항을 따랐습니다. Activity와 Fragment에서 로직을 떼어내어 ViewModel로 옮겼습니다. LiveData를 사용하여 데이터를 관찰하고 Data Binding Library를 사용하여 레이아웃의 UI 컴포넌트를 앱의 데이터 소스에 바인딩했습니다.
앱의 전체 아키텍처를 다음 그림처럼 요약할 수 있습니다.
우리는 데이터 작업 처리를 위해 Repository 계층을 사용했습니다. IOSched의 데이터는 몇몇 서로 다른 소스에서 가져옵니다. 사용자 데이터는 Cloud Firestore에 저장되고(원격으로 저장되거나 오프라인 사용 시에는 로컬 캐시에 저장됨) 사용자 기본 설정과 각종 설정은 SharedPreferences에 저장됩니다. 컨퍼런스 데이터는 원격으로 저장되고 앱에서 사용할 수 있도록 가져와 메모리에 저장됩니다. 그리고 저장소 모듈이 모든 데이터 작업을 처리하고 앱의 나머지 부분에서 데이터 소스를 추출하는 역할을 맡습니다. 아키텍처를 이렇게 구성해두었으므로, 혹시 앞으로 다른 데이터 소스에 대해 Firestore 백엔드를 바꾸고 싶을 때 쉽고 깔끔하게 바꿀 수 있습니다.
우리는 가벼운 도메인 계층을 구현했는데, 데이터 계층과 프레젠테이션 계층 사이에 있는 이 계층은 UI 스레드에서 떨어져 나온 개별 비즈니스 로직을 처리합니다 (시보기)
우리는 종속성 주입을 위해 Dagger2를 사용하고 상용구 코드를 추출하는 데는 주로 dagger-android를 사용했습니다.
기본적인 계측 테스트에는 Espresso를 사용하고 단위 테스트에는 JUnit과 Mockito를 사용했습니다.


Firebase

Firebase 플랫폼이 성숙 단계로 접어들면서 앱에서 Firebase 기술 사용 비중도 커졌습니다. 2018 버전에서는 다음과 같은 Firebase 컴포넌트를 사용합니다.

  • Cloud Firestore는 모든 사용자 데이터(사용자가 시작하거나 예약한 이벤트)를 위한 Google의 소스입니다. Firestore가 자동으로 동기화하고 오프라인 기능도 완벽하게 관리해주었습니다.
  • Firebase Cloud Functions를 통해 백엔드 코드를 실행할 수 있었습니다. 예약 기능은 Functions에 주로 의존하여 사용자의 상태를 확인하고(참석자만 예약할 수 있도록 허용되었음) 공간 가용성을 확인하고 Firestore에서 예약 상태를 지속했습니다.
  • Firebase 클라우드 메시징을 사용하면 서버에서 컨퍼런스 데이터 변경 내용을 앱에 알릴 수 있습니다. 컨퍼런스 데이터는 주로 정적인 상태로 유지되지만, 때때로 바뀌는데 특히 컨퍼런스의 기조연설 후에 바뀝니다. 앱은 지금까지 컨퍼런스 데이터로 작업할 때 주로 '핑하고 가져오기' 모델을 사용했는데, 올해 역시 그런 사용 방법을 그대로 유지했습니다.
  • 원격 구성은 인앱 상수를 관리하는 데 도움이 되었습니다. 예년에는 컨퍼런스 일정에 직접 관련되지 않은 데이터(예: WiFi 정보, 컨퍼런스 장소로 운행되는 셔틀 운행 일정 등)가 예기치 않게 변경될 때 사용자에게 알릴 수 없다는 사실을 깨달았습니다. 그런데 원격 구성 덕분에 이러한 값을 쉽고 가볍게 업데이트할 수 있었습니다.


    Kotlin

    우리는 최신 Android 아키텍처에 적합하게 맞추려면 앱을 처음부터 다시 작성해야 한다는 결정을 일찍부터 내렸습니다. 재작성에 Kotlin을 사용하자는 선택은 쉽게 할 수 있었습니다. Kotlin은 다양한 표현을 간결하면서도 강력한 구문으로 처리할 수 있는 점이 마음에 들었기 때문입니다. Null 허용 여부와 불변성을 포함한 안전 기능을 위한 Kotlin의 지원으로 코드의 복원성이 더욱 좋아졌다는 점도 강점이었습니다. 또한 Android KTX Extension에서 제공하는 향상된 기능을 활용할 수 있는 이점도 있었습니다.


    머티리얼 디자인

    I/O 2018에서 머티리얼 디자인 팀은 제품 브랜드 가치를 더욱 높이기 위해 머티리얼 디자인을 훨씬 더 유용하고 강력하게 사용자설정하는 능력을 앱에 제공하는 머티리얼 테마 설정 기능을 발표했습니다. 머티리얼 테마 설정보다 앞서 이 앱을 출시했으므로 새로운 컴포넌트를 전부 사용하지는 못했지만, Floating Action 버튼을 끼워 넣은 새로운 Bottom App Bar처럼 두어 가지 기능을 슬쩍 집어넣을 수는 있었습니다. 또한 컨퍼런스 브랜딩 요소를 다수 포함할 수 있었습니다.


    향후 계획


    앱을 다시 작성함으로써 앱 빌드에 관해 Android가 고집하는 권장 사항에 맞춰 코드가 동기화되므로, 코드베이스가 더욱 깔끔해지고 유지 관리하기도 좋아졌습니다. 우리는 계속 앱의 개선 작업을 진행할 예정입니다. 그래서 JetPack 컴포넌트가 출시되면 이를 통합하고 앱에 꼭 맞는 플랫폼 기능을 보여줄 기회를 계속 모색할 것입니다. 개발자는 GitHub에서 코드 변경 사항을 계속 확인하실 수 있습니다.



    그동안 CNN(Convolutional Neural Networks)은 이미지 분류, 얼굴 인식, 개체 탐지 등의 다양한 영역에서 널리 사용되었습니다. 안타깝게도 모바일 기기에 맞게 CNN을 설계하기는 어렵습니다. 모바일 모델은 작고 빠르면서도 정확해야 하기 때문입니다. MobileNet이나 MobileNetV2처럼 모바일 모델을 설계하고 개선하기 위한 노력이 많이 있었지만, 고려해야 할 잠재적 사항이 너무 많기 때문에 여전히 효율적인 모델을 수동으로 만들기는 어렵습니다. 최근 AutoML 신경 아키텍처 탐색의 발전에서 영감을 얻어 모바일 CNN 모델 설계에도 AutoML을 적용해보면 어떨까 생각했습니다.


    MnasNet: 모바일을 위한 플랫폼 인식 신경 아키텍처 탐색”에서는 강화 학습으로 모바일 모델 설계에 자동 신경 아키텍처 탐색을 적용하는 방법을 살펴봅니다. 모바일의 속도 제약을 해결하기 위해 탐색 알고리즘의 메인 보상 함수에 속도 정보를 명시적으로 포함하여 탐색으로 정확도와 속도 간의 균형을 이루는 모델을 찾아낼 수 있도록 합니다. 따라서 MnasNet은 똑같이 ImageNet 최고의 정확도에 도달하면서도 수동으로 제작한 최신 MobileNetV2보다 1.5배, NASNet보다 2.4배 빠르게 실행되는 모델을 찾을 수 있습니다.


    다른 프록시(예: FLOPS)를 통해 모델 속도를 고려하는 이전의 아키텍처 탐색 방식과 달리, 당사는 특정 플랫폼(이 연구에서는 Pixel 휴대폰 사용)에서 모델을 실행하여 모델 속도를 직접 측정합니다. 모바일 기기 유형마다 고유한 소프트웨어와 하드웨어 특이성이 있고 정확도와 속도가 최적의 균형을 이루려면 다른 아키텍처가 필요할 수 있기 때문에, 이 방법을 사용하면 실제 현실에서 무엇을 달성 가능한지 직접 측정할 수 있습니다.


    이 방법의 전체적 흐름은 크게 3가지로 구성됩니다. 모델 아키텍처 학습과 샘플링을 위한 RNN 기반 컨트롤러, 모델을 빌드하고 훈련시켜 정확도를 달성하는 트레이너, TensorFlow Lite를 사용하여 실제 휴대폰에서 모델 속도를 측정하는 추론 엔진이 있습니다. 높은 정확도와 속도를 달성하는 것을 목표로 하는 다목표 최적화 문제를 만들고 맞춤 보상 함수가 포함된 강화 학습 알고리즘을 활용해 파레토 최적 솔루션(예: 속도를 저하하지 않고 가장 높은 정확도를 달성하는 모델)을 찾습니다.


    모바일을 위한 자동 신경 아키텍처 탐색의 전반적인 흐름.
    탐색 유연성과 탐색 공간의 크기가 적절히 균형을 이루게 하기 위해 새로운 분해형 계층적 탐색 공간을 새로 제안하고자 합니다. 이 방법은 매우 복잡한 신경망을 연속적 블록으로 분해한 다음, 계층적 탐색 공간을 사용해 각 블록의 계층 아키텍처를 결정합니다. 이렇게 하면 각 계층이 서로 다른 연산과 연결을 사용할 수 있고, 동시에 각 블록의 모든 계층이 동일한 구조를 공유하여 평평한 계층별 탐색 공간에 비해 탐색 공간 규모를 몇 배나 줄일 수 있습니다.


    새로운 분해형 계층적 탐색 공간에서 샘플로 추출한 MnasNet 네트워크로, 네트워크 아키텍처 전체의 계층 다양성을 보여줍니다.
    이 방법으로 ImageNet 분류와 COCO 객체 탐지에 얼마나 효과를 발휘하는지 테스트해보았습니다. 일반 모바일 속도 제약을 적용하여 실험했을 때 기록적인 정확도를 달성했습니다. 특히, 아래 그림은 ImageNet에서 얻은 결과를 보여줍니다.


    ImageNet 정확도 및 추론 지연 시간 비교 MnasNet은 당사의 모델입니다.
    정확도가 동일할 때 MnasNet 모델은 수동으로 제작한 최신 MobileNetV2보다 1.5배, NASNet보다 2.4배 빠르게 실행됩니다(두 모델도 아키텍처 탐색을 사용함). squeeze-and-excitation 최적화를 적용한 후, MnasNet+SE 모델은 ResNet-50 수준의 최상급 정확도(76.1%)를 달성했습니다. 하지만 매개변수는 19배 줄어들었고 곱셈-덧셈 연산은 10배 감소했습니다. COCO 객체 탐지에서는 당사 모델군이 MobileNet보다 정확도와 속도가 더 높았고, SSD300 모델과는 정확도가 유사하지만 연산 비용은 35배 적게 들어갔습니다.


    당사의 자동 모델이 여러 가지 복잡한 모바일 시각 작업에서 최고의 성능을 보여주어 기쁩니다. 향후에는 탐색 공간에 더 많은 연산과 최적화를 통합하여 의미론적 세그먼테이션 등과 같은 더 많은 모바일 시각 작업에 적용할 계획입니다.


    감사의 말

    논문의 공동 저자인 Bo Chen, Quoc V. Le, Ruoming Pang과 Vijay Vasudevan에게 특별한 감사를 전합니다. 또한, 도움을 주신 Andrew Howard, Barret Zoph, Dmitry Kalenichenko, Guiheng Zhou, Jeff Dean, Mark Sandler, Megan Kacholia, Sheng Li, Vishy Tirumalashetty, Wen Wang, Xiaoqiang Zheng, Yifeng Lu와 TensorFlow Lite 및 Google Brain 팀에도 감사드립니다.

    Jen Person
    디벨로퍼 어드보케


    이번 에디션에서 다룰 내용: Cloud Firestore, Flutter, Algolia를 이용한 검색, Phone Auth, 새로운 ML 키트


    저는 새로운 프로젝트를 시작하고 싶은 기분이 들 때면 도움이 될 만한 가이드를 꼭 챙긴답니다. Firebase 커뮤니티에서는 늘 새로운 자료가 쏟아져 나오고 있어 계속 바쁘게 만든다는 점이 오히려 다행이라고나 할까요. Firebase 제품에 관해 더 많은 자료를 찾고 계신 분이라면 아마 블로그나 동영상 자료를 찾아보기도 하고 이런 매체를 통해 자신의 경험을 공유하신 적도 있을 겁니다.
    그런데 워낙 다양한 콘텐츠가 여기저기 흩어져 있는 관계로, 저는 인터넷을 샅샅이 뒤져 지난 두어 달 동안 공개된 Firebase 가이드 중 최고의 가이드만 추려내어 여러분께 소개해 드리면 어떨까 하고 생각했습니다. 마음 같아서는 Firebase에 관한 기사와 동영상을 죄다 챙겨 보시라고 하고 싶지만, 여러분 모두 시간이나 공간에 제약이 있으므로 제가 가장 흥미롭게 본 가이드를 몇 가지만 소개해 드리겠습니다.

    동영상 가이드

    Cloud Firestore 동영상 시리즈

    작성자: The Net Ninja
    이 시리즈에서는 Shaun이 Cloud Firestore를 단순한 웹 앱에 통합하는 과정을 단계별로 안내합니다. Cloud Firestore에 대한 소개부터 시작해서 데이터 읽기, 쿼리 생성, 데이터 쓰기, 실시간 업데이트 등의 과정으로 계속 진행합니다. 해당 내용을 잘 시각화한 일러스트레이션 덕분에 이해하는 데 정말 큰 도움이 되었습니다. 이 동영상 시리즈에는 GitHub의 코드로 연결되는 링크도 포함되어 있습니다.

    Flutter 내 Firebase 및 Firestore에서 Google로 사용자 인증

    작성자: Tensor Programming
    제목이 시사하는 바와 같이, 이 가이드에서는 개발자에게 Firebase 인증을 이용해 Flutter 앱에 사용자가 로그인하도록 하는 방법을 보여줍니다. 이 동영상은 시리즈 중간 부분을 발췌한 것이므로 Cloud Firestore를 Flutter와 통합하는 방법에 대해 알아보려면 첫 부분으로 돌아가서 보시면 됩니다. 저는 이전에는 Dart로 작업해 본 적이 한 번도 없지만, 강사가 워낙 쉽게 각 단계를 설명해줘서 정말 쉽게 따라 할 수 있었습니다.

    Algolia Firestore 순간 검색

    작성자: Angular Firebase
    Angular Firebase 채널에서는 Firebase의 온갖 종류의 기능을 사용하는 다양한 가이드를 많이 만들어냅니다. 특히 이 가이드를 추천하고 싶은데요. 너무나도 많은 개발자가 Firestore에 전체 텍스트 검색을 구현하는 방법을 알고 싶어 하기 때문입니다. 전 Cloud Functions를 사용하는 것도 좋아하는데, 특히 환경 변수에서 비밀 API 키를 숨기는 방법에 관한 데모가 마음에 들더군요. Angular를 사용하지 않는 분이라도 이 동영상을 보시면 많은 걸 배우실 수 있을 겁니다. Angular를 사용하는 분이라면 당연히 훨씬 더 많은 걸 배우실 수 있겠죠!

    문서 가이드

    Firebase 전화 인증 Android

    문서 가이드와 동영상 가이드 중 어떤 걸 선택할지 고민하기 싫으세요? 그렇다면 동영상 콘텐츠도 포함된 Belal Khan의 Firebase 전화 인증 가이드를 추천해 드립니다. Khan이 글을 쓰는 스타일은 한 줄마다 구질구질하게 설명을 덧붙이기보다는 좀 큰 단위의 코드 블록을 제시하고 그 사이에 설명을 하는 방식입니다. 코드를 전체적으로 살펴보면서 배우고 싶은 분들께 적합한 스타일이죠. 저는 새로운 기능을 배울 때 전체 샘플을 보면서 각 코드 블록이 함께 어떤 식으로 작동하는지 살펴보는 방식이 좋아서 Khan의 스타일이 마음에 꼭 들었습니다.

    Firebase BQ 데이터에 적합한 Google 애널리틱스

    작성자: Anže Kravanja
    저는 이 가이드가 마음에 듭니다. 솔직히, 저는 Google 애널리틱스에 대해 거의 아는 게 없고 Big Query는 전혀 모릅니다. 이 가이드를 살펴보니 Firebase용 Google 애널리틱스에 저장된 데이터의 활용도를 더욱 높이려는 개발자에게 훌륭한 자료라는 걸 깨달았습니다. 이 가이드에서는 Firebase용 Google 애널리틱스에서 세션을 추적하는 방식을 설명하고 Firebase 이벤트를 사용자 세션으로 분류하는 방법을 단계별로 보여줍니다.

    iOS에서 Google의 Firebase용 ML 키트를 이용한 텍스트 인식 및 안면 감지 기술 탐구

    Adam Talcott는 Firebase용 ML 키트를 위한 두 가지 재미있고 유용한 사례를 살펴봅니다. Swift 공동 개발자로서, 저는 다른 iOS 관련 개발자들이 Firebase를 어떻게 사용하고 있는지 알고 싶습니다.
    이러한 리소스가 훌륭한 앱을 빌드하는 데 영감을 주기를 바랄게요! 저 역시 이런 자료를 보고 나니, 이젠 자외선 차단 크림을 듬뿍 바르고 쏟아지는 햇살을 만끽하면서 다음 Firebase 프로젝트를 코딩할 준비가 된 느낌이 듭니다!

    다양한 가이드를 통해 소중한 지식을 공유해주신 모든 개발자께 감사드립니다. Firebase는 개발자가 충분히 활용할 때 그 진정한 가치를 발휘할 것입니다. 제가 이곳에 두 달에 한번씩 가이드에 대한 정보를 싣도록 할 테니, 여러분도 마음에 드는 가이드를 발견하시면 제게 꼭 얘기해주세요. Twitter에서 @ThatJenPerson으로 절 찾으실 수 있을 겁니다.



    새로운 CSS 트릭

    Chrome에 여러 가지 새로운 CSS 기능이 추가되었습니다.


    Conic 그라데이션

    CSS Conic(좁은 타입/넓은 타입) 그라데이션은 색상이 중심에서 방사형으로 퍼지지 않고 중심을 주변으로 전환되도록 합니다. 예를 들어 아래와 같이 CSS 속성 2개만 사용하여 원형으로 퍼지는 색상 그라디언트를 만들 수 있습니다. 자세한 예시를 알아보세요.


    div {
     background: conic-gradient(red, yellow, lime, aqua, blue, magenta, red);
     border-radius: 50%
    }


    새로운 여백, 패딩 및 테두리 속성

    논리적 margin, paddingborder 속성은 이제 표준 이름을 사용합니다. 특히 margin-{block,inline}-{start,end}, padding-{block,inline}-{start,end}, border-{block,inline}-{start,end}-{width,style,color}가 이에 해당합니다. 이전에 이 기능은 -webkit 접두사를 붙어거나 표준이 아닌 이름으로 지원되었습니다. 약칭 속성은 border-{block,inline}-{start,end}에만 추가되었습니다.


    CSS 스크롤 스냅

    CSS 스크롤 스냅 위치는 스크롤 컨테이너의 시각적 뷰포트에 있는 오프셋으로, 각 스크롤 동작을 완료한 후 스크롤이 멈추는 곳입니다. 쉽게 스크롤 가능한 영역을 미리 정의된 지점에 멈추게 할 수 있으므로 사용자 경험이 개선됩니다. 또한 JavaScript를 사용할 필요 없이 일반적인 UX 스크롤 패턴을 지원합니다. 그런 패턴의 예로는 아래와 같은 가로 이미지 캐러셀을 들 수 있습니다. 이에 관한 상세한 내용은 'Well-Controlled Scrolling with CSS Scroll Snap' 문서를 참조하시기 바랍니다.


    #gallery {
     scroll-snap-type: x mandatory;
     overflow-x: scroll;
     display: flex;
    }

    #gallery img {
      scroll-snap-align: center;
    }


    디스플레이 컷아웃

    이제 Chrome에서는 디스플레이 컷아웃을 새로운 CSS env() 함수(환경 변수)와 뷰포트 맞춤 메타 태그를 통해 지원합니다. 이로써 개발자는 디스플레이 컷아웃이 있는 기기의 화면 전체를 활용할 수 있습니다.


    예를 들어 브라우저에 디스플레이 컷아웃 영역 안으로 확장되도록 지시하려면 사이트에서 viewport 메타 태그의 viewport-fit 속성을 cover로 설정해야 합니다. 그런 다음 사이트가 안전 영역 인셋 CSS 환경 변수를 사용하면 컷아웃에 가리지 않고 콘텐츠를 배치할 수 있습니다. 아래를 참조하세요. 자세한 정보는 설명서사양에서 참조하세요.


    <meta name="viewport" content="viewport-fit: cover" />

    <style>
     #box {
       margin-top: env(safe-area-inset-top);
       margin-left: env(safe-area-inset-left);
       margin-bottom: env(safe-area-inset-bottom);
       margin-right: env(safe-area-inset-right);
     }
    </style>

    <div id=box></div>


    이번 릴리즈에 포함된 기타 기능

    캔버스

    OffscreenCanvas는 워커에서 2D 및 WebGL 캔버스 렌더링 콘텍스트를 사용할 수 있게 해주는 새 인터페이스입니다. 이는 웹 애플리케이션의 병렬 처리를 늘리고 멀티 코어 시스템에서의 성능을 향상합니다.


    이제 Chrome에서는 DedicatedWorker.requestAnimationFrame()도 지원하므로, Window에서와 같이 전용 워커에서도 애니메이션과 유사한 이벤트를 트리거할 수 있습니다. 예:


    const offscreenCanvas = new OffscreenCanvas(100, 100);
    const ctx = offscreenCanvas.getContext("2d");
    ctx.fillRect(0, 0, 10, 10);


    또는 캔버스를 포함하는 경우:


    const canvasElement = document.getElementById("mycanvas")
    const offscreenCanvas = canvasElement.transferControlToOffscreen();
    const ctx = offscreenCanvas.getContext("2d");
    ctx.fillRect(0, 0, 10, 10);


    워커 내부:


    self.onmessage = function(ev) {
     const offscreenCanvas = ev.data;
     const ctx = offscreenCanvas.getContext("2d");
     let x = 0;
     const draw = function() {
       ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
       ctx.fillRect(x, 0, 10, 10);
       x = (x + 1) % ctx.canvas.width;
       requestAnimationFrame(draw);
     };
     draw(0);
    }


    메인 페이지:


    const worker = new Worker("worker.js");
    const offscreenCanvas =
       document.getElementById("canvas").transferControlToOffscreen();
    worker.postMessage(offscreenCanvas, [offscreenCanvas]);


    DOM

    Element.toggleAttribute() 라는 새 메서드를 사용하면 Element.classList.toggle과 유사한 방법으로 요소 속성의 존재유무를 전환할 수 있습니다. 선택 사항으로 Force 매개변수를 사용하면 Force의 값에 따라 속성을 강제로 추가하거나 삭제합니다. 이렇게 하면 인터페이스가 Element.setAttribute()처럼 문자열을 사용하지 않기 때문에 불리언 속성을 훨씬 간편하게 관리할 수 있습니다.


    Fetch API: Request.isHistoryNavigation

    요청 객체에 불리언 속성을 추가하여 특정 요청이 히스토리 네비게이션인지 여부를 나타내게 하였습니다. 이렇게 하면 서비스 워커가 요청의 원인이 뒤로/앞으로 네비게이션인지 여부를 알 수 있습니다. 서비스 워커가 그러한 네비게이션에 캐시된 응답으로 대응할 수 있게 된다는 것이 좋은 활용 사례입니다.


    JavaScript API

    JavaScript에 여러 개의 새로운 API가 생겼습니다.


    • ReportingObserver API는 지원 중단 및 브라우저 간섭에 대응하여 호출되는 JavaScript 콜백 함수를 제공합니다. 보고서는 저장하거나 서버에 전송하거나 임의의 JavaScript를 사용하여 처리할 수 있습니다. 이 기능은 개발자가 실제 기기에서 사이트의 작동 현황을 좀 더 잘 파악할 수 있도록 고안한 것입니다.
    • JavaScript 배열에는 새 메서드 2개가 추가됩니다. Array.prototype.flat()은 새 배열에 지정된 깊이까지 재귀적으로 연결된 모든 하위 배열 요소를 포함하여 반환합니다. 이러한 하위 배열 요소는 새 배열의 구성원이 됩니다. Array.prototype.flatMap()은 우선 매핑 함수를 사용하여 각 요소를 매핑한 다음 그 결과를 결합하여 새 배열로 만듭니다. 이 메서드는 깊이 = 1로 flat()을 호출했을 때 표시되는 맵과 기능적으로 동일합니다.

      Keyboard Map API

      게임과 같은 일부 애플리케이션에서는 특정 실제 키에 특정 함수를 할당합니다. 인터페이스가 해당 키를 참조하는 경우, 인터페이스는 키에 표시된 문자(로케일에 따라 다름)를 표시하거나 사용자가 설치한 대체 키보드 레이아웃으로 키에 할당한 문자를 표시해야 합니다. 이와 같은 레이아웃 차이가 있기 때문에 인터페이스에 표시된 문자가 원래 의도한 실제 키를 참조하지 않는 경우도 있습니다.


      이러한 새 API는 실제 키를 나타내는 KeyboardEvent.code 값을 사용자에게 표시할 올바른 문자열로 변환할 방법을 제공합니다. 이 새로운 API에 대한 자세한 정보와 예시는 사양설명서를 참조하세요.


      Loader

      "rtt", "downlink" 및 "ect" 클라이언트 힌트 값 지원과 HTTP 요청 헤더를 Chrome에 추가하여 서버에 대한 기기의 네트워크 연결 속도를 전달하도록 하였습니다. 예를 들어 rtt 클라이언트 힌트의 경우 현재 연결의 예상 유효 왕복 시간을 가장 가까운 25밀리초의 배수로 반올림/반내림하여 서버에 제공합니다. 연결 속도가 예상보다 느린 경우, 서버는 이것을 다운샘플링한 이미지로 사용할 수 있습니다. 이러한 네트워크 품질 힌트는 서버에 Network Information API(navigator.connection.rtt, navigator.connection.downlink 및 navigator.connection.effectiveType)가 웹페이지에 제공한 것과 동일한 값을 제공합니다.


      미디어: EME를 통한 암호화 구성표 지원 쿼리

      일부 플랫폼 또는 키 시스템은 CTR 모드의 AES-128만 지원하거나, CBCS 모드만 지원합니다. 두 가지 모드를 모두 지원할 수도 있습니다. 새 메서드를 사용하면 웹 개발자는 특정 암호화 구성표가 EME(Encrypted Media Extensions)로 지원되는지 쿼리할 수 있습니다.


      합자 중 텍스트 선택

      이제 Chrome에서는 합자(ligature) 내의 텍스트를 선택할 수 있습니다. (합자란 두 개 이상의 문자를 한 개의 기호로 결합한 것을 말합니다.) 여기에는 입력 및 텍스트 영역 요소의 마우스 선택과 커서 선택이 모두 포함됩니다. 이 변경 사항을 지원하기 위해 텍스트 선택을 렌더링하는 방법도 약간 변경하였습니다. 이제 선택 영역을 벗어난 텍스트 부분은 원래 방식대로 렌더링됩니다.




      영어 합자에서의 선택.




      아랍어 합자에서의 선택.


      성능

      프레임 간의 정보 유출을 방지하기 위해 현재 performance.memory 값을 무겁게 양자화하여 20분간 지연됩니다.


      렌더러 프로세스를 단일 사이트의 문서로 제한된다면(예: 데스크톱에서 사이트 격리의 경우) 프레임 간 정보 유출에 대한 큰 걱정 없이 이 정보를 노출할 수 있습니다. 이런 경우에는 양자화된 메모리 사용 정보를 반환하지 않습니다(30초 지연). 이로써 메모리 측정이 더욱 정확해지고 더 자주 실시할 수 있기 때문에 개발자가 사용자 데이터 성능 저하를 쉽게 파악할 수 있습니다.


      ServiceWorker

      서비스 워커에 두 가지 개선 사항이 있습니다.


      • 이전에 ServiceWorkerRegistration.update()는 undefined였지만 이제는 등록 객체로 나타납니다(사양에 따라 필요한 경우).
      • 이전에는 기술적인 한계로 인해 비보안 컨텍스트에 액세스하면 navigator.serviceWorker가 SecurityError를 발생시켰습니다. 이번 변경 사항이 적용된 후 navigator.serviceWorker는 undefined을 반환합니다.

        이는 스펙과 일치합니다.


        CSS 그리드 레이아웃 퍼센테이지 행 트랙 및 여백의 동작 업데이트

        향후 릴리즈에서는 규정되지 않은 높이의 그리드 컨테이너에서 퍼센테이지 행 트랙과 여백을 확인하는 방법이 변경됩니다. 이들은 현재 일반 블록의 비율 높이와 유사하게 동작하지만, 앞으로는 열과 같이 동작하여 대칭을 이루게 됩니다.


        즉 기본 높이를 계산할 때는 비율을 무시하고(지금처럼) 나중에 높이에 비교하여 확인합니다. 이렇게 하면 열과 행 축이 모두 대칭으로 동작하므로 비율로 지정된 트랙과 여백을 확인할 수 있습니다.


        Chrome 69에서는 이 변경 사항에 대한 경고를 JavaScript 콘솔로 전달할 예정입니다. Chrome 70에서 현재 동작을 그대로 유지하고자 하는 경우, 규정되지 않은 높이의 그리드 컨테이너에서 퍼센테이지 행 트랙과 여백을 각각 "auto"과 "0px"로 교체해야 합니다.


        Web Locks API

        Web Locks API를 사용하면 한 탭에서 실행 중인 스크립트가 비동기식으로 잠금을 완료하고 작업을 수행 중인 동안에는 그대로 유지하다가 해제하도록 할 수 있습니다. 잠금 유지 시 같은 출처에서 실행 중인 다른 스크립트는 같은 잠금을 완료할 수 없습니다. 잠금은 몇 가지 잠재적인 공유 리소스를 나타내며, 이는 웹 앱이 선택한 이름으로 식별됩니다. 예를 들어 여러 탭에서 실행 중인 웹 앱이 하나의 탭만 네트워크에 동기화되도록 하고자 하는 경우 각 탭이 모두 my_net_sync 잠금을 완료하려 시도할 수 있지만, 한 탭만 성공하게 됩니다.


        예를 들면 아래와 같습니다. 이 예시에서는 my_resource 잠금이 완료되었을 때 호출되는 함수를 나타냅니다.


        await navigator.locks.request('my_resource', async lock => {
         const url = await look_up_in_database();
         const response = await fetch(url);
         const body = await response.text();
         await store_body_in_database(body);
        });


        이 API 메서드와 옵션에 대한 자세한 정보는 설명서사양 초안을 참조하세요.


        Web Authentication으로 CTAP2 FIDO 기기 지원

        Web Authentication에 CTAP2 기기 지원을 추가하면 생체 인증, 상주 키(기기에 저장된 키)와 같은 고급 보안 기능을 제공합니다. WebAuthentication API는 이전에는 전송 계층에서 U2F(Universal 2nd Factor) 기기만 지원했습니다. 이번 변경 사항으로 API 외관 자체가 바뀌지 않지만 기존 Web Authentication API를 통해 더욱 풍부한 기기 상호작용을 지원하게 됩니다.


        WebRTC

        WebRTC는 개선 사항이 두 가지 있습니다.


        • 이제 Chrome에서 RTCRtpParameters.headerExtensions dictionary 항목을 지원하며 이는 RTCRtpSender.getParameters()에 의해 반환됩니다. 이는 읽기 전용 필드로, 협상 후 PeerConnection에 설정되는 매개변수를 검사할 수 있습니다.
        • 이제 RTCRtpSender 및 RTCRtpReceiver 인터페이스가 getCapabilities() 메서드를 제공합니다.

          이 메서드는 주어진 종류의 미디어 전송에 가장 적합한 시스템 기능 뷰를 반환합니다. 리소스, 포트 또는 기타 상태를 예약하지는 않지만 브라우저에서 어떤 유형의 기능이 지원되는지 알아볼 수 있습니다(예: 지원되는 코덱 또는 RTP 확장 프로그램).


          지원 중단 및 상호 운용성 개선 사항

          Chrome에서는 가끔 다른 브라우저와의 상호 운용성 증대를 위해 지원 중단, 삭제 또는 변경되는 기능이 있습니다. 이번 Chrome 버전에도 다음과 같이 변경되는 사항이 있습니다.


          Media Source Extensions를 사용하는 HTMLMediaElements에서 'stalled' 이벤트 제거

          이전에는 미디어 다운로드가 최소 3초 이상 진행되지 않으면 HTMLMediaElement.stalled 이벤트가 발생했습니다. Media Source Extensions에서는 웹 앱이 다운로드를 관리하며 미디어 요소는 다운로드 진행률을 인식하지 못합니다. 일부 앱의 경우 3초 이상의 미디어 데이터를 대량으로 추가하기 때문에 부적절한 시점에 stalled가 발생하였습니다. 이 문제를 해결하기 위해 Media Source Extensions에서 stalled를 제거하였습니다.


          document.createTouchList 제거

          document.createTouchList() 메서드가 삭제되고


          그 대신 Chrome 48부터 지원되는 Touch() 생성자를 사용합니다.


          Window.confirm() 메서드가 상위 탭을 더 이상 활성화시키지 않음

          백그라운드 탭의 문서가 window.confirm()을 호출하면 이는 즉시 false를 반환하고, 사용자에게 아무런 대화상자를 표시하지 않습니다. 탭이 활성화된 경우에는 이 호출이 평소처럼 대화상자를 표시합니다. 구체적으로 설명하면 이번 조치로 인해 window.confirm()을 사용하여 탭을 전방으로 가져오지 못하게 됩니다. 사용자가 이를 바라는 경우는 거의 없기 때문입니다.

          게시자: Jennifer Apacible