web-dev-qa-db-ja.com

Xcode 6 iOS Cocoa Touchフレームワークの作成-アーキテクチャの問題

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)

さて、フレームワークのプロジェクトとターゲットの設定を変更しようとしました(Architectures&Build valid architecture only&Valid architectures)。 iOSアプリプロジェクトでも同じことをしましたが、何も機能しません。理解できなかったことがあると思います。

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

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

シミュレータを含むすべてのiOSアーキテクチャで動作するフレームワークを手伝ってくれる人がいれば。

49

申し訳ありませんが、このトピックを長い間公開してきました...一部の皆さんは私の質問に正しく答えています。この質問を書いたとき、完全な(脂肪とも呼ばれる)フレームワーク(すぐに使用できる)に2つのスライスがあったことに気づきませんでした。 1つはiOSデバイス用で、もう1つはシミュレーター用です。 lipoコマンドを使用して2つのスライスを融合するスクリプトを作成し、自動的に完全なフレームワークを得たことを発見したとき。

0

すべての応答に基づいて、 raywenderlich.comの投稿 および Gist によって作成された Chris Conway 私が思いついたのは this です。

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

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

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

UPDATE:手順3のパスが間違っていたGistのエラーを修正しました。 徳久 !!

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

67
cromandini

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

ワークスペース:

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

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

  • Workspace内にiOSCocoa touch Frameworkプロジェクトを作成します。
  • 単純なObjective CクラスMyClass(ヘッダー.hおよび実装ファイル.m)を追加し、メソッド-(void)greetingsを作成します_。
  • Goプロジェクトビルドフェーズ>Headers> Move MyClass.h fromProjecttoPublic
  • スキームをフレームワークプロジェクトに変更し、iOSシミュレーターを選択してからビルドします。 (このフレームワークを統合するアプリがデバイスで実行されている場合は、iOSデバイスを選択します。この例ではシミュレータを使用し続けます)
  • ビルドに問題はないはずです。フレームワークのビルドは、Derived Dataディレクトリにあり、これはOrganizerにあります。

アプリプロジェクト:

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

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

  • シミュレータのビルドライブラリ
  • deviceのビルドライブラリ
  • lipoを使用してそれらを組み合わせます

それについての良い参考文献がウェブ上にあります。たとえば、 here

フレームワークのユニバーサルバイナリを作成します。フレームワークの派生データディレクトリに移動してから/ 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が私のフレームワークプロジェクト名であることに注意してください。

47
vladof81

脂肪(ユニバーサル)フレームワークを作成する手順は次のとおりです。

  1. セットする ONLY_ACTIVE_Arch=NO の中に Build Settingsプロジェクトで。

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

enter image description hereenter image description here

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

    framework_name="${$(basename $(find ./Debug-iphoneos -type d -name '*.framework' -maxdepth 1))%.*}" && \
    cp -R Debug-iphoneos/$framework_name.framework ./$framework_name.framework && \
    lipo -create -output "$framework_name.framework/$framework_name" "Debug-iphonesimulator/$framework_name.framework/$framework_name" "Debug-iphoneos/$framework_name.framework/$framework_name"
    

または:

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

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

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

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

プロジェクトでは、xcworkspace- es:にはありません

this Gist を使用することもできますが、ワークスペースのプロジェクトでは機能しないようです。

13
skywinder

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

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

  • 新しいiOS Cocoa Touchフレームワークを作成します。 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ターゲットを選択して、ビルドフェーズを選択します。
  • [ターゲットの依存関係]で、+記号をクリックしてMyLibを追加します。
  • [ライブラリとリンク]で、+記号をクリックしてMyLib.frameworkを追加します。

Obj-Cアプリの場合

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

Swift app

  • ViewController.Swiftで、インポートMyLibを追加します
  • viewDidLoadで、次の行を追加します。
  • var x:MyLib = MyLib()
  • println( "(x.greetings())")-

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

10
pizzafilms

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

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}"
7
Nadzeya

上記のリンクが以前にあったので私がした古いビデオはもう利用できません。

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

2
naz

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

解決策は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}」に変更することでした:)

1
Tokuriku

Skywinder here によって提供されるリポスクリプトの回答に何かを追加したかった。手順を実行しましたが、フレームワークをシミュレータで実行できず、デバイスのみでした。それを修正するには:

