App Extensionを実装する際,本体のアプリとコードを共有したいことがあります. コード自体をExtensionのターゲットに追加することもできますが,メンテナンス性や複数のアプリで使い回すことを考慮すると,Embedded frameworkとして実装し,各々で取り込むのが理想的です.
しかし,ここで注意する点があります.
Extensionでは通常のアプリと違い,いくつかのAPIへのアクセスが禁止されています.
例えば,ExtensionからUIApplication
などのAPIにアクセスすることができません.
不意にframeworkのコードでこれらのAPIを仕様すると想定の通り動きませんので注意が必要です. そこで,安全にframeworkを共有するためにAllow app extension API onlyというオプションが存在します. (TARGETS > Deployment Info > App Extensionsから指定します.) この設定を有効にすると,framework内のコードで違反をしているときにビルドエラーを発生させることができます. 詳細は以下のドキュメントを参照してください.
CocoaPodsを使うと警告が発生
frameworkに切り出すと独立性が高くなるため,本体のプロジェクトとリポジトリを分けることが可能になります.
すると,その取り込みには当然CocoaPodsのようなツールを使いたくなります.
幸いCocoaPodsには0.36よりframeworkのbeta supportが追加されました.
podspecを追加し,pod install
を実行すると,linking against dylib not safe for use in application extensions
という警告が発生します.
この警告は前述した,Allow app extension API only
オプションが有効でないframeworkをExtensionに取り込んだ場合に見ることができます.
Allow app extension API only
を有効化したframeworkを取り込んだ場合でもこの警告は発生します.
これはCocoaPodsのアーキテクチャに起因する問題です.
CocoaPodsはPodを読み込む際,必要なファイルを取り込み,新たにプロジェクトやターゲットを生成して親プロジェクトに埋め込みます.
その際,元のプロジェクト設定を引き継いでくれませんので,生成されたframeworkのAllow app extension API only
はデフォルトでNO
になってしまいます.
CocoaPodsのframeworkサポートは追加されたばかりなのもあり,この設定をいじるためのAPIは設定は存在しません.
post_install
でAllow app extension API only
を有効にする
警告が出たままでは困るのでpost_install
で設定を書き換えます.
Podfileに以下のようなスクリプトを追加します.
post_install do |installer_representation| installer_representation.project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'YES' end end end
残念ながらpost_install
で変更することは本質的な解決とはいえません.
本来この設定自体はframework側に設定されるものなので,依存する側.
しかし,最近出てきたCarthageであればframeworkそのものを利用する設計なので特に困ることがないと思います..
後発だけあってframework時代に合った仕組みですね.
CocoaPodsよりイケテル感があります.
雑談コーナー
config.build_settings['APPLICATION_EXTENSION_API_ONLY']
にBooleanを代入していてプロジェクトがぶっこわれました.
参考
- App Extension Programming Guide: Handling Common Scenarios
- Pod Authors Guide to CocoaPods Frameworks - CocoaPods Blog
- CocoaPods Guides - Podfile Syntax Reference
追記
laisoさんに対応してるパッチがあることを教えていただきました.
@yashigani この進行中のパッチ関係ないですかね https://t.co/iitqrGoxQk
— laiso (@laiso) 2015, 1月 21
やったね!