iOSアプリで共通UIクラスを使うための仕組み

この記事はMERPAY TECH OPENNESS MONTHの17日目の記事です。

メルペイiOSエンジニアの@masamichiです。 メルペイで導入している、 iOSアプリで共通UIクラスを使うための仕組みについて紹介します。

背景

メルペイでは、メルペイの機能をSDKとして開発してメルカリアプリに組み込んでいます。SDKにはメルペイで横断的に使用する基本的なUIクラスがあります。例えばメルペイでは統一してテキストラベルの色に #000000 ではなく #333333 を使っていますが、その色を使ったUILabelのカスタムクラスをPrimaryLabelとして定義しています。他にもUIButtonでは、MercariPrimaryFilledButtonMercariSecondaryOutlinedButtonといったクラスを定義しています。

f:id:masamichiueta:20190607104300p:plain
UIクラス

LabelButtonといったベースとなるクラスを定義し、継承したクラスでプロパティをカスタムできるようにしています。

import UIKit
@IBDesignable
public class Label: UILabel {
public override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
public override func awakeFromNib() {
super.awakeFromNib()
setup()
}
public override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setup()
}
func setup() {
font = font.mp.toPrimaryFont()
}
}
public final class PrimaryLabel: Label {
override func setup() {
textColor = UIColor.mp.sumi
}
}

storyboardやxib、コードでViewを開発する時にはデザインを統一するためにこれらのクラスを使用する必要がありますが

  • そもそもそんなクラスがあることを知らない
  • すでにUIがあることを知らずに自作してしまう場合がある
  • storyboard, xibでカスタムクラスを適用するのを忘れてしまう

といった課題がありました。これらの課題を解決するために2つの仕組みを作りました。

仕組み1 UIカタログの作成

どういうUIクラスがあるのかを簡単に確認できるようにするために、SDKのサンプルアプリにUIカタログのページを作りました。
プロジェクト内にクラスが定義されているだけだと、実際にどのような見た目のクラスなのかがわかりにくいということと、コード量が多くなるとそもそもそのクラスの存在に気づくのが難しくなります。
SDKには各フレームワークをメルカリにインテグレーションする前に確認するためのサンプルアプリを作っていますが、そこに共通のUIクラス一覧を表示しました。

f:id:masamichiueta:20190607104629p:plain
UIカタログ

このUIカタログを見れば、各UIクラスをすぐに確認できるので、

  • そもそもそんなクラスがあることを知らない
  • すでにUIがあることを知らずに自作してしまう

といった課題を解決しやすくなりました。

UIカタログによって各クラスの確認はしやすくなりましたが、それだけだとxibでカスタムクラスをセットし忘れるという課題は解決しません。そこでさらにLinterツールを導入して、自動で検出する方法を考えました。

解決策2 Linterツールの導入

storyboard, xibのUIにカスタムクラスが使用されるかを自動で検出するLinterツールを導入しました。

開発者が忘れずにカスタムクラスを使ったり、コードレビューでカスタムクラスが適用されているかを確認するという運用ではセットし忘れを完全に防ぐということはできません。抱えていた課題を解決するには、自動でクラスの設定し忘れを検出する仕組みが必要でした。そこでIBLinterというstoryboard, xibを検査するLinterツールを導入しました。

IBLinterはプロジェクト内のstoryboard, xibファイルを解析し、指定したルールにしたがってエラーや警告を表示してくれます。プロジェクトの Run Script Phase で実行することで、ビルド時に自動でチェックすることができます。

導入検討時にはIBLinterには特定のカスタムクラスが適用されているかを検査するルールがなかったので、UseBaseClassRuleという新しいルールを作りました。

PRはこちらです → https://github.com/IBDecodable/IBLinter/pull/84
Use Base Class Rule by masamichiueta · Pull Request #84 · IBDecodable/IBLinter · GitHub

このルールでは、特定のUIクラスに設定ファイルで指定したカスタムクラスが適用されていないとビルド時にXcodeで警告がでるようになっています。
例えば、UILabelPrimaryLabelもしくはSecondaryLabelというクラスが適用されるべき場合は、設定ファイルの .iblinter.yml に以下のように設定します。

.iblinter.ymlの設定

use_base_class_rule:
- element_class: UILabel
base_classes:
- PrimaryLabel
- SecondaryLabel

この状態でカスタムクラスが使われていないラベルが存在するとビルド時に警告が表示されます。

f:id:masamichiueta:20190607104803p:plain
UseBaseClassRule

サンプルを作ったので参考にしてみてください。

https://github.com/masamichiueta/UseBaseClassRule

どこまでこのルールを適用すべきかは難しいところですが、全体に使うラベルや、サービスで統一されているボタンなどで使うのがおすすめです。メルペイではUILabel, UIButton, UITextFieldにこのルールを適用しています。
このルールを導入してからは、既存のxibで漏れていたものを全て置換することができました。

終わりに

メルカリ・メルペイではテックカンパニーらしく、このようにアプリ開発で様々な自動化を取り入れて課題を技術や仕組みで解決しています。
メルペイではミッション・バリューに共感しているiOSエンジニアを募集しています。一緒に働ける仲間をお待ちしております。

mercari.workable.com

明日、MERPAY TECH OPENNESS MONTH の 18日目の記事はメルペイ iOSエンジニア の@celia による「Introducing ViewModel Inputs/Outputs: a modern approach to MVVM architecture」です。iOS2連続です、お楽しみに!!!

  • X
  • Facebook
  • linkedin
  • このエントリーをはてなブックマークに追加