iOS 静态框架及其内部资源

23

我正在尝试创建一个框架,以便在我的项目中使用一些常用代码。我找到了在线教程并成功创建了一个框架,但仍然有一个与资源(xibs、图片等)相关的问题。

假设我有一个MainViewController.xib文件,其中包含一个使用test.pngUIImageView。所有这些都在我的框架包中。

当我在另一个项目中使用该框架时,将其添加到“Copy Bundle Resources”构建阶段中。问题是xib只能使用类似于dummy.framework/Resources/MainViewController.xib的路径访问,而内部的UIImageView无法加载test.png

似乎UIImageView会尝试从捆绑包的根目录加载png,而不是从也保存xib的相对文件夹加载它。

有人成功创建了一个带有代码和资源的框架,并在另一个项目中使用吗?


1
嗨,Andrei,你能告诉我如何将.bundle文件添加到框架目录中吗?我做不到。我的shell脚本可能有些错误。 - Apple
7个回答

14

一切都很好,但是你是否真的成功地将图像资源包含在Xcode 6创建的动态框架中?我自己尝试了所有方法,但无法使其正常工作!苹果似乎没有提供太多相关文档。 - simonthumper
10
是的。这很简单,但可能不太明显。只需像平常一样将图像包含在您的框架中,但要加载它们,您需要引用您的框架的捆绑包。因此,[NSBundle bundleWithIdentifier:@"com.<#company#>.<#framework#>"]; - Ryan Poolos
3
是的,我用 imageNamed:inBundle:compatibleWithTraitCollection 成功了。将 inBundle 参数设为 [NSBundle bundleWithClass:[self class]] 或者根据图片使用的位置设置适当的参数。 - simonthumper
1
是的,我们实际上直到现在都没有尝试过提交。结果发现你可以让它运行,并且甚至可以使用新的框架分发iOS7的企业版本。但是当苹果检查你的构建以上传到商店时,它会拒绝它。几个同事参加了WWDC,他们说它可以在iOS7上运行,但回头发现他们从讲座中删除了45分钟的视频! - simonthumper
1
嗨,Ryan。有什么建议可以在Storyboard或XIB中使用框架中的图像吗?当我尝试时,会出现错误:无法从标识符为“<BundleName>”的包中加载从nib引用的“<ImageName>”图像 - TheNeil
显示剩余9条评论

8
我创建了一个框架目标,并且为了访问其内部的资源目录中的图片,我执行了以下操作:
UIImage *img = [UIImage imageNamed:@"IMAGE_NAME_HERE" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:[UITraitCollection traitCollectionWithDisplayScale:[UIScreen mainScreen].scale]];

非常感谢您,我浪费了很多时间尝试寻找解决方案。而这个解决方案有效 :) - Ismail
5
这段话适用于动态框架,而不是静态框架,因为对于静态框架,bundleForClass:self.class返回的是主应用程序包。 - FreeNickname

5

我不再手动管理框架,而是使用推荐CocoaPods


原始答案:

  1. Use the fake framework @wattson12 mentioned. It will compile and save the resources as well.
  2. Inspired by this script, add this to your target to copy the resources to your app:

    SOURCE_PATH="${TARGET_BUILD_DIR}/MYFramework.framework/Resources/"
    TARGET_PATH="${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MYFrameworkResources.bundle"
    mkdir -p $TARGET_PATH
    cp -R $SOURCE_PATH $TARGET_PATH
    
你也可以将框架拖到“复制资源”步骤中,但这样会添加不必要的头文件和编译代码。
编辑:
例如,要在IB中使用这些资源(如png文件),请执行以下操作:
MyImage

由:

MYFrameworkResources.bundle/MyImage.png

它会显示一个损坏的图片图标,但在运行时会正常工作。

从代码中加载Nib:

