ios 如何在另一个框架中添加一个框架(Umbrella Framework)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34681435/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 08:33:14  来源:igfitidea点击:

How to add a framework inside another framework (Umbrella Framework)

iosframeworks

提问by Laur Stefan

I have build a framework using the following tutorial.

我已经使用以下教程构建了一个框架。

And I also got thisframework.

我也得到了这个框架。

I am trying to implement the second Framework inside mine, from what I read in the Apple docs the resulting framework is called "Umbrella Framework".

我正在尝试在我的内部实现第二个框架,从我在 Apple 文档中读到的结果框架称为“伞框架”。

I added the second framework in framework using drag and drop and the verify that it is in the "Link Binary With Libraries".

我使用拖放在框架中添加了第二个框架,并验证它是否在“Link Binary With Libraries”中。

And after I tried to make the next import in one of the classes of the my framework:

在我尝试在我的框架的一个类中进行下一次导入之后:

#import <CrashReporter/CrashReporter.h>

I received an error as the imported framework is not visible.

我收到一个错误,因为导入的框架不可见。

Also I have seen the stackoverflow post: How to create an umbrella framework in iOS SDK?

我也看过stackoverflow帖子: 如何在iOS SDK中创建一个伞形框架?

Update

更新

Have anyone tried to extract the PLCrashReporter classes for iOS and integrate the in a project?

有没有人尝试为 iOS 提取 PLCrashReporter 类并将其集成到项目中?

You can find my attempt here.

你可以在这里找到我的尝试。

回答by Vel Genov

The temptation to distribute another framework is understandable, but highly discouraged. I'll try to explain why that is (with arguments), and also provide some great alternatives that will help in your case.

分发另一个框架的诱惑是可以理解的,但非常不鼓励。我将尝试解释为什么会这样(带参数),并提供一些很好的替代方案,对您的情况有所帮助。

Umbrella framework are intended for use, only when you are the distributor of both frameworks, you have full control over them, and they will be distributed together.

Umbrella 框架是为使用而设计的,只有当您是两个框架的分发者时,您才能完全控制它们,并且它们将一起分发。

There is a popular quote on the topic from Apple, where they say that they discourage umbrella frameworks.

有一个来自 Apple 的关于这个话题的流行引述,他们说他们不鼓励伞形框架。

Don't Create Umbrella Frameworks

While it is possible to create umbrella frameworks using Xcode, doing so is unnecessary for most developers and is not recommended. Apple uses umbrella frameworks to mask some of the interdependencies between libraries in the operating system. In nearly all cases, you should be able to include your code in a single, standard framework bundle. Alternatively, if your code was sufficiently modular, you could create multiple frameworks, but in that case, the dependencies between modules would be minimal or nonexistent and should not warrant the creation of an umbrella for them.

不要创建伞形框架

虽然可以使用 Xcode 创建伞形框架,但对于大多数开发人员来说,这样做是不必要的,也不推荐这样做。Apple 使用伞形框架来掩盖操作系统中库之间的一些相互依赖关系。在几乎所有情况下,您都应该能够将您的代码包含在单个标准框架包中。或者,如果您的代码足够模块化,您可以创建多个框架,但在这种情况下,模块之间的依赖关系将是最小的或不存在的,并且不应保证为它们创建一个保护伞。

First, here is what most developers do in this situation, since there are many frameworks out there that rely on others.

首先,这是大多数开发人员在这种情况下所做的,因为有许多框架依赖于其他框架。

Inform the user that your framework requires the use of another third party framework. This is completely standard and expected in most cases. Then link to it at the system level. It's as simple as that. Your framework will find the third party and function seemlesly, just like using a native framework. Take UIKitfor example. To link to the third party, follow the steps in the next section. It can certainly be done the standard way, but using a tool like CocoaPods will make your project easier to maintain.

通知用户您的框架需要使用另一个第三方框架。在大多数情况下,这是完全标准和预期的。然后在系统级别链接到它。就这么简单。您的框架将找到第三方并无缝运行,就像使用本机框架一样。以UIKit为例。要链接到第三方,请按照下一部分中的步骤操作。它当然可以通过标准方式完成,但是使用 CocoaPods 之类的工具将使您的项目更易于维护。

