web-dev-qa-db-ja.com

別のフレームワーク内にフレームワークを追加する方法(Umbrella Framework)

チュートリアルに従う を使用してフレームワークを構築しました。

また、 this フレームワークも取得しました。

Apple docsで読んだものから、結果のフレームワークは「Umbrella Framework」と呼ばれます。

ドラッグアンドドロップを使用してフレームワークに2番目のフレームワークを追加し、「ライブラリとバイナリをリンク」にあることを確認します。

そして、私のフレームワークのクラスの1つで次のインポートを試みた後:

#import <CrashReporter/CrashReporter.h>

インポートされたフレームワークが表示されないため、エラーを受け取りました。

また、私はstackoverflowの投稿を見ました: iOS SDKでアンブレラフレームワークを作成する方法?

更新

IOS用のPLCrashReporterクラスを抽出してプロジェクトに統合しようとした人はいますか?

あなたは私の試みを見つけることができます こちら

43
Laur Stefan

別のフレームワークを配布する誘惑は理解できますが、非常にがっかりします。その理由を(引数付きで)説明し、あなたの場合に役立ついくつかの素晴らしい代替手段も提供します。

Umbrellaフレームワークは、両方のフレームワークのディストリビューターであり、それらを完全に制御でき、それらが一緒に配布される場合にのみ、使用を目的としています。

Appleのトピックには、アンブレラフレームワークを思いとどまらせると言う人気のある引用があります。

Umbrellaフレームワークを作成しないでください

Xcodeを使用してアンブレラフレームワークを作成することは可能ですが、ほとんどの開発者にとってこれは不要であり、お勧めしません。 Appleは、アンブレラフレームワークを使用して、オペレーティングシステムのライブラリ間の相互依存関係の一部をマスクします。ほとんどすべての場合、単一の標準フレームワークバンドルにコードを含めることができます。コードが十分にモジュール化されていれば、複数のフレームワークを作成できますが、その場合、モジュール間の依存関係は最小限または存在しないため、それらの傘の作成を保証するべきではありません。

まず、他の人に依存する多くのフレームワークが存在するため、この状況でほとんどの開発者が行うことは次のとおりです。

フレームワークで別のサードパーティフレームワークを使用する必要があることをユーザーに通知します。これは完全に標準であり、ほとんどの場合に予想されます。次に、システムレベルでリンクします。それはそれと同じくらい簡単です。あなたのフレームワークは、ネイティブフレームワークを使用するのと同じように、サードパーティと機能を見かけ上見つけます。 UIKitを例にとります。サードパーティにリンクするには、次のセクションの手順に従ってください。確かに標準的な方法で実行できますが、CocoaPodsのようなツールを使用すると、プロジェクトの保守が容易になります。

あなたの質問に完全に答えるために、サードパーティのフレームワークを通常の方法で追加する代わりに、問題や合併症に遭遇した場合は、 CocoaPods を使用して追加してください。このようにして、起こりうる問題を排除し、CocoaPodsが必要なサードパーティの正確なバージョンを取得するという追加の利点も得ます。

「CrashTest」というアプリのCocoaPods Podfileは次のとおりです。

target 'CrashTest' do
pod 'PLCrashReporter', '~> 1.2.0'
end

明確にするために、フレームワークを開発しているときに、プロジェクトに追加され、表示されます。ここでの大きな違いは、フレームワークとは別に配布されることと、エンドユーザーが物事を機能させるために両方をプロジェクトに追加する必要があることです。

これがこのように行われる理由は次のとおりです。

たとえば、フレームワークにPLCrashReporterを含めたいとします。別のフレームワークベンダーも自社のフレームワークベンダーに含めたいとします。両方のフレームワークを使用するアプリケーションには、PLCrashReporterが2回(各アンブレラフレームワークの一部として)含まれます。異なるバージョンでも可能です。これにより、ユーザーアプリケーション内で深刻な問題が発生する可能性があります。前のセクションで説明したように、両方のアンブレラフレームワークがPLCrashReporterにリンクしている場合、この問題は完全に回避されます。