[NSBundle loadNibNamed:@"MYFrameworkResources.bundle/MyNib" ...

最后,您可以将这些方法添加到NSBundle类别中,以便轻松访问可能在主捆绑包或MYFrameworkResources.bundle中的Nib资源。
@implementation NSBundle (MyCategory)

+ (NSString *)pathForResource:(NSString *)name
                       ofType:(NSString *)extension
{
    // First try with the main bundle
    NSBundle * mainBundle = [NSBundle mainBundle];
    NSString * path = [mainBundle pathForResource:name
                                           ofType:extension];
    if (path)
    {
        return path;
    }

    // Otherwise try with other bundles
    NSBundle * bundle;
    for (NSString * bundlePath in [mainBundle pathsForResourcesOfType:@"bundle"
                                                          inDirectory:nil])
    {
        bundle = [NSBundle bundleWithPath:bundlePath];
        path = [bundle pathForResource:name
                                ofType:extension];
        if (path)
        {
            return path;
        }
    }

    NSLog(@"No path found for: %@ (.%@)", name, extension);
    return nil;
}

+ (NSArray *)loadNibNamed:(NSString *)name
                    owner:(id)owner
                  options:(NSDictionary *)options
{
    // First try with the main bundle
    NSBundle * mainBundle = [NSBundle mainBundle];
    if ([mainBundle pathForResource:name
                             ofType:@"nib"])
    {
        NSLog(@"Loaded Nib named: '%@' from mainBundle", name);
        return [mainBundle loadNibNamed:name
                                  owner:owner
                                options:options];
    }

    // Otherwise try with other bundles
    NSBundle * bundle;
    for (NSString * bundlePath in [mainBundle pathsForResourcesOfType:@"bundle"
                                                          inDirectory:nil])
    {
        bundle = [NSBundle bundleWithPath:bundlePath];
        if ([bundle pathForResource:name
                             ofType:@"nib"])
        {
            NSLog(@"Loaded Nib named: '%@' from bundle: '%@' ", name, bundle.bundleIdentifier);
            return [bundle loadNibNamed:name
                                  owner:owner
                                options:options];
        }
    }

    NSLog(@"Couldn't load Nib named: %@", name);
    return nil;
}

@end

它将首先查找您的应用程序包,然后查找MYFrameworkResources.bundle等。

谢谢,但界面构建器仍无法正确检测资源。 - Andrei Stanescu
1
你遇到了图片的问题吗?(仅需在前面添加路径)还是Nibs的问题?您还可以检查构建目录,以了解资源在应用程序中的复制位置。 - Rivera

4

在Swift 3中,从动态框架加载图片的方式是:

UIImage(named: "name", in: Bundle(for: type(of: self)), compatibleWith: nil)


它完美地工作。我的情境是,我正在使用自定义框架与资产,但无法使用资产图像。但这对我起作用。 - Manish Mahajan
原始问题是关于如何使用静态框架中的资源。 - Legonaftik

1

基本框架不包括大多数资源,如果要包含资源,请使用this "fake" framework library

你最终会得到一个 .embeddedframework 文件夹,其中包含实际的框架,但也包括你添加到“复制捆绑资源”构建阶段的任何资源。我已经用它来包含 xib、核心数据模型、图像和属性列表。


是的,但如果您在框架中有一个使用框架中资源(比如一张图片)的xib文件,那么您能否在测试应用程序中加载该xib文件呢? - Andrei Stanescu
我现在没有那个项目在我面前,但我非常确定那应该没问题,试试看吧... - wattson12
我得出结论,我想要实现的并不是真正可能的。由于Interface Builder无法显示位于子文件夹中的图像(但在运行时它们有效),因此以捆绑形式提供任何资源真的不可行。最好的方法是在静态库旁边添加一个zip文件,用户可以在其项目中使用该文件夹。 - Andrei Stanescu
您可以通过添加路径:MyResources.bundle/image.png,从IB中引用嵌套在子文件夹中的资源。虽然在IB中看起来不太好看,但它确实有效。 - Rivera

-1
从Xcode 7开始,我们现在可以使用资源目录。在我的实验中,我发现你可以引用同一工作区但不同项目中的文件,这消除了在构建阶段微观管理资产或担心目标的需求。

这个答案与问题无关 - doozMen

-1

简短回答:你无法这样做。

当你编译应用程序时,捆绑包是由“主”项目的资源生成的,忽略链接框架中的资源。这包括图像、xib、plist等(任何不是源文件的东西)

你需要做的是将这些资源添加到你的主项目中,以便它们可以在你的应用程序内使用,虽然这不是最理想的方法,但它会起作用。


1
好的,资源已经复制,但是在一个子文件夹中。 - Andrei Stanescu
3
这是最接近真实情况的答案。但是,你可以强制Xcode从框架中复制资源,但它们将被放置在主包中的子文件夹中。这使得加载它们非常麻烦。 - Andrei Stanescu
6
可以解释一下如何操作吗? - Rob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接