To completely answer your question, instead of adding the third party framework the usual way, since you could run into problems and complications, use CocoaPodsto add it for you. This way, you eliminate possible issues and also get the added benefit of CocoaPods getting you the exact version of the third party you will need.

要完全回答您的问题,不要像往常一样添加第三方框架,因为您可能会遇到问题和并发症,请使用CocoaPods为您添加它。通过这种方式,您可以消除可能的问题,并获得 CocoaPods 的额外好处,让您获得所需的第三方的确切版本。

Here is the CocoaPods Podfile for an app called "CrashTest"

这是名为“CrashTest”的应用程序的 CocoaPods Podfile

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

Just to clarify, when you are developing the framework, it will still be added to your project and visible. The big difference here is that it will be distributed separately from your framework, and end users will have to add both to their projects in order to make things work.

澄清一下,当你开发框架时,它仍然会被添加到你的项目中并且可见。这里的最大区别在于它将与您的框架分开分发,最终用户必须将两者都添加到他们的项目中才能使工作正常进行。

Here are the reasons why this is done this way.

以下是这样做的原因。

For example, you would like to include PLCrashReporterin your framework. Say another framework vendor wants to include it in theirs as well. The application using both frameworks will have PLCrashReporterincluded twice (as part of each umbrella framework). Possible even different versions of it. This could lead to serious issues inside of the user application. If both umbrella frameworks are linking to PLCrashReporter, as described in the previous section, this issue would be avoided completely.

例如,您希望包含PLCrashReporter在您的框架中。假设另一个框架供应商也希望将它包含在他们的框架中。使用这两个框架的应用程序将PLCrashReporter包含两次(作为每个框架框架的一部分)。甚至可能有不同的版本。这可能会导致用户应用程序内部出现严重问题。如果两个伞形框架都链接到 PLCrashReporter,如上一节所述,则可以完全避免此问题。

Another point, which I touched on above is versioning. When distributing an umbrella framework, you need to be able to control the versions of all frameworks involved, and you have no control over the third party framework. Which would again lead to a similar problem as the one described above.

我在上面提到的另一点是版本控制。在分发一个伞形框架时,你需要能够控制所涉及的所有框架的版本,而你无法控制第三方框架。这将再次导致与上述问题类似的问题。

I know that this approach does not provide a direct answer to the question, but it's trying to discourage a bad practice instead, while pointing the industry standard way of doing things.

我知道这种方法并没有直接回答这个问题,但它试图阻止不好的做法,同时指出行业标准的做事方式。

回答by Segev

Apple discourages you to create an umbrella framework but yet, still says it is possible with some description on its structure etc'so i'll focus on how to actually do it.

Apple 不鼓励您创建一个伞状框架,但仍然表示可以对其结构等进行一些描述,因此我将专注于如何实际操作。

I must mention that if you control one or more frameworks, bundling them into one is not such a bad idea and can help the end-developer.

我必须提到,如果您控制一个或多个框架,将它们捆绑成一个并不是一个坏主意,可以帮助最终开发人员。

Creating an umbrella framework is really simple now on recent Xcodes (7 and up)

现在在最近的 Xcode(7 及更高版本)上创建一个伞形框架非常简单

Here's how to do it.

这是如何做到的。

First create a framework:

首先创建一个框架:

enter image description here

在此处输入图片说明

Drag CrashReporter.frameworkto the Umbrella framework project:

拖到CrashReporter.frameworkUmbrella 框架项目:

enter image description here

在此处输入图片说明

Example code to make sure both frameworks are functional:

确保两个框架都能正常工作的示例代码:

Umbrella.h:

伞.h:

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

@interface Umbrella : NSObject

+(void)sayHelloFromUmbrella;

@end

Umbrella.m:

伞.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

Build and you'll get the Umbrella.framework(that contains CrashReporter.framework) in your build folder.

构建,您将在构建文件夹中获得Umbrella.framework(包含CrashReporter.framework)。

Drag Umbrella.frameworkand place it inside "Embedded Binaries" in the project that is going to use it:

Umbrella.framework它拖放到要使用它的项目中的“嵌入式二进制文件”中:

enter image description here

在此处输入图片说明

Then just import your finished framework.

然后只需导入您完成的框架。

ViewController.mfrom the project that we just dragged Umbrella.frameworkto:

ViewController.m来自我们刚刚将Umbrella.framework拖到的项目:

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

@interface ViewController ()

@end

