TL;DR
Provide a means to set the bundle identifier in the podspec for generated frameworks #3032
CocoaPodsで配布するライブラリでリソースバンドル(NSBundle
)を取得する必要がある場合はbundleForClass:
(Swiftではinit(forClass:)
)を使いましょう。というお話。
ライブラリのリソースバンドルを取得する
CocoaPodsで配布するライブラリにおいて、そのライブラリのリソースバンドル(NSBundle
)をコードから取得することがあります。
アプリ側のコードではたいていメインバンドルを取得すればOKですが、ライブラリのリソースバンドルはアプリのメインバンドルと同じとは限らないため、正しいバンドルを取得しなければなりません。
メインバンドル以外のバンドルを取得する方法はいくつかあります:
- URLを指定する (
+ bundleWithURL:
,- initWithURL:
) - パスを指定する (
+ bundleWithPath:
,- initWithPath:
) - バンドルIDを指定する (
+ bundleWithIdentifier:
) - バンドルに含まれるクラスを指定する (
+ bundlerForClass:
)
このうち、上の2つは、ライブラリのバンドルのパスやURLを取得するのがそもそも面倒くさそうです。
バンドルIDを指定する方法は一見正攻法に見えますが、上記のIssueでも議論されている通りこの方法は問題があります。
バンドルIDが一意に定まらないのです。CocoaPodsではライブラリをモジュールを使用せずにインストールした場合はアプリのバンドルIDになりますが、モジュールを使用(Podfileでuse_framworks!
を指定)してインストールした場合は、モジュールごとにバンドルIDが割り振られます。
さらに、モジュールに限定したとしてもCocoaPodsは各モジュールに対して、ライブラリのプロジェクトの(開発者が指定した)バンドルIDではなく、org.cocoapods
で始まるバンドルIDを勝手に割り振ります。
このバンドルIDをコードに書いてしまうと、CocoaPodsの仕様が変わったときに生成されるバンドルIDがコードで指定するバンドルIDと一致しなくなる可能性がありますし、CocoaPodsを通さず配布する場合もプロジェクトのバンドルIDをCocoaPodsに合わせなければならなくなります。
結局のところ、上記のIssueでも書かれている通り、バンドルに含まれるクラスを指定するのが確実であると言えそうです。
クラスはいずれかのバンドルに含まれているはずなので、ライブラリ内のクラスを指定すれば目的のバンドルを取得できるはずです。
例
ライブラリ内のクラスのインスタンスメソッドから:
let bundle = NSBundle(forClass: self.dynamicType)
NSBundle *bundle = [NSBundle bundleForClass:[self class]];