「fat」Cocoa Touch Framework(シミュレーターおよびデバイス用)をエクスポートする方法


107

Xcode 6では、独自のDynamicを作成することができますCocoa Frameworks

ここに画像の説明を入力してください

のため:

  • シミュレータはまだ32-bitライブラリを使用しています

  • 2015年6月1日以降、App Storeに送信されるアプリの更新には64ビットのサポートが含まれ、iOS 8 SDK(developer.apple.com)でビルドされている必要があります

デバイスとシミュレータでプロジェクトを実行するには、ファットライブラリを作成する必要があります。つまり、フレームワークで32ビットと64ビットの両方をサポートします。

しかし、他のプロジェクトとの将来の統合のためにUniversal Fat Framework をエクスポートする方法(およびこのライブラリを誰かと共有する方法)のマニュアルは見つかりませんでした。

これが私の再現手順です:

  1. 設定するONLY_ACTIVE_ARCH=NOにはBuild Settings

    ここに画像の説明を入力してください

  2. (確かに)サポートarmv7 armv7s arm64 i386 x86_64を追加するArchitectures

ここに画像の説明を入力してください

  1. フレームワークをビルドし、Finderで開きます。

ここに画像の説明を入力してください ここに画像の説明を入力してください

  1. このフレームワークを別のプロジェクトに追加する

実結果:

しかし、結局のところ、このフレームワークを使用してプロジェクトをデバイスとシミュレーターで同時に実行することにまだ問題があります。

  • フレームワークをDebug-iphoneosフォルダーから取得した場合-デバイスで動作し、シミュレーターでエラーが発生します。ld: symbol(s) not found for architecture i386

      xcrun lipo -info CoreActionSheetPicker

    ファットファイル内のアーキテクチャ:CoreActionSheetPickerは次のとおりです:armv7 armv7s arm64

  • Debug-iphonesimulatorフォルダからフレームワークを取得すると、シミュレータで機能します。デバイスにエラーがあります:ld: symbol(s) not found for architecture arm64

      xcrun lipo -info CoreActionSheetPicker

    ファットファイル内のアーキテクチャ:CoreActionSheetPickerは次のとおりです:i386 x86_64

では、デバイスとシミュレータで動作する動的フレームワークを作成するにはどうすればよいでしょうか。

この回答はXcode 6 iOSに関連していますCocoa Touch Frameworkの作成-アーキテクチャの問題ですが、重複していません。


更新:

この場合、「ダーティーハック」を見つけました。以下の私の答えを参照してください。誰かがもっと便利な方法を知っているなら、教えてください!



@AndriusSteponavičiusこの質問は2か月前に行われました。
スカイワインダー2015

はい、しかし、ユーザーが知っておくべきだと思います、より詳細な答えがあります
AndriusSteponavičiusJul

ビルド設定でONLY_ACTIVE_ARCH = NOを設定することは重要なステップです。
ジェディジャ2015年

コンピューターに64ビットアーキテクチャがある場合でも、シミュレーターでフレームワークを実行する場合は、フレームワークにfatバイナリの両方のi386 x86_64スライスが必要です!!! その難しい方法を学びました。
J.beenie 2017年

回答:


82

この回答の実際は次のとおりです。2015年7月。状況が変わる可能性が最も高いです。

TLDR;

現在、Xcodeにはユニバーサルファットフレームワークの自動エクスポート用のツールがないため、開発者は手動でlipoツールを使用する必要があります。また、このレーダーによるとフレームワークのコンシューマーであるAppStore開発者に提出する前にlipo、フレームワークからシミュレータースライスを取り除くためにも使用する必要があります。

より長い答えが続きます


トピック(回答の下部にあるリンク)でも同様の調査を行いました。

私は私の研究は、Appleデベロッパフォーラムの探査、カルタゴとレルムプロジェクトや私自身の実験とに基づいていたので、の分布についての公式ドキュメント見つからなかったxcodebuildlipocodesignツールを。

これは、Apple Developer Forums thread Exporting app with embedded frameworkからの長い引用(私からの少しのマークアップ付き)です

