67
68

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Xcode] 自作frameworkを作成する

Posted at

Xcodeで開発を行っていると必ず使う「****.framework」。
今回はこれの作成手順をまとめます。

ちなみにframeworkについてはドキュメントもあります。
Framework Programming Guide: Introduction to Framework Programming Guide

実態はただのディレクトリ

実はframework自体はただのディレクトリです。
その中身の構造にフォーマットがあり、適切にファイルやディレクトリを配置することでXcodeがframeworkとして認識し、利用できるようになる、というわけです。

ディレクトリ構造

ドキュメントによると一番シンプルな状態は以下のようになります。

A simple framework bundle

MyFramework.framework/
    MyFramework  -> Versions/Current/MyFramework
    Resources    -> Versions/Current/Resources
    Versions/
        A/
            MyFramework
            Resources/
                English.lproj/
                    InfoPlist.strings
                Info.plist
        Current  -> A

上記例ではResourcesしかありませんが、実際にはHeadersも含めることでヘッダファイルを個別にincludeする必要がなくなります。

実際に作成したキャプチャはこんな感じです↓
cap.png

よく見てもらうと分かりますが、エイリアスも生成されています。
階層直下にエイリアスを起き、実際はそれぞれVersionの下に入っているものが実態となります。
Versionの名が示す通り、A以外にもBなど複数バージョンを混在させることもできるようになっています。
(その場合は、Currentの参照先を適切に変更することで利用するバージョンを切り替えることができるようになっています)

構造

構造は画像を見てもらうと分かると思いますが、フレームワーク直下には3つのエイリアスとひとつのディレクトリがあります。
HeadersHogeResourcesはそれぞれ、Versions/Aディレクトリ以下のそれぞれ同名のものにリンクされています。
また、Versionsの中にCurrentというエイリアスがあります。
このエイリアスは上記サンプルではAを指しています。

しかし仮に、Bなどの別バージョンが存在する場合は、このCurrentの向き先を変えることでバージョン管理ができるようになっています。
(ちなみに拡張子なしの「Hoge」がライブラリ(.aファイル)の本体です)

Run Scriptでファイルをコピー

ファイルが増えてきたら使えない(というかめんどくさい)ですが、以下のようにRun Scriptを設定して自分自身でディレクトリの生成やファイルのコピーを行うことで作成することが可能です。

サンプルではディレクトリの作成からファイルのコピー、そしてエイリアスの設定まですべてスクリプトで行っています。
普通(?)はHeadersディレクトリなどをプロジェクト内で作ってそこにファイルを入れておいたほうがいいのかもしれませんが、すでに作成してしまったプロジェクトをframework化する場合など、現状の構造では問題がある場合などはスクリプトでやっちゃうといいと思います。

#!/bin/bash

BUILD_DIRECTORY=build
FRAMEWORK_NAME=Hoge
FRAMEWORK_DIR=${BUILD_DIRECTORY}/${FRAMEWORK_NAME}.framework

rm -rf ${BUILD_DIRECTORY}/*

xcodebuild -scheme Hoge -configuration Debug -sdk $SDK_NAME
             
# ---------------------------------
# Create directories.
# ---------------------------------
FRAMEWORK_VERSION=A
mkdir -p ${FRAMEWORK_DIR}
mkdir -p ${FRAMEWORK_DIR}/Versions
mkdir -p ${FRAMEWORK_DIR}/Versions/${FRAMEWORK_VERSION}
mkdir -p ${FRAMEWORK_DIR}/Versions/${FRAMEWORK_VERSION}/Resources
mkdir -p ${FRAMEWORK_DIR}/Versions/${FRAMEWORK_VERSION}/Headers

# ---------------------------------
# Create aliases.
# ---------------------------------              
ln -s ${FRAMEWORK_VERSION} ${FRAMEWORK_DIR}/Versions/Current
ln -s Versions/Current/Headers ${FRAMEWORK_DIR}/Headers
ln -s Versions/Current/Resources ${FRAMEWORK_DIR}/Resources
ln -s Versions/Current/${FRAMEWORK_NAME}.a ${FRAMEWORK_DIR}/${FRAMEWORK_NAME}

# ---------------------------------
# Create an object file.
# ---------------------------------
lipo -create path/to/lib/libHoge.a \
-output ${FRAMEWORK_DIR}/Versions/${FRAMEWORK_VERSION}/LobiRecMetal.a

# ---------------------------------
# Copy header files.
# ---------------------------------
cp ${PROJECT_DIR}/${PROJECT_NAME}/Hoge.h \
${FRAMEWORK_DIR}/Versions/${FRAMEWORK_VERSION}/Headers/

# ---------------------------------
# Copy resouse files.
# ---------------------------------      
cp ${PROJECT_DIR}/${PROJECT_NAME}/sample.png ${FRAMEWORK_DIR}/Versions/${FRAMEWORK_VERSION}/Resources/

ポイントはlnコマンドでエイリアスを生成している部分です。
このあたりのルールはドキュメントに書いてある通りです。

上記を設定しておけば、ビルド実行時に必要なファイルがコピーされ、Hoge.frameworkが生成されます。
フレームワーク生成専用のビルドターゲットを作り、それをビルドすることでフレームワークが生成されるようにしておくといいと思います。

上記の構造が出来上がると、Xcodeにフレームワークとして追加した際に自動的に内容が読み込まれます。
あとは他のフレームワーク同様、ヘッダファイルをインポートして使うことができるようになります。

複数アーキテクチャのライブラリをひとつにまとめるlipoコマンド

lipoコマンド

複数アーキテクチャ向けにビルドされたライブラリファイルをひとつにまとめ、ユニバーサルに対応させるためのコマンド。

以下のようにします。
(armv7とarm64を入れる、みたいな感じの例)

lipo -arch armv7 ./path/to/armv7/libhoge.a -arch arm64 ./path/to/arm64/libhoge.a -create -output ./path/to/output/libhoge.a

今回の例ではひとつのアーキテクチャしか含めていませんが、複数アーキテクチャに対応する場合(というか、基本的には対応する必要があるでしょう)に使用します。

frameworkで管理されているリソースにアクセスする

リソースにアクセスするにはNSBundleを使います。
(frameworkをリンクさせると認識されます)

NSString *path = [NSBundle.mainBundle pathForResource:@"sample" ofType:@"png"];
UIImage *image = [UIImage imageWithContentsOfFile:path];

参考記事

67
68
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
67
68

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?