hiragram no blog

iOSとか

ビルドターゲットがフレームワークの時にCommonCryptoをimportしたい

この記事はSwift Advent Calendar 2016の2日目です。

TL;DR

結局イケてる解決はできませんでした

前提

  • UIにかかわらない部分を切り離すため、Embedded Frameworkの仕組みを用いてモデル層を別モジュールにした
  • API通信時にSHA256でトークンを作ってるところがある
  • 切り離し前はアプリターゲットのBridging-headerでCommonCrypto.hを読み込んでいた
  • フレームワークがターゲットのときにはBridging-headerが使えない(仕様)
  • どうしよう

やりかた1: modulemapを自分で書く

[Swift] FrameworkプロジェクトにCommonCryptoをインポートする

これを真似てやったんだけど、Header Search Pathsに$(SDKROOT)/usr/include/CommonCryptoを足してもビルド時にヘッダを見つけてもらえずにコケていた。しばらくコレにしがみついたけど解決しなそうなので次のやり方に。

やりかた2: modulemapに書いてあるヘッダのパスをBuild Phase内で動的に書き換える

やりかた1をいじいじする中で、相対パスで指定するとヘッダを見つけられずにコケるが、絶対パスで指定するとコンパイルが通ることがわかった。

そこで、フレームワークのビルド手順の一番最初に、modulemapに絶対パスを書き出すようなスクリプトを書いた(べた書きだと人によってパスが違うから)。

しかし、直列に実行されている(はず)のビルド手順で、modulemapに書き出した直後の手順でその書き出しが反映されていない事があり、(sleep 10とかやると通る)成功したり失敗したりするのでCIを通せずにボツにした。

やりかた3: modulemapに絶対パスを書き出すところを独立したターゲットにして一番最初に動くようにする

ソースもヘッダもない、Run scriptだけがあるターゲットを作って、すべてのモジュールがそれに依存するように設定した。

これにより、そのターゲットが一番最初にビルドされるようになり、modulemapの書き換えもうまく反映されるのでは、と思った。

が、「ビルドキャッシュがない状態では必ずビルドに失敗する」とかいう状態になったので諦めた。

やりかた4: SDKROOTからヘッダファイルをコピーしてきてプロジェクトに直接突っ込んだ状態でCommonCryptoのフレームワークをビルドする

結局これかという感じになってしまった。

相対パスで探せないなら探せる場所に物理的にコピーしてしまえばいいということで、CommonCrypto用のXcodeプロジェクトを作って、そこにヘッダをコピーしてきて、$ carthage bootstrap --no-skip-currentでビルドした。

Allow non-modular ほげほげみたいなのをYESにして、各種ヘッダをpublicにして、アプリのプロジェクトに組み込んだら、ビルド通った。

結論

結局いけてない解決になってしまった感はあるものの、余計なworkaround(CIを通すために、一旦ビルドキャッシュを作るための100%コケるビルドをしてから本番のビルドをする、みたいな)を解消できたのは良かったのかな、とおもう