フレームワークプロジェクトからフレームワークをエクスポートする適切な方法は何ですか?

現在のところ、唯一の方法は、あなたがやったことです。

  • シミュレータとiOSデバイスの両方のターゲットをビルドします。
  • そのプロジェクトのXcodeのDerivedDataフォルダに移動し、2つのバイナリを1つのフレームワークにまとめます。ただし、Xcodeでフレームワークターゲットをビルドする場合は、ターゲット設定の「アクティブアーキテクチャのみをビルド」を「いいえ」に調整してください。これにより、Xcodeは複数のバイナリタイプ(arm64、armv7など)のターゲットを構築できます。これが、Xcodeからは動作するがスタンドアロンバイナリとしては動作しない理由です。

  • また、スキームがリリースビルドに設定されていることを確認し、リリースに対してフレームワークターゲットをビルドすることもできます。それでもライブラリが読み込まれないというエラーが発生する場合は、フレームワークのコードスライスを確認してください。

  • lipo -info MyFramworkBinary結果を使用して調べます。

lipo -info MyFrameworkBinary

結果は i386 x86_64 armv7 arm64

  • 最新のユニバーサルフレームワークには4つのスライスが含まれますが、さらに多くのスライスを含めることができます。i386 x86_64 armv7 arm64 少なくともこの4つが表示されない場合は、[アクティブアーキテクチャの構築]の設定が原因である可能性があります。

これは、@ skywinderが彼の回答で行ったのとほとんど同じプロセスを説明しています。

これがCarthageがlipo使用しRealmがlipoを使用する方法です。


重要な詳細

レーダーがあります:Xcode 6.1.1&6.2:シミュレータースライスを含むiOSフレームワークはApp Storeに提出できません。Realm#1163Carthage#188に関する長い議論がApp Storeにあり、特別な回避策で終わりました:

AppStoreに送信する前に、iOSフレームワークのバイナリをシミュレータスライスから削除する必要があります。

Carthageには特別なコードがあります:CopyFrameworksおよび対応するドキュメント:

このスクリプトは、ユニバーサルバイナリによってトリガーされるApp Storeの送信バグを回避します。

レルムには特別なスクリプトがあります:strip-frameworks.shおよび対応するドキュメント:

この手順は、ユニバーサルバイナリをアーカイブするときにApp Store送信のバグを回避するために必要です。

また、「Xcodeの動的ライブラリから不要なアーキテクチャを取り除く」という優れた記事もあります。

私自身はRealmを使用strip-frameworks.shしましたが、これは変更を加えることなく完全に機能しましたが、もちろん誰もがゼロから作成することは自由です。


この質問の別の側面が含まれているため、私が読むことをお勧めする私のトピックへのリンク:コード署名-iOS / OSXフレームワークの作成:他の開発者に配布する前にコード署名する必要がありますか?


1
私は脂肪を使用しましたが、フレームワークがシミュレータで構築されているとき、クラス名で未解決の識別子を示していますが、デバイスでは機能します。バイナリのシミュレーターバージョンを使用している場合、それはうまくいきます。
Susim Samanta 2016年

2
2016年12月にXcode 8.2によって変更された証拠は見つかりませんでした。:/
Geoffrey Wiseman '18

1
@Geoffrey、これはXcode 9.2で変更されましたか、それとも何か違うのですか?配布用のバイナリフレームワークを作成するのはこれが初めてで、私はすでに怖いです...
ScottyB 2018年

悲しいことに、これを少しは行っていません-言うことはできません。幸運を。
ジェフリーワイズマン2018年

57

これはそれほど明確な解決策ではありませんが、私が見つける方法は唯一あります。

  1. 設定するONLY_ACTIVE_ARCH=NOにはBuild Settings

    • シミュレーター用のビルドライブラリ
    • デバイスのビルドライブラリ
  2. Productsフレームワークのコンソールフォルダーで 開く(フレームワークフォルダーを開いcd ..てそこから開くことができます)

