我使用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。
答案 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及以上版本)上创建一个伞形框架非常简单
这是怎么做的。
首先创建一个框架:
将CrashReporter.framework
拖到Umbrella框架项目中:
确保两个框架都正常运行的示例代码:
<强> 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
并将其放置在将要使用它的项目中的“嵌入式二进制文件”中:
然后只需导入已完成的框架。
我们刚刚将 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)
这是一个演示项目:
这一行下的所有答案都是错误的,因为他们只是手动将子框架复制到“伞框架”中
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)
首先我们应该知道“伞形框架”是Mac OS中不是iOS的概念,官方文档在这里
如果您想创建一个不推荐的“UmbrellaFramework”,您必须一步一步地完成这些过程,并在编译和链接期间了解详细信息
!!以下是您可以参考的“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
正如我所说的,制作一个不推荐的“UmbrellaFramework”的关键是!!!! [将子框架编译为静态,通过假捆绑处理资源],记住!! Apple总是说不要创建一个UmbrellaFramework
如果您能理解中文,可以从我的博客中获取更多详细信息以制作“UmbrellaFramework”
答案 3 :(得分:5)
我尝试过@Segev建议,但我一直收到嵌入式框架文件丢失的错误。
然而,做了一些额外的配置我设法使它工作!
这就是我的所作所为:
你会看到伞形框架&#39; Headers&#39;文件夹将包含&#39; EmbeddedFramework.h&#39;文件
您可以在此处查看示例项目:
希望这有帮助