-私はフレームワークのdebug-iphonesimulatorバージョンに入り、Modules/[FrameworkName] .swiftmoduleでi386およびX86ファイルをすべてコピーしました。

-次に、新しく作成されたフレームワークのファットバージョンに移動し、同じフォルダーに移動しました。 i386ファイルとX86ファイルを貼り付け(ARMファイルが既にそこにある)するために)、その後、太ったフレームワークをプロジェクトに追加しました。

出来上がり、彼女はシミュレーターと実際のデバイスで働いています!これはXcode 10/Swift 4.2 btw

1
yousefnjr

Swiftベースのフレームワークにより適切であるvladofによって共有されるアプローチの周りのいくつかの追加ポイント

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

この質問はしばらく前(Xcode 6)に投稿されましたが、最近Xcode 10で同じ問題に遭遇しました。

問題は、構築されたフレームワークが十分なアーキテクチャをサポートしていないことです。

アーキテクチャの略がわからない場合、iPhoneデバイスごとにアーキテクチャが異なるため、完全なリストを次に示します。

  • arm6:iPhone 1、2、3G
  • arm7:最も古いiOS 7対応デバイス[32ビット]で使用されます。 iPhone 4、4s
  • arm7s:iPhone 5および5C [32ビット]で使用されています。 iPhone 5、5c
  • arm64:64ビットの場合ARM iPhone 5S [64ビット]のプロセッサ。iPhone5s以降。
  • arm64e:A12チップセットで使用されます。 iPhone XS/XS Max/XR
  • i386:32ビットシミュレーターの場合
  • x86_64:64ビットシミュレーターで使用

そのため、シミュレータでフレームワークを使用している場合、フレームワークはi386またはx86_64をサポートする必要があります。 iPhone 6でアプリを実行している場合、フレームワークはarm64アーキテクチャをサポートする必要があります。

したがって、ほとんどの場合、フレームワークは前述のすべてのアーキテクチャをサポートする必要があります。

次に、問題の解決方法に戻ります。デバイスとシミュレータの両方のフレームワークを構築する必要があります。

デバイス用のビルド方法:

  1. 「一般」で、「展開ターゲット」を指定します。
  2. 「ビルド設定」で、「アクティブなアーキテクチャのみをビルド」を「いいえ」に変更します
  3. [ビルド設定]で、[有効なアーキテクチャ]に必要なすべてのアーキテクチャがリストされていることを確認します。通常、デフォルトオプション(arm64、arm64e、armv7、armv7s)を使用します。
  4. 「スキームの編集」->「実行」->「ビルド構成」に進み、「ビルド構成」を「リリース」に変更します。
  5. アクティブなスキーム「Generic iOS Device」を選択します。 Cmd + Bを押してプロジェクトをビルドします。
  6. Xcodeプロジェクトの「Products」フォルダの下にある[MyFrameworkProject] .frameworkを右クリックし、「Finderに表示」を押します。[MyFrameworkProject] .frameworkは、手順2で指定されたすべてのアーキテクチャをサポートします。
  7. [MyFrameworkProject] .frameworkを、このフレームワークを使用する必要があるプロジェクトにドラッグします。さらに、[MyFrameworkProject] .frameworkを「Embedded Binaries」にもドラッグします。

シミュレータ用のビルド方法:

  1. 上記と同じ手順1〜4。
  2. アクティブなSchemeとしてシミュレータを選択します。 Cmd + Bを押してプロジェクトをビルドします。
  3. 上記と同じ手順6〜7。

デバイスとシミュレータの両方のビルド方法:

デバイス用のフレームワークを作成したら、シミュレーター用のフレームワークとデバイス用のフレームワークを「リポ」コマンドで組み合わせる必要があります。シミュレーターのフレームワークの名前を[MyFrameworkProject] _sim.frameworkに変更し、両方のフレームワークを同じフォルダーにコピーします。ターミナルで以下のコマンドを実行します(フォルダー内にいることを確認してください):

lipo -create -output [MyFrameworkProject].framework/[MyFrameworkProject] [MyFrameworkProject].framework/MyFrameworkProject [MyFrameworkProject]_sim.framework/MyFrameworkProject

[MyFrameworkProject] .frameworkは、シミュレーターとデバイスの両方をサポートする最終製品です。

1
nyus2006