「シミュレータ」および「デバイス用」の「脂肪」Cocoa Touchフレームワークをエクスポートする方法
Xcode 6を使用すると、独自のDynamic Cocoa Frameworks
を作成できます。
のため:
シミュレーターは引き続き
32-bit
ライブラリーを使用しますapp Storeに送信される2015年6月1日以降のアプリの更新には、64ビットのサポートが含まれ、iOS 8 SDKでビルドされる必要があります( developer.Apple.com )
デバイスやシミュレータでプロジェクトを実行するには、ファットライブラリを作成する必要があります。つまり、フレームワークで32ビットと64ビットの両方をサポートします。
しかし、他のプロジェクトとの将来の統合のためにユニバーサル脂肪フレームワークを(exportする方法と、このライブラリを誰かと共有する方法)を見つけられませんでした。
再現する手順は次のとおりです。
ONLY_ACTIVE_Arch=NO
にBuild Settings
を設定しますサポート
armv7 armv7s arm64 i386 x86_64
をArchitectures
に追加します(確かに)
- フレームワークをビルドし、Finderで開きます。
- このフレームワークを別のプロジェクトに追加します
実結果:
しかし、結局のところ、このフレームワークを使用したプロジェクトをデバイスとシミュレーターで同時に実行することにはまだ問題があります。
フレームワークを
Debug-iphoneos
フォルダーから取得した場合-デバイスで機能し、シミュレーターでエラーが発生します:ld: symbol(s) not found for architecture i386
xcrun lipo -info CoreActionSheetPicker
Fatファイルのアーキテクチャ: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の作成-アーキテクチャの問題 に関連していますが、重複していません。
更新:
このケースで「ダーティハック」を見つけました。 以下の回答 を参照してください。誰かがもっと便利な方法を知っているなら-教えてください!
この回答の実際は、2015年7月です。状況が変わる可能性が最も高いです。
TLDR;
現在、Xcodeにはユニバーサルファットフレームワークの自動エクスポート用のツールがないため、開発者はlipo
ツールを手動で使用する必要があります。また、 このレーダー によると、フレームワークのコンシューマーであるAppStore開発者に提出する前に、lipo
を使用してフレームワークからシミュレータースライスを取り除く必要があります。
長い回答が続きます
トピックで同様の調査を行いました(回答の下部にあるリンク)。
配布に関する公式ドキュメントを見つけていないので、私の研究はApple開発者フォーラム、CarthageおよびRealmプロジェクトの調査、およびxcodebuild
、lipo
、codesign
ツールを使用した私自身の実験に基づいています。
これは、Apple Developer Forumsスレッドからの長い引用です(私から少しマークアップしています) 組み込みフレームワークを使用したアプリのエクスポート :
フレームワークプロジェクトからフレームワークをエクスポートする適切な方法は何ですか?
現在、唯一の方法はあなたがやったことです。
- シミュレーターとiOSデバイスの両方のターゲットをビルドします。
そのプロジェクトのXcodeのDerivedDataフォルダーに移動し、2つのバイナリを1つのフレームワークにリポします。ただし、Xcodeでフレームワークターゲットをビルドする場合は、ターゲット設定の「Build Active Architecture Only」を「NO」に調整してください。これにより、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#116 および Carthage#188 これは特別な回避策で終わりました:
AppStore iOSフレームワークバイナリに送信する前に、シミュレータスライスから削除する必要があります
Carthageには、特別なコード CopyFrameworks および対応するドキュメントがあります:
このスクリプトは、ユニバーサルバイナリによってトリガーされる App Store提出バグ を回避します。
レルムには特別なスクリプトがあります: strip-frameworks.sh および対応するドキュメント:
この手順は、ユニバーサルバイナリをアーカイブするときに App Store提出バグ を回避するために必要です。
また、良い記事があります: Xcodeの動的ライブラリから不要なアーキテクチャを取り除く 。
私自身、Realmのstrip-frameworks.sh
を使用しましたが、修正なしで完璧に機能しましたが、もちろん誰でも最初から自由に作成できます。
この質問の別の側面が含まれているため、読むことをお勧めする私のトピックへのリンク:コード署名- iOS/OSXフレームワークの作成:他の開発者に配布する前にコード署名する必要がありますか?
これはそれほど明確な解決策ではありませんが、私が見つける唯一の方法があります:
ONLY_ACTIVE_Arch=NO
にBuild Settings
を設定します- シミュレータ用のビルドライブラリ
- デバイス用のビルドライブラリ
フレームワークのコンソール
Products
フォルダーで開く(フレームワークフォルダーを開いてそこからcd ..
で開くことができます)
Products
フォルダからthisスクリプトを実行します。このフォルダーにfat Frameworkを作成します。 (または3。4。で説明されているように手動で実行します)
または:
このスクリプトでlipoを使用してこれら2つのフレームワークを結合します(
YourFrameworkName
をフレームワーク名に置き換えます)lipo -create -output "YourFrameworkName" "Debug-iphonesimulator/YourFrameworkName.framework/YourFrameworkName" "Debug-iphoneos/YourFrameworkName.framework/YourFrameworkName"
既存のフレームワークの1つを新しいバイナリに置き換えます。
cp -R Debug-iphoneos/YourFrameworkName.framework ./YourFrameworkName.framework mv YourFrameworkName ./YourFrameworkName.framework/YourFrameworkName
- 利益:
./YourFrameworkName.framework
-すぐに使用できるファットバイナリです!プロジェクトにインポートできます!
ワークスペースにないプロジェクトの場合:
here で説明されているように this Gist を使用することもできます。しかし、ワークスペース内のプロジェクトでは機能しないようです。
@Stainlavの回答は非常に役に立ちましたが、代わりに2つのバージョンのフレームワーク(デバイス用とシミュレータ用)をコンパイルし、次の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に提出する際にlipo
を使用して脂肪のフレームワークを作成せず、レルムのstrip-frameworks.sh
を使用して不要なスライスを削除する必要はありません。
基本的にこれのために私は非常に良い解決策を見つけました。これらの簡単な手順に従うだけです。
- ココアタッチフレームワークを作成します。
- ビットコードを有効に設定します。
- ターゲットを選択し、スキームの編集を選択します。実行を選択し、情報タブからリリースを選択します。
- 他の設定は必要ありません。
- シミュレーターがx86アーキテクチャーで実行されるときに、シミュレーターのフレームワークを構築します。
- Project Navigatorの[製品]グループをクリックして、.frameworkファイルを見つけます。
- それを右クリックし、Finderで表示をクリックします。任意のフォルダにコピーして貼り付けます。個人的には「シミュレータ」という名前を好みます。
- 次に、汎用iOSデバイスのフレームワークを構築し、手順6〜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バイナリのシミュレーターとデバイスバージョンをマージします。シミュレーターやデバイスを含むすべてのアーキテクチャー向けに構築されるユニバーサルフレームワークを取得します。
更新したいだけです この素晴らしい答え by @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
また、コピーする前にターゲットディレクトリをクリアするための行を追加しました。サブディレクトリ内の追加のファイルが上書きされないことに気付いたからです。
私の答えは以下の点をカバーしています:
シミュレーターとデバイスの両方で機能するフレームワークを作成する
「脂肪」ココアタッチフレームワークをエクスポートする方法(シミュレーターとデバイスの両方)
アーキテクチャx86_64の未定義のシンボル
ld:アーキテクチャx86_64のシンボルが見つかりません
ステップ1:最初にシミュレータターゲットを使用してフレームワークを構築します
ステップ2:シミュレーターのビルドプロセスが成功した後、デバイスターゲット選択または汎用iOSデバイス選択を使用してフレームワーク用にビルドします
ステップ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"