LoginSignup
21
21

More than 5 years have passed since last update.

独自のライブラリ(.framework)を組み込んで苦労した話

Last updated at Posted at 2019-03-20

iOSプロジェクトにライブラリを導入する時、
多くの人は Cocoapods or Carthage を用いると思います。

しかし先日、やむを得ず
どちらのやり方もできないライブラリを導入する機会がありました。
この導入に際して、たくさんのエラーとぶつかったので、記録として残します。
※以下そのライブラリを、仮名 R.framework と称すことにします。

前提

frameworkとは

そもそもframeworkとは、いくつかのリソースを1つまとめたパッケージで、
Projectファイルに埋め込むことで、framework内のリソースを
Projectで使えるようになります。

※参考:

参考文献で分かりやすいと思った一文:

Frameworkとは、動的共有ライブラリや nibファイル、イメージファイル、ローカライズファイル、ヘッダファイル、ドキュメント等のリソースファイルを1つのパッケージにまとめたディレクトリ

今回のケース

R.framework は自作ではなく、知り合いの方が作成したもの。
自分の扱うProjectに一度cocoapodsで導入して、ビルド成功させます。
そこで生成できた R.framework を用います。
cocoapodsで導入すると不都合がことがあったというレアケースだと思います。

開発環境

OS: Mac
Xcode: v10.1

こうやればできるはず

まず、ぼくが試した正常パターンであろう手順を説明します。

1. 自分のProjectにpod install&ビルド成功

本当に導入したいProjectでも、自身のサンプルProjectでもよいですが、
一度pod installで R.framework を導入します。

$ bundle exec pod install

※自分の場合、bundlerでcocoapodsのバージョン管理してるので上記コマンド。

pod install完了後、Xcodeで MyProject.scworkspace を立ち上げ、
ビルド成功させます。

2. R.frameworkを取得

ビルドを成功させたら、Xcodeの設定ファイルを開いて、
下記の矢印ボタンを押します。Finderが開きます。

DerivedDataというフォルダが開かれます。
このDerivedDataとは、いわゆるXcodeのキャッシュです。
普段は、Xcodeを完全にクリーンするときに削除するものですね。

このDerivedData上に R.framework が生成されます。
階層は下記。

DerivedData/MyProject-{ランダム文字}/Build/Products/Debug-iphonesimulator/R/R.framework

これで R.framework の取得完了です。

3. R.frameworkをProjectに埋め込む

R.framework をProjectファイルにドラッグ&ドロップします。
※今回は FunctionConfirm Projectに導入してみます。

するとこんな感じのポップアップが出てきます。

Projectフォルダに R.framework ファイルを保存した方がよいので、
Copy items If needed にはチェックを入れておきましょう。
※チェックを入れ忘れた場合は、あとで Build Phases>Copy File で設定すれば同様のことができたりします。(詳細省略)

R.framework をドラッグ&ドロップした箇所に入れるだけなら、
Create folder references のままに、Groupに入れたい場合は、
Create groups にチェックします。

Targetはよしなに必要なものを選んでおいて、Finishボタンを押します。

4. Embedded BinariesにR.frameworkを追加

つまり、 FunctionConfirm プロジェクトに埋め込むファイル一覧に、
R.framework を追加するということです。

General>Embedded BinariesR.framework を+します。

5. 重複するR.frameworkを削除

上記4を行うと、下の Linked Frameworks and Librares に、
R.framework が2つあることが分かります。

3の操作と4の操作で、計2回追加されてしまったんですね。
複数ある必要は特にないので、片方を削除しておきます。

6. ビルドで完了

ビルドして成功すれば完了です。
コード内で import R ができるようになります。

本題:困ったこと

ここからが本題です。出くわしたエラーたちを紹介していきます。

そもそもpod install&ビルドできない

エラーログ:

ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

エラー見ても分からない、なんやねん...

原因と対処

そもそもcocoapodsのバージョンがダメでした。初歩的...
実は $ bundle exec pod install ではなく、
$ pod install をやっちゃっていたんですね...

bundlerでcocoapodsを管理していないと、
勝手にcocoapodsのバージョンが最新になってしまいます。
R.framework が最新のcocoapodsに対応していませんでした。

cocoapodsのバージョンをbundlerで管理するように変えました。

Pods参照できない

エラーログ:

/Users/XXX/XXX/XXX/XXX/Pods/Pods/Target Support Files/Pods-XXX/Pods-XXX.debug.xcconfig: unable to open file

なんやねん...
Pods/Pods ってなんやねん...

原因と対処

