おぼえがき

アウトプットで知識を体系化していきます

Embedded Frameworkの導入の検討 / firefox-iosの例

f:id:taku_oka:20170821020210p:plain

個人的なアプリでは導入してみていますが、途中から入った現在のプロジェクトでも導入を検討しているので、色々と整理してみました。

Embedded Frameworkを取り入れる利点

ビルドパフォーマンスの改善

EmbeddedFrameworkを導入することで差分コンパイルが効きやすくなるため、ビルドの時間を減らすことに大きく貢献します。

そのためビルド時間短縮の有効な手段の1つとしてよく取り上げられています。

本格的なiOS開発では、ビルドパフォーマンスを意識せずに開発を続けていくと大抵の場合フルビルドに8分~15分くらいかかるようになっていきます。しかもメソッドを1つ追加するだけでも全体をビルドし直しになったりします。

Swiftはコードが増えてくると凄く生産性が悪くなるのでビルド時間の短縮化は開発者の間でよく取り扱われるテーマの1つとなっています。

ウィジェットなどとの間で機能を共通化できる

iOSアプリ本体に加えて、ウィジェットやシェア拡張などのAppExtensionを開発する場合やiPad向けアプリやAppleTV向けアプリやWatch向けアプリを開発する際、ビルドターゲットはアプリとは別になります。

ターゲットの切り分けをしていない場合、 TodayウィジェットからAPIを叩く必要があるときは、アプリのコードを使用することができず、結果、二重にAPIへのリクエスト部分を実装することになってしまいますが、 機能がEmedded Frameworkとして切り離されていればアプリとウィジェット間で共通の機能を使うことが出来ます。

コードがキレイになる

依存がはっきりとわかれて、名前空間も別れるので簡潔なコードが書きやすくなります。

ターゲットを分けずにアプリ開発している場合はアクセス修飾子のinternal / public の違いがなくなりますが、 フレームワーク内ではinternal/publicが意味を持つようになり、より安全に分かりやすく開発していくことが可能です。 ターゲット内でのみ使えるinternalなクラスを作ったり、外部に公開するクラスやメソッドを限定的にしてモジュールを使いやすく分かりやすいインターフェイスにしていけます。

Embedded Frameworkの作り方

参考になりそうな記事を貼っておきます。

Embedded Frameworkを導入してXcodeのビルドパフォーマンスをあげる - VASILY DEVELOPERS BLOG

Embedded Frameworkの分け方の例

以下のように層ごとで分けることが多いかと思います。

メインターゲット

Embed Framework

  • Util (全体で使う汎用的な機能やExtensionなど)
  • APIClient
  • Model
  • in-App-Purchase機能

mozilla-mobile/firefox-ios の例

mozilla-mobile/firefox-ios

embed frameworkを取り入れている例として firefox-iosオープンソースプロジェクトをざっくり観察してみました。

ターゲットのわけ方

f:id:taku_oka:20170821020346p:plain:w300

メインターゲット

  • Client(iOSアプリ)
  • ShareTo(ShareExtension)
  • Today(TodayExtension)
  • NotificationService(NotificationExtension)
  • SendTo(ActionExtension)
  • ViewLater(ActionExtension)

Embed Frameworks

  • Shared: 汎用的なextensionやUtil系クラス
  • Storage: ブックマークなどの永続化層?
  • Account: アカウント管理?
  • Sync: ブックマークなどの同期?
  • ReadingList: リーディングリストの管理?
  • Telemetry: 効果測定?

Model,APIClient…というふうに層で分けるのもいいですが、firefoxのように機能ごとに分けるのもよさそうですね。

ライブラリの管理をどうしているのか

f:id:taku_oka:20170821020408p:plain

Carthageで取得してきたframeworkたちが一番上の階層のFrameworksフォルダにまとめられており、各ターゲットがおのおの必要なフレームワークを取り入れていました。

具体的には各ターゲットの”Linked Framewoks and Libraries”, ”Linked Binary with Libraries” に使用するframeworkを追加して、使用しているファイル内でimport文を追加しています。

f:id:taku_oka:20170821020430p:plain

EmbedFrameworkを使いすぎると起動が遅くなる件について

EmbedFrameworkを使いすぎると起動が遅くなるそうです。 (参考資料: More Swift App Startup Time)

つまりEmbedFrameworkを使用してビルド時間を短縮することとアプリの起動時間が伸びるのはトレードオフとのこと。 (参考資料: iOSプロジェクトのBuildを高速化する)

しかし実際 firefoxのアプリの起動時間を体感してみたところそこまで起動の遅さが感じられなくて安心しました。 むしろ平均以上の速さのように感じました。

firefoxのEmbeded Frameworkの数

  • 外部framework 23個
  • 内部framework 6個

このframework数でiPhone6sで250msほどで起動していました。

firefoxのEmbeded Frameworkの数は少なくもなく多くもなく通常のアプリ開発はこのくらいの数になると思います。

これで充分に起動時間が速いので、過剰な数のEmbeded Frameworkを使いさえしなければ起動時間の伸びについては特に問題になることはなさそうだと思いました。

まとめ

Embeded Frameworkは利点が多く、ウィジェットの開発を視野に入れていたりビルド時間を肥大化させたくない場合は早めに導入できると良さそうだと思いました。

firefox-iosは Embed Frameworkを活用している例としては貴重で参考になりました。 大手のプロジェクトでEmbed Frameworkを活用した例があると安心感があります。 僕の会社でも最近のiOSプロジェクトはEmbed Frameworkを導入いる例がいくつかあるので参考にしてみたいと思いました。

導入時期の検討

Embed Frameworkの導入はアプリ開発が進むほどにコストが高まっていきます。

僕のアプリの場合はリリースが近くなってしまったので、今導入するとデグレの危険性があるためリリース直後くらいに行えたら良いなと思っています。