@implementation ViewController

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

Which will output this:

这将输出:

Hey from Umbrella 
crashObject: <PLCrashReporter: 0x7fb441d5c650>

Which tells us that both frameworks are working.

这告诉我们两个框架都在工作。

回答by MinamiTouma

HERE IS AN DEMO PROJECT:

这是一个演示项目:

Umbrella Framework Demo

Umbrella 框架演示

All answers under this line are wrong, cause they just do the thing that manually copy sub frameworks into "umbrella framework"

此行下的所有答案都是错误的,因为他们只是将子框架手动复制到“伞形框架”中

Embedding a framework within a framework (iOS 8+)

在框架中嵌入框架(iOS 8+)

How to create an umbrella framework in iOS SDK?

如何在 iOS SDK 中创建一个伞形框架?

How to add a framework inside another framework (Umbrella Framework)

如何在另一个框架中添加一个框架(Umbrella Framework)

Umbrella framework

伞形框架

First thing we should know that "umbrella framework" is a conception in Mac OS not in iOS, the official document is here

首先我们应该知道“伞形框架”是Mac OS中的一个概念,而不是iOS,官方文档在这里

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

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

if you want to create an un-recommend "UmbrellaFramework", you must do these process step by step, and know details during the compile and link periods

如果你想创建一个不推荐的“UmbrellaFramework”,你必须一步一步地做这些过程,并在编译和链接期间了解细节

  1. Change all sub frameworks Mach-O to Static Library, it means compile this target as Static Library(.a)
  2. Manually copy all sub-Framework into UmbrellaFramework during the build phase(Like other answers did)
  3. Add "FakeBundleShellScript" to Target "UmbrellaFramework", it makes all sub frameworks package itself resources as bundle to join "UmbrellaFramework"
  4. Change the framework load function, you must load the sub-framework resources via path or url, cause it became an bundle, this step means you should have the supreme control of all codes both sub-frameworks & umbrella
  1. 将所有子框架 Mach-O 更改为 Static Library,即将此目标编译为 Static Library(.a)
  2. 在构建阶段手动将所有子框架复制到 UmbrellaFramework 中(就像其他答案一样)
  3. 将“FakeBundleShellScript”添加到目标“UmbrellaFramework”,使所有子框架将自身资源打包成bundle加入“UmbrellaFramework”
  4. 改变框架加载功能,你必须通过路径或url加载子框架资源,因为它变成了一个bundle,这一步意味着你应该拥有子框架和伞所有代码的最高控制权

!!Here is an example of "FakeBundleShellScript" you can refer

!!这里是“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/

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

As all I said, the key point of to make an un-recommend "UmbrellaFramework" is !!!! [Compile the sub-frameworks as Static, process the resources via fake a bundle], REMEMBER!! Apple always said DONT'T CREATE AN UmbrellaFramework

正如我所说的,制作一个不推荐的“UmbrellaFramework”的关键是!!!![将子框架编译为静态,通过假包处理资源],记住!!Apple 总是说不要创建 UmbrellaFramework

if you can understand Chinese, more details to make an "UmbrellaFramework" can be obtained from my blog

如果你懂中文,可以从我的博客中获得制作“UmbrellaFramework”的更多细节

Alan.li 2017年的文章

Alan.li 2017 年的文章

回答by Adriana Pineda

I tried doing what @Segev suggested, but I kept receiving the error that the embedded framework files were missing.

我尝试按照@Segev 的建议进行操作,但一直收到嵌入式框架文件丢失的错误消息。

However, doing some additional config I managed to make it work!

但是,做了一些额外的配置,我设法让它工作了!

Here's what I did:

这是我所做的:

  1. Add the embedded framework header file inside the umbrella framework project.
  2. In the umbrella header add: import "EmbeddedFramework.h"
  3. Then import the umbrella framework into the desired project and you wont get more errors
  1. 在伞形框架项目中添加嵌入式框架头文件。
  2. 在伞头中添加:import "EmbeddedFramework.h"
  3. 然后将伞形框架导入到想要的项目中,就不会报错了

You will see that the umbrella framework 'Headers' folder will include the 'EmbeddedFramework.h' file

您将看到伞形框架“Headers”文件夹将包含“EmbeddedFramework.h”文件

You can see an example project here:

您可以在此处查看示例项目:

Hope this helps

希望这可以帮助