ライブラリ・SDKにSwiftLintを導入するベストプラクティス


ライブラリ作るの、楽しいですよね。
作ったからには、沢山の人に使ってもらいたいですよね。
そして、ソースコードをきれいに保つためにSwiftLintも使いたいですよね。
でも、環境によってSwiftLintがErrorを吐いて使われなくなる、とかは避けたいですよね。
というわけで、そのあたりをまとめてみました。

なぜまとめたか

今関わっているプロジェクトで以下の現象に遭遇したために、掘り下げてみました。

  • mixpanel-swiftを導入
  • SwiftLintを0.13.2 > 0.15.0 にアップデート
  • carthage update --platform iOS --no-use-binaries が通らなくなる
  • ふむ🤔

SwiftLintバージョン違い問題

上記の現象について詳しく調べてみたところ、

  • mixpanel-swiftが想定するSwiftLintのバージョン:
    • 0.13.2
  • ローカルのSwiftLintのバージョン
    • 0.15.0

と想定するSwiftのバージョンに差異があったために引き起こされていたことがわかりました。
つまり、いつものこいつによって、引き起こされていたのです。

どう解決できるか?

自分でもPlayListPlayerなどのライブラリを開発しているため、この件について色々と考えてみました。

例えば、

  • SwiftLintのScriptを削除する
    • SwiftLintが手軽に実行できなくなるため、ダメ🙅
  • swiftlintに対してエイリアスを設定(上記の例であれば、mixpanel-swiftlint等)
    • 悪くはなさそう。
  • ライブラリのリポジトリにswiftlintのバイナリを追加
    • swiftlintのバージョンが固定されるのは良いが、そもそもライブラリのリポジトリに追加すべき?

などなど。

岸川さんからのアドバイス

ただ、何かしっくりこないなーと思いつつ、つぶやいたところ、


岸川さんからアドバイスが!

SwiftLintを別ターゲットに分ける?なるほど、わからん🤔


なるほど、SwiftLintのScript Phaseのみを含むターゲットを作ればよくて、
Realmプロジェクトにその実装があると。

Realmのプロジェクト構成を確認

普段あまり使わないような形でSwiftLintがターゲットとして独立して追加されていました。

調べてみたところ、ターゲットの追加 > Cross-platformで選択できるAggregateというものを使っているようです。

Aggregateとは

Xcode Target Aggregateで検索してみましたが、公式ドキュメントは見つけられませんでした。。。
他で探したところ、こちらが参考になりました。
要約すると以下のようになります。

  • 直接、何かをビルドするものではない
  • 他のターゲットのビルドステップを整理する手段として役に立つ
  • run scriptscopy filesなどのような追加的なBuild phasesに対処する時に特に役に立つ。

SwiftLintではrun scriptsを追加することになりますので、ぴったりです。

実際に導入

PlayListPlayerに実際に導入してみました。
導入手順としては
1. ターゲットの追加 > Cross-platform > Aggregate を選択
2. Run Scriptを追加し、SwiftLint実行用のコードを追加

するだけです。
これによって、SwiftLintのBuild Schemeも追加され、独立してSwiftLintを実行できるようになります。

テスト時にのみ実行

以上の実装では、Lint用Targetを選択しないとLintが実行されないため、
メインターゲットの選択中、かつテスト時にのみ(🙅ビルド・アーカイブ時)実行されるように設定します。
以下のように設定するだけです。

まとめ

アプリのプロジェクトと違い、ライブラリでは効果的なLintの実行方法が異なることがわかって頂けたかと思います。
是非、ご自身のライブラリにも適用してみてください!

参考