Karakuri.com

Fintechではたらくアプリケーションエンジニアの技術録

XcodeのFrameworkでBridging Headerは使えないのでmodule.modulemapを追加してエラー回避する

外部ライブラリをラップするライブラリを作成して社内で使いまわすということをWindowsやAndroidでは当然のようにやってきたのですが、iOSでは簡単にできない場合があります。それはObjective-Cで書かれたライブラリをSwiftのFrameworkでラップする場合です。

FrameworkでObjective-CのFrameworkの組み込み時にエラー

error: using bridging headers with framework targets is unsupported

プロジェクトにObjective-Cで書かれたFrameworkを組み込む場合、Bridging Headerを追加して参照できるようにします。Frameworkで同じようにするとエラーが発生してビルドできません。エラーメッセージそのままですが、FrameworkではBridging Headerが使えないようです。

ググってもObjective-CのFrameworkを修正する方法ばかり

ではどうやって組み込むのかどうか、ググって調べてもObjective-CのFrameworkを修正してビルドし直すという方法ぐらいしか見つかりませんでした。しかし、今回のFrameworkはサードパーティー製でソースコードは手元になく修正はできません。

FrameworkでObjective-CのFrameworkを組み込む

module.modulemapを作成する

そこでmodule.modulemapを追加修正することで対応します。Frameworkは実態はただのフォルダなので中身を開くことができます。今回使用していたFrameworkの中身はこうなっていました。
f:id:hazakurakeita:20180715010731p:plain
ここにModulesというフォルダを追加します。
f:id:hazakurakeita:20180715010656p:plain
そしてこのModulesフォルダの中にmodule.modulemapというファイルを新規で作成します。

Bridging Headerでimportしているヘッダーファイルを追加する

続いてmodule.modulemapに参照するヘッダーファイルを指定します。指定するのはBridging Headerでimportしているヘッダーファイルです。Bridging Headerの指定方法は基本的に外部ライブラリ開発元が公開しているはずなので、そちらを参照してください。例えばBridging Headerは下記のようになっていた場合、

#ifndef FrameworkName_Bridging_Header_h
#define FrameworkName_Bridging_Header_h

#import <FrameworkName/Header.h>

#endif /* FrameworkName_Bridging_Header_h */

module.modulemapは下記のようになります。

framework module FrameworkName {
  umbrella header "Header.h"

export *
  module * { export * }
  
  link framework "FrameworkName"
}

Bridging Headerでimportしているヘッダーファイルが複数の場合

module.modulemapで指定できるヘッダーファイルは1つだけです。このため、もしBridging Headerは下記のようになっていた場合、

#ifndef FrameworkName_Bridging_Header_h
#define FrameworkName_Bridging_Header_h

#import <FrameworkName/Header1.h>
#import <FrameworkName/Header2.h>
#import <FrameworkName/Header3.h>

#endif /* FrameworkName_Bridging_Header_h */

この3つのヘッダーファイルをimportするヘッダーファイルを新規で作成する必要があります。

framework module FrameworkName {
  umbrella header "Header.h"

export *
  module * { export * }
  
  link framework "FrameworkName"
}

module.modulemapを同様に作成して、「Versions/A/Headers/」の中にmodule.modulemapで指定したHeader.hを新規で作成して下記のように中身を書いておきます。

#import <Foundation/Foundation.h>
#import <FrameworkName/Header1.h>
#import <FrameworkName/Header2.h>
#import <FrameworkName/Header3.h>

これでBridging HeaderなしでFrameworkをビルドできるようになります。当然Framework内のソースコードから外部ライブラリを参照できるようになります。