IOS Static Framework with resources inside

2019-01-14 03:06发布

I'm trying to create a framework that keeps some common code I use around in my projects. I found online tutorials and managed to create a framework but I still have one problem related to resources (xibs, images, etc).

Let's say I have a MainViewController.xib which has a UIImageView using a test.png. All these are in my framework package.

When I use the framework in another project, I add it to the "Copy Bundle Resources" build phase. The problem is that the xib is only accessible using a path like dummy.framework/Resources/MainViewController.xib and the UIImageView inside can't load test.png.

It seems that the UIImageView will try to load the png from the root of the bundle, and not from the relative folder where the xib is also stored.

Has anybody managed to create a framework with code and resources and use it in another project?

7条回答
混吃等死
2楼-- · 2019-01-14 03:11

I created a framework target and to access images inside its asset catalog I did the following:

UIImage *img = [UIImage imageNamed:@"IMAGE_NAME_HERE" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:[UITraitCollection traitCollectionWithDisplayScale:[UIScreen mainScreen].scale]];
查看更多
劫难
3楼-- · 2019-01-14 03:12

I don't manually manage frameworks anymore but use and recommend CocoaPods instead.


Original answer:

  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
    

You could also just drag the framework to your Copy Resources step, but then you'll be adding unnecessary headers and compiled code as well.

Edit

To use these resources from IB, for instance a png file, replace:

MyImage

by:

MYFrameworkResources.bundle/MyImage.png

It will preview a broken image icon but will work when running.

Load a Nib from code:

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

Finally you can add these methods in a NSBundle category to ease access to Nib resources that my be in your main bundle or in MYFrameworkResources.bundle:

@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

It will first look into your application bundle and then in MYFrameworkResources.bundle, etc.

查看更多
Deceive 欺骗
4楼-- · 2019-01-14 03:21

Basic frameworks do not include most kinds of resources, to include resources use this "fake" framework library

You end up with a .embeddedframework folder which contains the actual framework, but also includes any resources which you add to the Copy Bundle Resources build phase. Ive used it to include xibs, core data models, images, and plists

查看更多
趁早两清
5楼-- · 2019-01-14 03:25

As of Xcode 7 we can now use Asset Catalogs. In my experiments I've found that u can reference files in the same workspace bit different projects removing the need to micro manage assets in build phases or worrying about targets.

查看更多
贼婆χ
6楼-- · 2019-01-14 03:31

In order to load an image from a dynamic framework in Swift 3:

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

查看更多
兄弟一词,经得起流年.
7楼-- · 2019-01-14 03:33

Short answer: you can't.

When you compile the app, the bundle is generated with the resources of the "main" project, ignoring the resources in linked frameworks. This includes images, xib's, plist's, etc. (anything that isn't a source file)

What you need to do is add those resources to your main project so that they are available for use inside your application, not the happiest way around it but it'll work.

查看更多
登录 后发表回答