cocoapodsをダウングレードすると起きる現象らしいです。
project.pbxprojファイル内に、

name = Pods;
path = Pods;

という記述を見つけました。これか...
片方消したらビルド通るようになりました。

※参考:

R.framework見つからないとか言われる

R.framework を埋め込んでビルドしようとしたときのエラーです。

エラーログ:

ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

※エラーログちょっと違うかも...とりあえずnot foundがあったのは確実。

ちゃんと Embedded Binaries したのになぜ...

原因と対処

Target複数あったのを忘れていました :innocent:
自分あほ...
Targetが複数ある場合は、どのTargetの Embedded Binaries にも
R.framework を追加する必要があります。

自分が設定したTargetの Embedded Binaries に設定してなかった
だけだったので、修正したらエラーは直りました。

Simulatorではビルドできるのに実機だとできない

今回ぼくが一番悩んだエラーです。

warningログ:

ld: warning: ignoring file /Users/.../R.framework/R, file was built for x86_64 which is not the architecture being linked (arm64): /Users/.../R.framework/R

エラーログ:

PhaseScriptExecution failed with a nonzero exit code

R.framework ファイルなんか無視されるし、
権限上のなにかしらでダメらしい...
ぼくが悪かったなら謝るから、何が悪かったか教えてくれよ...

※参考:

状態を確認する

教えてくれないなら、こちらから調べにいくしかありません。
調べていたら、 arm64 やら x86_64 というのは、
iOS・tvOS・watchOSデバイスのアーキテクチャであることが分かりました。

この記事の表がとても参考になりました。

Simulator(x86_64)はビルドできるけど、実機(arm64)はビルドできない...
もしかして、R.framework がx86_64はサポートしているけど、
arm64はサポートしてない的な...という仮説を考えました。

実際に調べてみます。
$ xcrun lipo -info [binary] を使えば、
サポートしているデバイスアーキテクチャが調べられるとのこと。
※参考:https://teratail.com/questions/61071

別の有名なライブラリ Perfect.framework と比べてみました。

$ xcrun lipo -info Perfect.framework/Perfect
Architectures in the fat file: Perfect.framework/Perfect are: i386 x86_64 armv7 arm64

やはりPerfect。i386、x86_64、armv7、arm64をサポートしていました。
続いて R.framework を調べてみます。

$ xcrun lipo -info R.framework/R
Non-fat file: R.framework/R is architecture: arm64

...!?

原因

原因は、「R.framework が実機をサポートしていなかったから」でした。
なぜこんなことに。。。ふと、気付きました。

このDerivedData上に R.framework が生成されます。
階層は下記。
DerivedData/MyProject-{ランダム文字}/Build/Products/Debug-iphonesimulator/R/R.framework

... Debug-iphonesimulator/ だと...!?

そうです、この R.framework はSimulator階層にあったもの。
だからSimulator専用の R.framework だったのです。

無事、ぼくが悪いことが判明しました。ごめんなさい。

対処

謝るのは簡単ですが、それでは何も解決しません。
対応策として考えられるのは、
「Simulatorも実機もサポートしている R.framework を作成すること」
です。

MyProject.scworkspace のビルドを実機を対象に行うと、
DerivedData/MyProject-{ランダム文字}/Build/Products/Debug-iphoneos/R/
階層に R.framework が見つかります。

しかし、これは逆に「実機しかサポートしていない R.framework 」です。
これでは実機でビルドできるだけで、根本の解決にはなりません。

この記事によると、
Simulatorも実機もサポートしているframeworkを、
Universal Framework と呼ぶことが分かりました。これを作ればいい...!!

...

_人人人人人人人人人人人人人_
> 作り方がわからない <- NOW <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄

frameworkを自作していた場合の Universal Framework
の作り方は調べて分かりましたが、今回は知り合いの方が作った場合なので、
自分ではどうすれば良いか分かりませんでした(:3」∠)
※やり方分かる方いましたら教えてくださいm(__)m

今回は、知り合いの方に Universal Framework の作成を依頼しました。

※Framework作成系参考:

まとめ

以上、独自のライブラリ(.framework)を組み込んで苦労した話でした。
今回自分がエラーを対処するために気をつけたポイントは下記。

  • エラーログを見る
  • 状態を確認する
  • ググる

そしてライブラリの扱いの件について思ったまとめは下記。

  • cocoapods等で取得したライブラリを無闇に.frameworkにしない
  • というか、ライブラリはcocoapods等で取得したまま利用する
  • 知見として、自分でライブラリ作る経験は必要ですわ...

以上です。

※その他参考:

21
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
21