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

时间:2016-01-08 16:14:56

标签: ios frameworks

我使用following tutorial构建了一个框架。

我还有this框架。

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

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

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

#import <CrashReporter/CrashReporter.h>

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

我也看过stackoverflow帖子: How to create an umbrella framework in iOS SDK?

更新

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

您可以找到我的尝试here

4 个答案:

答案 0 :(得分:50)

分发另一个框架的诱惑是可以理解的,但是非常沮丧。我将尝试解释为什么(带参数),并提供一些有用的替代方案。

伞框架仅供您使用,只有当您是两个框架的分销商时,您才能完全控制它们,并且它们将一起分发。

苹果公司对这个主题有一个很受欢迎的引用,他们说这些引用阻止了伞形框架。

  

不要创建伞框架

     

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

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

通知用户您的框架需要使用其他第三方框架。这是完全标准的,在大多数情况下是预期的。然后在系统级别链接到它。就这么简单。您的框架会发现第三方和函数似乎很有用,就像使用本机框架一样。以UIKit为例。要链接到第三方,请按照下一部分中的步骤操作。它当然可以通过标准方式完成,但使用像CocoaPods这样的工具将使您的项目更容易维护。

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

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

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

只是澄清一下,当您开发框架时,它仍将被添加到您的项目中并且可见。这里的最大区别在于它将与您的框架分开分发,最终用户必须将两者都添加到他们的项目中才能使事情有效。

以下是这样做的原因。

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

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

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

答案 1 :(得分:24)

Apple不鼓励你创建一个伞形框架但是仍然说some description on its structure etc'可以这样做,所以我将专注于如何实际做到这一点。

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

现在,在最近的Xcodes(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.framework(包含CrashReporter.framework)。

拖动Umbrella.framework并将其放置在将要使用它的项目中的“嵌入式二进制文件”中:

enter image description here

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

我们刚刚将 Umbrella.framework 拖到

的项目中的

ViewController.m

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

@interface ViewController ()

@end

@implementation ViewController

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

哪个会输出:

Hey from Umbrella 
crashObject: <PLCrashReporter: 0x7fb441d5c650>

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

答案 2 :(得分:12)

这是一个演示项目:

Umbrella Framework Demo

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

Embedding a framework within a framework (iOS 8+)

How to create an umbrella framework in iOS SDK?

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

Umbrella framework

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

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”添加到Target“UmbrellaFramework”,它使所有子框架将自身资源打包为捆绑加入“UmbrellaFramework”
  4. 更改框架加载功能,您必须通过路径或网址加载子框架资源,因为它成为一个捆绑包,这一步意味着您应该对所有代码都具有最高控制权子框架&amp;伞
  5. !!以下是您可以参考的“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年的文章

答案 3 :(得分:5)

我尝试过@Segev建议,但我一直收到嵌入式框架文件丢失的错误。

然而,做了一些额外的配置我设法使它工作!

这就是我的所作所为:

  1. 在伞框架项目中添加嵌入式框架头文件。
  2. 在伞标题中添加: import&#34; EmbeddedFramework.h&#34;
  3. 然后将伞形框架导入到所需的项目中,您将不会遇到更多错误
  4. 你会看到伞形框架&#39; Headers&#39;文件夹将包含&#39; EmbeddedFramework.h&#39;文件

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

    希望这有帮助