Darwin-style フレームワーク内に他ライブラリ・フレームワークへの依存関係を記述する
皆さんこんばんは。
最近腰をやってしまったDayBySayです。
本日はDarwin-styleのフレームワーク内に依存関係を記述する方法についてまとめました。
概要
Mac OSXやiOSで利用されるDarwin-styleのフレームワークですが、サードパーティの誰かがフレームワークを提供する場合に、プラットフォームが提供するライブラリやフレームワークに対して依存関係を持つことが有ります。
例えば、Dropboxが提供しているSDK(フレームワーク)をダウンロードして利用する場合、こちらに書いてあるとおりSecurity.framework
などのフレームワークへのリンクをSDK利用側が明示的に行う必要があり、ちょっとめんどくさいです。
一方で、Googleが提供するAdMobのSDKをダウンロードして利用する場合、フレームワークのリンクを明示的に行う必要はありません。
この違いは、Clang
のLink declaration
を使っているかどうかになります。
Link declaration
先日の記事で書いたClang
のモジュール機能の中に、Link declaration
という依存関係を記述する機能が存在します。
この機能を使うことでフレームワーク側に依存関係を記述し、フレームワーク利用側の負担を減らすことが出来ます。
機能の説明は下記のようにされています。
Link declaration
A link-declaration specifies a library or framework against which a program should be linked if the enclosing module is imported in any translation unit in that program.
説明の通り、モジュールがライブラリ(共有ライブラリを指しています)とフレームワークに対してリンクを行うべきかを定義するものです。
記述方法は下記のような感じです。
link-declaration:
link framework opt string-literal
opt
はframework
記述に対してかかっています。
どういうことかというと、ライブラリ、例えばlibxml2
へのリンクは
link xml2
であり、フレームワーク、例えばAVFoundation.framework
へのリンクは
link framework AVFoundation
となる、ということです。
これらをmodule.modulemap
ファイルに記述することでフレームワーク側で依存関係の記述を吸収することが出来ます。
ちなみに先述のAdMob SDKのmodule.moduemap
はこんな内容になっています。
framework module GoogleMobileAds { umbrella header "GoogleMobileAds.h" export * module * { export * } link framework "AdSupport" link framework "AudioToolbox" link framework "AVFoundation" link framework "CoreGraphics" link framework "CoreMedia" link framework "CoreTelephony" link framework "EventKit" link framework "EventKitUI" link framework "Foundation" link framework "MessageUI" link framework "StoreKit" link framework "SystemConfiguration" link framework "UIKit" // ~~ 略 ~~ }
実際に使ってみる
実際の処理は下記のような感じになっています
#import "HOGEFugaService.h" @import AdSupport; @implementation HOGEFugaService // 中略 + (NSString *)ADID { return [[ASIdentifierManager sharedManager] advertisingIdentifier].UUIDString; } @end
今回は上記のようにASIdentifierManager
のadvertisingIdentifier
メソッドをフレームワーク内で利用しているため、このプロジェクトで作成されるHOGEFuga.framework
はAdSupport.framework
への依存を持つこととなります。
依存関係を記述するためのmodule.modulemap
は下記のようになっています。
framework module HOGEFuga { umbrella header "HOGEFuga.h" export * module * { export * } link framework "AdSupport" }
link framework "AdSupport"
の記述を追加しました。
動かしてみる
HOGEFuga.framework
を利用する側の実装は下記のようにしています。
import UIKit import HOGEFuga class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. HOGEFugaService.show() NSLog("%@", HOGEFugaService.ADID()) } // 略 }
また、プロジェクトに対してAdSupport.framework
のリンクを明示的に記述していません。
この状態でコンパイルできれば成功です。
Ctrl+R
でシミュレータ実行を行うと・・
コンパイル成功!そしてシミュレータのIDFA
が出力されているので、動作確認も完了です!
まとめ
フレームワークを外部に対して提供する場合は、モジュールとして利用できる形にし、フレームワークへの依存を記述しておくと便利である。
※ CocoaPods
を使う場合リンク機能があるのでモジュールにしなくても済む場合があります
※ Unity
プラグインとしてフレームワークを提供する場合、モジュール化とLink declaration
が有効に働く気がします。