안드로이드 앱 다크모드 적용기

Why — The future is dark.

김종식
원티드랩 기술 블로그
15 min readSep 19, 2019

--

머터리얼 디자인 가이드라인에서 다크테마는 화면 전반적으로 저조명의 UI로 표현하는 것으로 소개하고 있습니다. 유저 입장에서 눈에 부담을 많이 줄이고, 베터리 소모량 개선에 도움이 된다고 알려져 있습니다. 개발자들에게 다크테마 지원을 크게 권장한다고 Google I/O 2019 에서 밝힌 바 있으며, 안드로이드 10 정식 출시 이 후 시스템 설정에서 다크모드 활성화가 정식 지원됩니다.

원티드사용자의 관점에서 일관적인 경험을 할 수 있도록 디자인 하는것을 목표로 하고 있으며, 언제나 유저 입장에서 제품을 만들기 위하여 노력중입니다. 이러한 노력으로 사용자 피드백 중 앱 사용성이 좋다는 의견을 가장 많이 받고있습니다. 일반적으로 모바일 환경에서 검색/탐색은 유저들의 가장 많은 행동 패턴이고, 원티드 또한 서비스 특성으로 특히 저녁시간대가 많은 편입니다. (놀랍게도, 가장 많이 사용되는 시간대는 출근 시간대입니다.) 어두운 환경에서도 편안하게 앱을 사용할 수 있도록 다크테마 도입에 대하여 고민하였고, 팀에서도 긍정적인 의견에 힘입어 4.4.1 버전에 실제 제품에 해당 기능이 포함되어 출시로 이어질 수 있었습니다.

<연봉정보 다크모드 적용화면>

현재 운영중인 안드로이드 서비스에 다크테마를 적용하는 과정에 대하여 정리해 보았습니다.

Goal — 안정성을 유지한 채 사용자 경험 개선하기

앱 개발팀 내 사이트 프로젝트로 진행하여 개발 진행 시 필요한 팀 리소스를 최소화하며, 검증이 필요없는 수준으로 개발 완료 를 목표로 설정하였습니다. 크게 아래와 같은 순서로 작업이 진행되었습니다.

  1. 개발팀 주도 프로토타이핑
  2. 디자인 리뷰 1차 (대표 색상 정리, 다크모드 적용을 위한 이미지 리소스 작업 요청)
  3. 디자인 리뷰 2차 (동시 진행되는 과제들 머지 및 이미지 리소스 적용, 1차때보다 완성도 높은 기준으로 디자인 리뷰)
  4. 내부 피드백 및 출시