上記で触れた別のポイントは、バージョン管理です。アンブレラフレームワークを配布する場合、関連するすべてのフレームワークのバージョンを制御できる必要があり、サードパーティのフレームワークを制御することはできません。この場合も、上記と同様の問題が発生します。

このアプローチは質問に対する直接的な答えを提供するものではないことを知っていますが、業界標準のやり方を示しながら、代わりに悪い習慣を思いとどまろうとしているのです。

51
Vel Genov

Appleは、アンブレラフレームワークを作成することをお勧めしませんが、それでも その構造などに関する説明 で可能だと言っているので、実際にそれを行う方法に焦点を当てます。

1つまたは複数のフレームワークを制御する場合、それらを1つにまとめることはそれほど悪い考えではなく、開発者を助けることができることに言及する必要があります。

アンブレラフレームワークの作成は、最近のXcode(7以降)で非常に簡単になりました。

方法は次のとおりです。

最初にフレームワークを作成します。

enter image description here

CrashReporter.frameworkをUmbrellaフレームワークプロジェクトにドラッグします。

enter image description here

両方のフレームワークが機能していることを確認するサンプルコード:

Umbrella.h:

#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>

@interface Umbrella : NSObject

+(void)sayHelloFromUmbrella;

@end

Umbrella.m:

#import "Umbrella.h"
#import <CrashReporter/CrashReporter.h>

@implementation Umbrella

+(void)sayHelloFromUmbrella
{
    NSLog(@"Hey from Umbrella");
    PLCrashReporter *crashObject = [[PLCrashReporter alloc]initWithConfiguration:nil];
    NSLog(@"crashObject: %@",crashObject);
}

@end

ビルドすると、ビルドフォルダーにUmbrella.frameworkCrashReporter.frameworkを含む)が取得されます。

Umbrella.frameworkをドラッグして、使用するプロジェクトの「埋め込みバイナリ」内に配置します。

enter image description here

次に、完成したフレームワークをインポートします。

ViewController.mドラッグしたプロジェクトからUmbrella.frameworkへ:

#import "ViewController.h"
#import <Umbrella/Umbrella.h>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [Umbrella sayHelloFromUmbrella];
}

これはこれを出力します:

Hey from Umbrella 
crashObject: <PLCrashReporter: 0x7fb441d5c650>

これは、両方のフレームワークが機能していることを示しています。

26
Segev

HERE IS AN DEMO PROJECT:

mbrella Framework Demo

この行の下のすべての答えは間違っています。サブフレームワークを「傘フレームワーク」に手動でコピーするだけです

フレームワーク内にフレームワークを埋め込む(iOS 8以降)

iOS SDKでアンブレラフレームワークを作成する方法

フレームワークを別のフレームワーク内に追加する方法(Umbrella Framework)

傘のフレームワーク

「傘フレームワーク」はiOSではなくMac OSの概念であることを最初に知っておく必要があります。公式ドキュメントはこちらです。

https://developer.Apple.com/library/content/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/CreationGuidelines.html#//Apple_ref/doc/uid/20002254-BAJHGGGA

推奨されない「UmbrellaFramework」を作成する場合は、これらのプロセスを段階的に実行し、コンパイルおよびリンク期間中に詳細を把握する必要があります。

  1. すべてのサブフレームワークMach-Oを静的ライブラリに変更します。つまり、このターゲットを静的ライブラリ(.a)としてコンパイルします。
  2. ビルド段階ですべてのサブフレームワークをUmbrellaFrameworkに手動でコピーします(他の回答と同様)
  3. 「FakeBundleShellScript」をターゲット「UmbrellaFramework」に追加すると、すべてのサブフレームワークが「UmbrellaFramework」に参加するためのバンドルとしてリソース自体をパッケージ化します
  4. フレームワークのロード機能を変更します。パスまたはURLを介してサブフレームワークリソースをロードする必要があります。これはバンドルになります。このステップは、サブフレームワークとアンブレラの両方のすべてのコードを最高に制御する必要があることを意味します