ここに画像の説明を入力してください ここに画像の説明を入力してください

  1. このスクリプトをProductsフォルダーから実行します。このフォルダにファットフレームワークを作成します。(または、以下の3. 4.で説明するように手動で実行します

または:

  1. このスクリプトで脂肪を使用してこれらの2つのフレームワークを結合YourFrameworkNameします(フレームワーク名に置き換えます)

    lipo -create -output "YourFrameworkName" "Debug-iphonesimulator/YourFrameworkName.framework/YourFrameworkName" "Debug-iphoneos/YourFrameworkName.framework/YourFrameworkName"
  2. 既存のフレームワークの1つを新しいバイナリに置き換えます。

    cp -R Debug-iphoneos/YourFrameworkName.framework ./YourFrameworkName.framework
    mv YourFrameworkName ./YourFrameworkName.framework/YourFrameworkName

  1. 利益:./YourFrameworkName.framework- すぐに使えるファットバイナリです!プロジェクトにインポートできます!

ワークスペースにないプロジェクトの場合:

ここで説明するように、この要旨を使用することもできます。しかし、ワークスペース内のプロジェクトでは機能しないようです。


Appleはもうファットバイナリを受け入れないだろうと思った。kodmunki.wordpress.com/2015/03/04/...
Monstieur

1
@skywinder Cocoa Touch Frameworkをファットバイナリを使用する準備ができるようにエクスポートする他の簡単な方法を見つけましたか?私は上記と同じアプローチを使用していますが、好きではありません。Xcodeには、プロセスを自動化するものがいくつか必要です。
dev gr 2015

1
@devgrはまだ..それが私が自分の答えを受け入れなかった理由です。まだより良い解決策を探しています。
スカイワインダー、2015年

1
シミュレーターでは実行できませんが、デバイスでは3および4ステップで動作します
jose920405

1
@ Debug-フォルダだけが使用される理由を誰かが説明できますlipo -createか?このフレームワークをRelease構成に使用できますか?その理由は?ありがとう。
Yevhen Dubinin

10

@Stainlavの回答は非常に役に立ちましたが、代わりにフレームワークの2つのバージョン(1つはデバイス用、もう1つはシミュレータ用)をRun Script Phaseコンパイルし、実行中のアーキテクチャに必要なプリコンパイル済みフレームワークを自動的にコピーするために以下を追加しました

echo "Copying frameworks for architecture: $CURRENT_ARCH"
if [ "${CURRENT_ARCH}" = "x86_64" ] || [ "${CURRENT_ARCH}" = "i386" ]; then
  cp -af "${SRCROOT}/Frameworks/Simulator/." "${SRCROOT}/Frameworks/Active"
else
  cp -af "${SRCROOT}/Frameworks/Device/." "${SRCROOT}/Frameworks/Active"
fi

このようにして、App Storeに送信するときに不要なスライスを削除するためにlipoRealmのファットフレームワークを作成するために使用する必要はありませんstrip-frameworks.sh


どちらにリンクしますか?
JakaJančar2016年

@JakaJančar ${SRCROOT}/Frameworks/Activeフォルダー内のものに対してリンクします。それらは、コンパイル時にアクティブなアーキテクチャに適したプリコンパイル済みフレームワークに置き換えられます。
odm '06 / 06/16

2
大好きです!これは、結合後引き離しlipoアプローチよりもはるかに簡単です。
clozach

2

基本的にこれのために私は非常に良い解決策を見つけました。これらの簡単な手順に従うだけです。

  1. ココアタッチフレームワークを作成します。
  2. ビットコードを有効に設定します。
  3. ターゲットを選択し、スキームの編集を選択します。[実行]を選択し、[情報から解放]タブを選択します。
  4. 他の設定は必要ありません。
  5. シミュレーターがx86アーキテクチャーで実行されるように、シミュレーターのフレームワークを構築します。
  6. Project Navigatorで[Products]グループをクリックし、.frameworkファイルを見つけます。
  7. それを右クリックし、ファインダーに表示をクリックします。それをコピーして任意のフォルダに貼り付けます。個人的には「シミュレータ」という名前を好みます。
  8. 次に、汎用iOSデバイスのフレームワークを構築し、手順6〜9に従います。フォルダーの名前を「シミュレーター」ではなく「デバイス」に変更します。
  9. デバイスの.frameworkファイルをコピーして、他のディレクトリに貼り付けます。私は両方の直下のスーパーディレクトリを好みます。したがって、ディレクトリ構造は次のようになります。
    • デスクトップ
    • 端末
      • MyFramework.framework
    • シミュレーター
      • MyFramework.framework
    • MyFramework.frameworkターミナルを開き、デスクトップに移動します。次のコマンドの入力を開始します。

lipo -create 'device / MyFramework.framework / MyFramework' 'simulator / MyFramework.framework / MyFramework' -output 'MyFramework.framework / MyFramework'

以上です。ここでは、MyFramework.framework内にあるMyFrameworkバイナリのシミュレータとデバイスバージョンをマージします。シミュレータやデバイスを含むすべてのアーキテクチャ用に構築されたユニバーサルフレームワークを取得します。


ビットコードを有効にしてFATファイルを作成したい。案内してください。
user3898700

2

@odmでこの素晴らしい答えを更新したいだけです。Xcode 10以降、CURRENT_ARCH変数はビルドアーキテクチャを反映しなくなりました。そこで、代わりにプラットフォームをチェックするようにスクリプトを変更しました。

echo "Copying frameworks for platform: $PLATFORM_NAME"
rm -R "${SRCROOT}/Frameworks/Active"
if [ "${PLATFORM_NAME}" = "iphonesimulator" ]; then
    cp -af "${SRCROOT}/Frameworks/Simulator/." "${SRCROOT}/Frameworks/Active"
else
    cp -af "${SRCROOT}/Frameworks/Device/." "${SRCROOT}/Frameworks/Active"
fi

また、コピーする前にターゲットディレクトリをクリアする行を追加しました。これは、サブディレクトリ内の追加のファイルが他の方法で上書きされないことに気付いたためです。


1

私の答えは以下の点をカバーしています:

  • シミュレータとデバイスの両方で機能するフレームワークを作成する

  • 「太った」Cocoa Touch Frameworkをエクスポートする方法(シミュレータとデバイスの両方)

  • アーキテクチャx86_64の未定義のシンボル

  • ld:アーキテクチャx86_64のシンボルが見つかりません

手順1:最初にシミュレーターターゲットを使用してフレームワークをビルドする

手順2:シミュレーターのビルドプロセスが成功したら、デバイスターゲットの選択またはGeneric iOS Device selectionを使用してフレームワーク用にビルドします。

ステップ3:フレームワークターゲットを選択し、そのために[ビルドフェーズ]で[実行スクリプトの追加]を選択し、以下のスクリプトコードをコピーします)

