🌜

LUUPアプリのダークモード対応をした話

2024/11/05に公開

こちらの記事は、LUUP のTVCM放映に合わせた一足早い「Luup Developers Advent Calendar 2024」の5日目の記事です。

はじめに

こんにちは!iOSエンジニアとして、Software Development部でLUUPアプリを開発している @tsuboyan5 です。

LUUPアプリは今年5月、ダークモード対応を行いました。本記事では、この対応にあたってiOSアプリへの実装視点で考慮したこと・どのような手順で対応を進めたかなどについて解説します。

▼ ダークモード対応時のX上での告知

https://x.com/Luup_Official/status/1791053920535773603

ダークモードについて

iOS のダークモードは、2019年にリリースされた iOS 13 から搭載された外観を変更できる機能です。ダークモードを有効にすると、周囲が暗くても画面が見やすくなり、さらにアプリの電力使用量の抑制にもつながります。
OS側でのライト・ダークモードの切り替えは、設定 > 画面表示と明るさで行うことができます。

LUUP におけるダークモード対応

背景

LUUPアプリにおいては、一部地域で試験的にナビ機能[1]を提供していることもあり、画面の見やすさは重要だと考えています。
特に夜間においては、ダークモードに対応することで、目にかかる負担を極力減らし運転への集中を保つことにつなげられます。

これを徹底するために、LUUPではユーザの設定にかかわらず、ライド中は昼間はライトモード、夜間はダークモードに自動で切り替わる仕様としています。
参考までにですが、Google Maps といったマップアプリのナビについても、これに近い挙動となっているようです。

ライトモード ダークモード

LUUPアプリのライトモードとダークモード時の表示

ダークモード対応

ここでは、LUUPアプリのダークモード対応を完了するまでにたどったいくつかのステップをご紹介します。基本的な流れとしては、

  1. ライト・ダーク両方の色定義を含むカラースキームの定義 (by デザイナー)
    1. のカラースキームを、アプリの全てのコンポーネントに適用する (by エンジニア)

となります。

Step1. 準備

LUUPアプリで使用するカラーアセットは、デザインツールの Figma で定義されており、アプリ側でも同じカラーアセットがアセットカタログ(xcassets)に登録されています。そのため、Figma上で定義されたカラーアセットにダークモードの色を設定するだけで対応できると考えていましたが、実際にはいくつかの課題が発生しました。

  1. 色名(例:themeBlack)がついたカラースキームが、ボタンやテキストなど主要コンポーネントの色として指定されており、ダークモードでは意味が通じなくなる部分があった
  2. コード内で色が直指定されている箇所や、APIから色情報を直接取得して表示する箇所が存在していた

これらの課題を解決するために、カラースキームを意味に基づいた命名へ刷新し、この新しいカラースキームを全ての画面のUIコンポーネントに反映していく必要があります。
また、コード側で直指定されている色や、サーバーから色を直接受け取って表示している箇所については、新しいカラースキームの色を当てる方向で仕様の調整を行いました。

Step2. 実装

準備が整ったところで、実装を開始しました。新しいカラースキームを、アセットカタログに追加して、この色をすべての画面のコンポーネントに反映していきます。


新しく定義したアセットカタログ

マップ画面、メニュー画面、検索画面、会員登録フローなど、50以上ある画面のコンポーネント一つひとつに新しいカラースキームを適用していく地道な作業で、何度か日が暮れました。🌄

動的な外観切り替えへの対応
UIColorで設定された色については、Assets Catalogにライト・ダーク両方の色を定義しておくことで、アプリ利用中に外観が切り替わった際にも自動で反映されます。ただし、UIViewlayer.borderColor などの CGColor で指定されている色や、外観によって切り替える必要がある画像は、ライト・ダークモードの切り替えに自動で追従しません。

そこで、下記のように UIViewControllertraitCollectionDidChange メソッドで、外観の変化を検知して、色の指定を更新する処理を追加しました。(iOS 17以降であれば、registerForTraitChanges の利用が推奨されています)

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
        // 外観に変化があった時の処理
    }
}

この実装により、外観が切り替わるタイミングで色を適切に更新し、ユーザーにとって一貫した表示が提供されるようになりました。

Step3. QA

今回の対応では、ほぼすべての画面に手を加えたため、通常よりも厚めに品質保証を行い、フルリグレッションテストを実施しました。その結果、細かな色指定の漏れがいくつか見つかりましたが、大きな問題は発生せず、無事に実装を完了できたと思います。

しかし、今後はライトモードに加えてダークモードのテストも必要になるため、単純計算では品質チェックをする必要のある画面数が倍増して品質保証の負担が大きくなってしまいます。この負担を軽減するため、バージョン間での画面差分を自動または半自動でチェックできるスナップショットテストの拡充を進めています。

おわりに

やはりコード内で直で色を指定したり、Asset Catalog でダークモードを想定しない使い方をしていると、後々苦労するな〜とは感じましたが、この規模のアプリの割には大きなトラブルなく対応を終えられたかなと思います。
今後、新しいアプリを作る際は、ダークモードも見越した上で、色の定義をしておくと良さそうです。

今後もアプリチームとしては、OSの機能を活かしながら、ユーザーの利便性や安全性を向上させる開発に取り組んでいきたいと考えています。
最後までお読みいただき、ありがとうございました!

宣伝

Luup では、一緒に開発してくださるソフトウェアエンジニアを積極的に募集していますので、採用情報もぜひ、ご覧ください!
https://recruit.luup.sc

一足早い「Luup Developers Advent Calendar 2024」もまだまだ続きますので、よろしくお願いします!

参考

https://developer.apple.com/jp/design/human-interface-guidelines/dark-mode

脚注
  1. Luup、利用者の安全な走行をサポートする「ナビ機能」の試験提供を開始 ↩︎

Luup Developers Blog

Discussion