!!参照できる「FakeBundleShellScript」の例

APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
BUNDLE_IN_ROOT="$APP_PATH/${FRAMEWORK_EXECUTABLE_NAME}.bundle"
if [[ -e "$FRAMEWORK_EXECUTABLE_PATH" ]]; then
  FRAMEWORK_MACH_O="$(otool -a "$FRAMEWORK_EXECUTABLE_PATH" | head -n 1)"
  FRAMEWORK_FAT_Arch="$(lipo -info "$FRAMEWORK_EXECUTABLE_PATH")"
else
  FRAMEWORK_MACH_O="NO EXIST"
  FRAMEWORK_FAT_Arch="NO EXIST"
fi
echo "FRAMEWORK_EXECUTABLE_NAME is $FRAMEWORK_EXECUTABLE_NAME"
echo "FRAMEWORK_EXECUTABLE_PATH is $FRAMEWORK_EXECUTABLE_PATH"
echo "FRAMEWORK_MACH_O is $FRAMEWORK_MACH_O"
echo "FRAMEWORK_FAT_Arch is $FRAMEWORK_FAT_Arch"
echo "BUNDLE_IN_ROOT is $BUNDLE_IN_ROOT"
if [[ "$FRAMEWORK_MACH_O" =~ "Archive :" ]]; then
  echo "Rmove Static-Mach-O is $FRAMEWORK_EXECUTABLE_PATH"
  rm "$FRAMEWORK_EXECUTABLE_PATH"
  defaults write "$FRAMEWORK/Info.plist" CFBundlePackageType "BNDL"
  defaults delete "$FRAMEWORK/Info.plist" CFBundleExecutable
  if [[ -d "$BUNDLE_IN_ROOT" ]]; then
    rm -rf "$BUNDLE_IN_ROOT"
  fi
  mv -f "$FRAMEWORK" "$BUNDLE_IN_ROOT"
Elif [[ "$FRAMEWORK_FAT_Arch" =~ "Architectures in the fat file" ]]; then
  #statements
  EXTRACTED_ARCHS=()
  for Arch in $ARCHS
  do
    echo "Extracting $Arch from $FRAMEWORK_EXECUTABLE_NAME"
    lipo -extract "$Arch" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$Arch"
    EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$Arch")
  done
  echo "Merging extracted architectures: ${ARCHS}"
  lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
  rm "${EXTRACTED_ARCHS[@]}"
  echo "Replacing original executable with thinned version"
  rm "$FRAMEWORK_EXECUTABLE_PATH"
  mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
fi
done

http://alanli7991.github.io/2017/07/17/%E6%A8%A1%E5%9D%97%E5%8C%9617Framework%E4%B8%8EStaticFramework%E4%BC%AA %E8%A3%85Bundle /

私が言ったように、非推奨の「UmbrellaFramework」を作成するための重要なポイントは!!!! [サブフレームワークを静的としてコンパイルし、偽のバンドルを介してリソースを処理する]、覚えておいてください!! Appleは常にUmbrellaFrameworkを作成しないでください

中国語を理解できるなら、「UmbrellaFramework」を作成するための詳細を私のブログから入手できます。

Alan.li 2017年的文章

13
MinamiTouma

@Segevが示唆したことを試してみましたが、埋め込みフレームワークファイルが見つからないというエラーを受け取り続けました。

しかし、いくつかの追加設定を行うことで、なんとか動作するようになりました!

私がやったことは次のとおりです。

  1. アンブレラフレームワークプロジェクト内に埋め込みフレームワークヘッダーファイルを追加します。
  2. アンブレラヘッダーに以下を追加します。 import "EmbeddedFramework.h"
  3. 次に、アンブレラフレームワークを目的のプロジェクトにインポートすると、エラーが発生しなくなります

アンブレラフレームワークの「Headers」フォルダに「EmbeddedFramework.h」ファイルが含まれることがわかります。

ここでサンプルプロジェクトを見ることができます。

お役に立てれば

5
Adriana Pineda