50

iOS アプリの動的フレームワークを作成しようとしています。Xcode (6) の新しいバージョンのおかげで、新しいプロジェクトを作成するときに Cocoa Touch Framework を選択できるようになり、集約ターゲットを追加したり、スクリプトを実行したりして作成する必要がなくなりました。フレームワークを構築するときに問題はありません。しかし、iOS アプリ内で使用しようとすると、アーキテクチャの問題が発生します。

ld: warning: ignoring file /Library/Frameworks/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (arm64): /Library/Frameworks/MyFramework.framework/MyFramework
Undefined symbols for architecture arm64:
  "_OBJC_CLASS_$_MyFrameworkWebService", referenced from:
      objc-class-ref in AppDelegate.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

ld: warning: ignoring file /Library/Frameworks/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (armv7): /Library/Frameworks/MyFramework.framework/MyFramework
Undefined symbols for architecture armv7:
  "_OBJC_CLASS_$_MyFrameworkWebService", referenced from:
      objc-class-ref in AppDelegate.o
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)

フレームワーク プロジェクトとターゲットの設定を変更しようとしました (アーキテクチャ & 有効なアーキテクチャのみをビルド & 有効なアーキテクチャ)。iOS アプリ プロジェクトに対して同じことを行いましたが、何も機能しません。わからないことがあったと思います。

たとえば、コマンド ライン「xcrun lipo -info MyFramework」を使用して i386 (iOS シミュレーター) チェックのみのフレームワークをビルドすると、次のような問題が発生します。

ld: 警告: ファイル /Library/Frameworks/MyFramework.framework/MyFramework を無視します。ファイルは、リンクされているアーキテクチャではない x86_64 用にビルドされました (i386)...

誰かが、シミュレータを含むすべての iOS アーキテクチャで動作するフレームワークを取得するのを手伝ってくれたら.

4

10 に答える 10

69

すべての応答、raywenderlich.com の投稿、およびChris Conwayによって作成された要点に基づいて、私はこれを思いつきまし

次の手順を実行すると、シミュレーターとデバイスの両方のすべてのアーキテクチャを含む Cocoa Touch フレームワーク (Swift および Objective-C ファイルを含む) を構築できました。

  1. フレームワークのプロジェクトで新しい (集約) ターゲットを作成します
  2. [ビルド フェーズ] で [実行スクリプトの追加] を選択し、このファイルの内容をコピーします。
  3. スキームの選択ドロップダウンで集計ターゲット選択します
  4. 集計スキームターゲット 構築する

それが役に立てば幸い :)

更新:ステップ 3 のパスが間違っていた要旨のエラーを修正しました。徳陸に感謝!!

更新 Xcode 7 および 8 では、[ファイル] > [新規] > [ターゲット...] をクリックし、[その他] グループを選択して [集計ターゲット] を選択します。

于 2014-11-01T16:02:36.403 に答える
47

フレームワーク プロジェクトとアプリ プロジェクトを含むワークスペースを作成するには、次の手順を試してください。

ワークスペース:

  • ワークスペースを作成します。

フレームワーク プロジェクト:

  • Workspace 内にiOS Cocoa touch Frameworkプロジェクトを作成します。
  • 単純な Objective C クラスMyClass (ヘッダー .h および実装ファイル .m) を追加し、メソッド(void)greetingsを作成します。
  • プロジェクトBuild Phases > Headers > Move MyClass.h from Project to Publicに移動します。
  • スキームをフレームワーク プロジェクトに変更し、 iOS シミュレーターを選択してビルドします。(このフレームワークを統合するアプリがデバイスで実行される場合は、 iOS デバイスを選択します。この例では引き続きシミュレーターを使用します)
  • ビルドに問題はありません。フレームワークのビルドは、 OrganiserにあるDerived Dataディレクトリにあります。

アプリ プロジェクト:

  • Workspace 内に Swift Single View アプリケーションを作成します。
  • iOS シミュレーター フレームワーク ビルド ( Debug-iphonesimulatorまたはRelease-iphonesimulatorにあります) の上にドラッグして、プロジェクトに移動します。
  • Objective C クラス メソッドを Swift に公開するためのブリッジング ヘッダーを作成します。
  • ブリッジング ヘッダー ファイルに MyClass.h をインポートします。
  • MyClass 定義が見つからない場合は、フレームワークのHeadersパスを Build Settings Header Search Pathsに追加することに注意してください。
  • ViewController.swiftの viewDidLoad にMyClassのインスタンスを作成し、 greetingsを呼び出します。
  • フレームワークをターゲットに追加 > 埋め込みバイナリ
  • スキームをアプリ プロジェクトに変更し、 iOS シミュレーターを選択してビルドします。
  • グリーティング メッセージを表示できるはずです。

上記の例は、シミュレーターで実行されるアプリをビルドする方法を示していることに注意してください。シミュレーターデバイスの両方で実行されるユニバーサル スタティック ライブラリを作成する必要がある場合、一般的な手順は次のとおりです。

  • シミュレーター用のライブラリーをビルドする
  • デバイスのライブラリをビルド
  • リポを使って組み合わせる

これについては、ウェブ上に参考文献があります。たとえば、こちらです。