기존의 색상값을 다크모드에서 적절한 색상값으로 정의하는 것은 개발자에게 쉽지 않습니다. 프로토타이핑시 색상 변환 웹페이지를 활용하여 기존에 사용중인 색상값을 입력하여 다크모드에 어울릴 만한 컬러값을 사용하였습니다. 완전히 흰색(#FFFFFF)혹은 검정색(#000000)을 제외하면 일반적으로 원본 컬러에 따라 Brightness Gradient / Saturation Gradient 20%, 30%, 40% 적용된 값이 프로토타이핑에 가장 적정한 색상값이었습니다. 이렇게 적용 된 버전으로 디자인팀에서 다크테마에 좀 더 완성도 있는 색상 값을 적용하는데 도움을 받을 수 있었습니다.

다크모드 적용과 함께 기존 리소스 정리(미사용 리소스 제거, 리소스 네이밍 정리 등)도 함께 진행하였으며, 상당히 오랜 시간 걸리는 작업이기 때문에 병렬로 진행되는 다른 과제들에 대하여 컬러 리소스를 참조하지 않고 뷰에 직접 #RGB 형태로 디자인 작업을 하도록 사전에 공유 하였습니다. 이러한 내용은 코드리뷰 시 관련 사항 체크 및 다크모드 작업 진행 브랜치에서 주기적으로 색상 정의 리소스 업데이트 팔로업에 용이하였으며, 다크모드 작업 전담자가 수행하는 것이 제품에 반영될 때 혼선을 최소화 할 수 있는 방법이라고 생각하였습니다.

How ?

기본적으로 다크모드 적용을 위한 방법은 크게 어렵지 않습니다. 개발자 가이드를 참조하여 적용하면 됩니다. 화면 단위로 다크모드 적용 여부 확인 및 기존 화면체크 하는데 있어 시간이 오래 걸리는 작업이고 꼼꼼하게 체크 하는 것이 중요합니다.

가장 먼저 해야 할 일은 App Theme를 Light에서 DayNight로 변경 하는 일입니다. 시스템 설정 — 야간 모드 활성화를 하게 되면 values-night 폴더 리소스가 활성화 되지만, 앱에서 사용되는 몇 가지 속성들은(ex. TabBarLayout, Toolbar style 등) DayNight로 변경해야 다크모드에 맞는 색상으로 변환이 됩니다. 모든 컬러 및 리소스를 values, values-night로 분기해서 참조하게 선언할 수 있으나 일부 UI의 경우 기본적으로 제공되는 스타일을 사용하고 있었기 때문에 다크모드 설정 시에도 기본 설정값을 따라가게 합니다.

대표 색상값 정리

가장 먼저 values-night 폴더를 생성하고 values 폴더의 colors.xml 파일을 values-night 폴더로 복사합니다. 그리고 values-night/colors.xml 리소스 중 주요 색상값을 다크모드 시 적용되어질 색상으로 변경하고 앱을 실행해 봅니다.

<주요 색상만 다크모드 적용을 위한 값으로 설정 하고 실행한 결과>

기존 코드에서 리소스 참조 중 colorPrimary, colorBackground, colorControlNormal 등이 흰색을 기준으로 참조하고 있어서 손쉽게 적용 완료했다는 인상을 받았습니다. 기능과 관련된 컬러 값만 colorAccent를 사용하고 있었으며, Text / Background 등 상황에 따라 다크모드에 최적화된 컬러 값을 찾는 부분은 프로토타이핑으로 초기 작업 후, 디자인 리뷰에서 점진적으로 개선해 나갔습니다.

Color 리소스 정리

기존에 사용중인 리소스를 다크모드 색상 값으로 정리할 때는 해당 리소스가 어떤 context에서 사용되는지 확인이 필요합니다. colorAccent 색상의 경우 텍스트일 경우, 아이콘일 경우 등 다양한 상황에서 사용됩니다. 또, Light Theme 일 경우에는 동일한 색상값을 참조하지만, 다크모드에서는 다른 색상값을 적용해야 할 필요한 경우가 있습니다.

이러한 상황을 고려하여 기본 색상 리소스 정의를 1차로 정리하고, 목적에 맞는 리소스가 겹칠 경우 기본 색상 리소스값을 참조하도록 구분하여 구성하였습니다. primary, accent, line, options 등 대상이 되는 색상을 명시적으로 선언하고 이를 참조하는 리소스를 각각 선언하여 사용합니다.(ex, text_accent, icon_bookmark_on…) 단, 특정 컨텍스트에서만 사용될 경우에는 별도 정리하지 않고 분리하여 관리되도록 하였습니다.

목적이 명확하다면 색상값이 중복이라고 해도 관리의 용이함을 위하여 명시적으로 키를 분리하여 관리되도록 하였습니다. 그리고 색상값이 조금씩 다른부분은 리소스명 마지막에 number를 추가하는 형식으로 정리하였습니다. (text_darkgray_1, text_darkgray_2, text_lightgray_1, text_lightgray_2… 보통 회색 계통의 색상값의 경우가 이러한 케이스가 많았습니다.)

일부 색상의 경우 Light Theme와 다크모드에서 다르게 표현되어야 하는 경우가 있습니다. 예를들어, 설정의 각 메뉴의 구분선 색상이 Light Theme 에서는 회색으로 처리가 되어야 하지만, 다크모드 에서는 배경과 동일하면 되는 것으로 디자인 가이드를 받았습니다. 이런 경우 리소스 정의는 아래와 같이 처리하여 적용 되었습니다. (primary는 기본 배경색으로 사용되고 있습니다.)

참조 컬러값을 정리할 때 Light / Dark 여부와 관계없이 표현되어야 하는 부분이 있습니다. 보통 아래의 케이스에 해당됩니다.

배경에 이미 색상 / 이미지가 존재하는 영역의 뷰 색상

특정 기능 / 화면에서는 Light 테마를 그대로 사용하는 경우

첫번째의 경우 크게 두가지 케이스로 나뉘어 집니다. 텍스트를 표현하는 경우 흰색으로 표현되어야 하는 케이스가 가장 많았으며, 배경을 표현하는 경우 alpha 값이 적용된 White or Black 값을 많이 참조하고 있었습니다. 변경 가능성이 매우 희박하고, 명시적인 색상일 경우에 대하여는 SDK 내 정의된 컬러(ex. android:color/white 등)를 사용하였으며, 테마 설정과 무관한 컬러값을 정의하는 경우. values 폴더에 colorsFixed.xml 파일을 생성하고, 해당 리소스명 앞에 {fixed_} prefix 를 사용(ex, fixed_text_accent...)하여 명시적으로 관리되는 리소스로 정리 하였습니다.

Vector Drawable 리소스 정리

Vector 리소스에 color 리소스를 참조로 선언하면 minSDK 21이하에서는 아래와 같은 오류 메시지를 확인할 수 있습니다

Resources are not supported by build-time PNG generation.
File was preprocessed as vector drawable support was added in Android 5.0 (API level 21)
See
http://developer.android.com/tools/help/vector-asset-studio.html for details.

원티드 안드로이드 설치 이용자 중 5.0 미만 사용자 비율(0.25%미만)각 플랫폼별 기기 출시 버전 확인 결과 업데이트에 무리가 없다고 판단되어 이번 출시버전부터 Android minSDK가 19에서 21로 업데이트 되었습니다.

위 내용 적용 후, 각 Vector 리소스가 컬러값을 참조하게 수정하여 다크모드 적용을 하였습니다. 예를들어, icon_arrow_black.xml 리소스의 경우 아래와 같이 되어있습니다.

Tint 적용

리소스를 모두 다크모드용으로 작업하지 않고, 안정적으로 다크모드를 지원하는데 있어 ImageView의 tint attribute를 설정은 매우 유용합니다.
예를들어, 초기 실행 시 잠깐 표시되는 텍스트로 된 로고 이미지의 경우 다음과 같이 ImageView로 되어있습니다.

코드에서도 Tint는 손쉽게 가능합니다.

하지만 아래와 같은 경우, 다크모드 적용을 위한 별도 작업이 필요했습니다.

  • Custom View(or library)를 활용할 경우
  • 리소스에 배경 색상이 별도 존재하는 경우

FloatingActionButton, CircleImageView 등 UI와 관련된 일부 라이브러리의 경우 xml 상에서 tint 적용이 불가능합니다.
이러한 경우 해당 뷰 객체에 Drawable 객체에 Tint를 적용하는 것으로 작업이 가능합니다.

Tint 적용에 한계가 있는 리소스들의 경우 디자인 작업을 통해 drawable-night 폴더로 추가하여 Dark Theme 적용하면 됩니다.

Adaptive Icon

만약 Adaptive Icon을 적용하였다면 <background>, <foreground> 의 drawable 에 vector drawable을 선언하고 해당 리소스 내에서 night 리소스 컬러를 참조시켜 개발이 가능합니다. 런처에서 시스템 설정 변경 시 아이콘 리소스를 갱신해주지 않으면 이전 테마 상태의 색상값을 유지하게 되기도 합니다. (스크린 on/off를 하거나, 다국어 설정을 변경하는 등 사용자의 특정 액션에 Light / Dark 설정에 맞는 색상값으로 업데이트가 되지만, 런처마다 약간씩 차이가 있을 수 있습니다.)

Light / Dark 에서 아이콘 표현을 다르게 하여 서로 다른 브랜딩을 시도해 볼 수 있습니다.

실제 출시된 제품에 반영하는 것은 제품의 브랜딩 측면에서 분리되는 것은 적절하지 않다는 판단으로 실제 제품에는 반영되지 않았습니다. 다크모드 지원 시 디자인 관점에서 이 부분도 함께 고민이 가능하다면 사용자에게 새로운 경험을 제공이 가능할 것으로 예상합니다.

미사용 리소스 제거 및 모듈 구성 변경

원티드 안드로이드앱은 인스턴트앱을 지원하고 있었습니다. 대략적인 모듈 참조는 아래와 같습니다.

인스턴트앱의 경우에도 다크모드 적용이 가능합니다. 하지만 위 그림처럼 크게 feature_base, feature_ia, app, instantApp 의 4가지 모듈로 구성되어 있으며, 각 모듈별로 리소스를 관리하게 되어있어 위 color 리소스 정리 내용과 같이 적용할 경우, colors.xml 파일은 위 모듈 구조에 따라 구분할 경우 6개 / colorsFixed.xml 파일은 3개 (instantApp 제외) 가 됩니다.

app, wantedaia 의 경우 base의 리소스를 참조 (보통 primary, accent 등)를 하여 리소스를 정의하지만 서로 다른 모듈에서 동일한 색상값을 선언해서 사용하게 되는 등 리소스 중복 문제를 만나게 됩니다. 미사용 리소스 정리 작업을 수행하는 데 있어 Lint를 활용할 경우, app / feature_ia 에서 base 모듈 리소스를 참조하고 base 모듈 내에서는 참조하지 않는 리소스의 경우 unused resource에 체크되지 않아 주의가 필요합니다. 다크모드를 적용을 진행하면서 앞에 설명드린 이슈와 인스턴트앱을 효율적으로 활용하고 있지 못하는 이슈로 인하여 인스턴트앱 지원을 위한 모듈 구성을 하나의 모듈 구성으로 정리하였습니다.

이후 그동안 서비스 해오면서 적용되었던 미사용 리소스를 상당수 제거가 가능할 수 있었고, 결과적으로 다운로드 앱 용량은 다음과 같이 약 10%정도 개선되었습니다.

Dark Theme 적용 이전 버전 : 16.2 ~ 16.9MB

Dark Theme 적용 이후 버전 : 14.6 ~ 15.2MB

다크모드 체크 로직

원티드 안드로이드 앱의 경우, 테마가 변경될 때 Activity 는 기본적으로 재생성 되도록 되어있어, 설정 변경 시 특별한 조치를 취하지 않아도 다크모드로 화면이 갱신됩니다. Configuration.uiMode 를 이용하여 다크모드 여부 확인을 하는 로직은 아래와 같습니다.

  • Light Status Bar 처리를 위한 로직
  • multi-platform 지원을 위한 인터페이스 사용 로직 (다크모드 여부에 따른 리소스 분기 처리)

Google Map 스타일 적용

지도 영역에 다크모드 적용하는 일은 라이브러리가 스타일 적용 지원이 가능해야 합니다. 원티드의 경우 채용정보 내 근무지역 위치를 구글 지도를 활용하여 표시하고 있습니다.

구글 지도의 경우 스타일 적용이 가능합니다. https://mapstyle.withgoogle.com/ 사이트에서 원하는 스타일을 설정한 뒤 , 스타일 json 파일을 raw / raw-night 폴더에 각 테마에 맞춰 추가합니다.
이 후, GoogleMap.setMapStyle 함수를 활용하면 됩니다. 만약 구글맵 기본 속성을 사용하려면 스타일 json 파일에는 [] 만 입력되어 있으면 됩니다.

대한민국의 경우 이미 알려져있는 이슈로 인하여 스타일 적용이 되지 않습니다. 해당 이슈에 대하여 1) 한국 뿐만 아니라 다양한 서비스 지역의 채용공고를 노출하고 있으며, 2) 사용자 관점에서 사용하는데 무리가 없는 것으로 판단하여 다크모드 스타일을 적용을 하는 것으로 결정하였습니다.