ステップ4:最後に、もう一度ビルドすると、フレームワークはシミュレーターとデバイスの両方の互換性の準備ができています。ばんざーい!

[注:最後のステップ4の前に、互換性のある両方のフレームワークを準備しておく必要があります(シミュレータとデバイスアーキテクチャの互換性があります。そうでない場合は、上記のステップ1と2を正しく実行してください)。

参照画像を参照してください:

ここに画像の説明を入力してください

ここに画像の説明を入力してください

以下のコードをシェル領域に配置します。

#!/bin/sh


UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal


# make sure the output directory exists

mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"


# Step 1. Build Device and Simulator versions

xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos  BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build

xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build


# Step 2. Copy the framework structure (from iphoneos build) to the universal folder

cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"


# Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory

SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/."

if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then

cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"

fi


# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory

lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"


# Step 5. Convenience step to copy the framework to the project's directory

cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"


# Step 6. Convenience step to open the project's directory in Finder

open "${BUILD_DIR}/${CONFIGURATION}-universal"


このスクリプトはそれ自体を呼び出して無限ループを引き起こしているようです!! 実行後にコンピュータを再起動する必要がありました。新しいxcodebuildプロセスを継続的に生成し、新しいファインダーウィンドウを開いていた
J.beenie

再帰の問題のない同様のスクリプトについては、このSO Q / Aの@ l0gg3rの回答を確認してください。
J.beenie 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.