フレームワークのユニバーサル バイナリを作成します。フレームワークの Derived Data ディレクトリに移動し、次に/Build/Productsに移動します。次のコマンドは、Productsディレクトリにユニバーサル バイナリを作成するのに役立ちます。

lipo -create -output "framework-test-01-universal" "Debug-iphonesimulator/framework-test-01.framework/framework-test-01" "Debug-iphoneos/framework-test-01.framework/framework-test-01" 

Framework -test-01は私のフレームワーク プロジェクト名です。

于 2014-06-18T21:14:50.557 に答える
10

私が行った方法はvladofに似ていますが、うまくいけばもう少し簡単です。フレームワークをアプリ プロジェクトのサブプロジェクトにしました。

フレームワーク プロジェクト

  • 新しい iOS ココア タッチ フレームワークを作成します。それを MyLib と呼びます。これにより、単一の MyLib.h が作成されます
  • 単純な Cocoa Touch Obj-C クラス MyClass (.h & .m) を追加し、.m の実装で、文字列を返すメソッドを作成します - (NSString *)greetings;
  • MyLib.h の一番下に #import "MyClass.h" を追加します。
  • ターゲットの Build Phases/Headers セクションで、MyClass.h を Project セクションから Public セクションに移動します。
  • ビルドを実行 (cmd-B)
  • プロジェクトを閉じる

アプリ プロジェクト

  • Swift または Obj-C のいずれかで、新しいシングル ビュー アプリケーション プロジェクトを作成します。それを MyApp と呼びます。
  • Finder から、MyLib プロジェクト ファイルを MyApp ウィンドウの左側のオーガナイザー セクションにドラッグし、挿入行が MyApp のすぐ下にあることを確認します。これにより、MyLib は MyApp のサブプロジェクトになります。(他のプロジェクトでも同じように使用できます)
  • オーガナイザーで MyApp をクリックし、MyApp ターゲットを選択して Build Phases を選択します。
  • [対象の依存関係] で、+ 記号をクリックして MyLib を追加します。
  • Link with Libraries で + 記号をクリックし、MyLib.framework を追加します。

Obj-C アプリの場合

  • ViewController.m に #import を追加します。
  • viewDidLoad で、次の行を追加します。
  • MyLib *x = [[MyLib alloc] init];
  • NSLog(@"%@", x.greetings);
  • プロジェクトを実行すると、デバッグ ウィンドウにメッセージが表示されます。-

Swift アプリの場合

  • ViewController.swift に import MyLib を追加
  • viewDidLoad で、次の行を追加します。
  • var x: MyLib = MyLib()
  • println("(x.greetings())") -

このようにすることで、アプリはフレームワークに依存するため、フレームワーク クラスを変更した場合、フレームワークを個別にビルドするためにターゲットを変更する必要はありません。最初にフレームワークをコンパイルしてからアプリをコンパイルするだけです。

于 2014-06-24T17:39:14.730 に答える
7

すべてのシミュレーターのアーキテクチャーをサポートするために、誰かのスクリプトを少し変更しました。

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}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator VALID_ARCHS="x86_64 i386" BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build

# Step 2. Copy the framework structure to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"

# Step 3. 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 4. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"

# Step 5. Delete temporary build directory in the project's directory
rm -rf "${PROJECT_DIR}/build"

# Step 6. Convenience step to open the project's directory in Finder
open "${PROJECT_DIR}"
于 2015-07-10T20:21:08.683 に答える
2

上記のリンクから以前に作成した古いビデオは、もう利用できません。

Xcode 6 を使用して Cocoa Touch フレームワークを作成する方法

于 2014-12-02T10:15:37.527 に答える
1

vladof が共有するアプローチに関して、Swift ベースのフレームワークにより適したいくつかの追加ポイント

  1. 関連リンクのスクリプトは、iphonesimulator と iphoneos の両方からすべてのファイルをコピーするように変更する必要があります。これは、swift には arm と i386 用に別々のコンパイル済みファイルがあるためです。
  2. シミュレーターのリンカーの問題を回避するために、iphonesimulator のビルドに ARCHS="x86_64" ONLY_ACTIVE_ARCH=NO があることを確認してください
  3. インターフェイス/クラスが NSObject を拡張していることを確認してください。そうしないと、コードを迅速に使用しようとしたときに問題が発生します (() を使用してオブジェクトを作成できないと不平を言うでしょう)。
于 2014-07-06T15:50:28.177 に答える
1

最後に、私はそれが私のために働くようになりました!大きな黄色い枠で申し訳ありませんが、それをより適切にフォーマットする方法がわかりません。

解決策は Claudio Romandi によるものですが、リンクされたスクリプトには小さな問題があります。私は50の評判が必要なので、彼の投稿にコメントすることはできません.

  1. フレームワーク プロジェクトで新しい (集約) ターゲットを作成する
  2. ワークスペースで集計を選択し、「新しい実行スクリプト フェーズ」を追加します。
  3. 次のコードを入れます。

    #!/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) to the copied framework directory cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/." "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
    
    # 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 "${PROJECT_DIR}"
    
  4. スキーム選択ドロップダウンで集計を選択します

  5. ビルドして完了です。

問題は、シミュレーターのディレクトリが存在しないディレクトリを指していたことで、2 か所で「フレームワーク」を「${PROJECT_NAME}」に変更するとうまくいきました:)

于 2015-01-17T16:02:45.060 に答える