아직 적용하지 못한 것

Dark Theme를 좀 더 처리하지 못한 것들은 아래와 같습니다.

  • Elevation 처리
  • 웹뷰 영역
  • 일부 UI Component (SwipeRefreshLayout 등)

Elevation 의 경우 material design component 1.1.0 부터 추가되는 colorSurface, colorOnSurface를 활용하면 되는 것으로 알려져 있습니다. 그리고 웹뷰 영역의 경우 appCompat 에서 추가된 isLightTheme, forceDarkAllowed 를 활용하면 웹 컨텐츠 색상이 반전되어 표시되는 것으로 알려져 있습니다.

글 작성일 기준으로 해당 라이브러리 버전은 design component는 1.1.0-alpha 이고 appcompat은 1.1.0-rc1 입니다. 원티드 제품의 경우 Dark Theme 적용 작업 시작 시 design component는 1.0.0, appcompat은 1.0.2 버전이며, 라이브러리 버전업에 대한 고려는 안정적으로 다크테마를 지원하는 것을 목표로 진행하였고 Dark Theme 제공에 있어 크리티컬한 이슈는 아니라고 판단되어 각 라이브러리들이 정식 출시 된 이후에 개선을 해보려고 계획중입니다.

마치며

다크모드 적용 과정에서 서비스 사용성이 좋다는 피드백이 인지를 코드레벨에서 확인하는 것을 경험하는 재미있는 과제였습니다. 또, 기존에 오랜기간 방치해뒀던 리소스네이밍 정리, 미사용 리소스 정리, 기존에 적용된 이미지 중에서 배경이 투명한 리소스 등이 다크모드 작업 진행간에 잘못 작업된 케이스를 찾는 등 완성도 높은 제품개발을 위한 작업을 잘 마무리 한 것 같아 좋은 경험이 되었습니다.

특히 다크모드 적용 기간동안 여러가지 화면 및 기능들을 직접 사용해보면서 다시 야간모드 off를 하지 못하는 스스로의 모습을 보면서 왜 다크모드 지원을 구글에서 강력히 권하는지 이해할 수 있었습니다. 개인적으로 많은 서비스들이 다크모드를 지원해주기를 기대해 봅니다.

원티드에서는 다양한 직군에서 적극적으로 채용중입니다! 서버, 웹, 앱, 디자인 등 제품을 만들어가는 각자의 분야에서 전문적인 분들과 함께 일하기를 기대하고 있습니다. 회사 채용 정보 페이지를 확인해 주세요!

--

--