kstenerud / iOS-Universal-Framework

An XCode project template to build universal frameworks (arm7, arm7s, and simulator) for iOS / iPhone.
2.95k stars 474 forks source link

Bundled Framework #28

Open computerpunc opened 12 years ago

computerpunc commented 12 years ago

The title is more of a proposed solution to 2 issues I've found when using real frameworks:

  1. CoreData momd issue - as mentioned in the troubleshooting, when using the framework xcode retains the contents of the momd directory for core-data but flattens its contents to the root app directory, therefore core-data models cannot be accessed via momd extension but directly using the mom extension. Unfortunately, this imposes problems when using automatic migration by core data and can cause collision with other resources.
  2. Distribution issue - using the current creation method for a universal embedded framework, xcode isn't updated when the framework has new resources. E.g., initial version of the framework had a single resource image.png. I would send the myframework.embeddedframework to my clients and they would add it to xcode. If the second version of the framework had another resouce, image2.png, upon receiving the new version, the client would replace on the HD, the old version with the new one, but xcode would not detect the new resouce. The client would have to remove the old version and add the new version in order for xcode to detect changes.

I would like to propose a solution to the above issues: provide a similar solution as provided in myframework.embeddedframework, but instead of having a myframework.embeddedframework/Resources dir with links to resources in myframework.embeddedframework/myframework.framework/... . Have a real resources in a dir that ends with .bundle.

To see this in action just add the following before the last section in the xcode script:

$ Build embedded framework with bundle structure

echo "Build Embedded Framework with Bundle"

echo rm -Rf "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.bundledframework" rm -Rf "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.bundledframework" echo mkdir "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.bundledframework" mkdir "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.bundledframework" echo cp -a "${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.bundledframework/" cp -a "${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.bundledframework/" echo mkdir "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.bundledframework/${PRODUCT_NAME}.bundle" mkdir "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.bundledframework/${PRODUCT_NAME}.bundle" echo mv "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.bundledframework/${PRODUCT_NAME}.bundledframework/Versions/A/Resources/"* "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.bundledframework/${PRODUCT_NAME}.bundle" mv "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.bundledframework/${PRODUCT_NAME}.framework/Versions/A/Resources/"* "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.bundledframework/${PRODUCT_NAME}.bundle"

$ Replace other platform's framework with a copy of this one (so that both have the same universal binary)


In order to access the bundle in the iOS app you can use the following obj-c code: NSString* bundlePath=[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"myframework.bundle"]; NSBundle* bundle=[[NSBundle alloc] initWithPath:bundlePath];

The above bundle will also be visible when calling: [NSBundle allBundles]

I hope this helps and if appropriate I would be happy to see this get into a release of iOS-Universal-Framework.

Punc.

0xced commented 12 years ago

I'm currently working on something similar here: https://github.com/0xced/iOS-Universal-Framework/commits/resources-bundle

kstenerud commented 12 years ago

Looks promising! Does this mean that anyone using resources contained within a framework must always search via a bundle (i.e. would simply calling [NSData dataWithContentsOfFile:@"data.bin"] fail?). I think partitioning off resources sounds like a good practice, but my worry is about how it will be received by users of frameworks...

Also, would it interfere with xib files when loading views?

computerpunc commented 12 years ago

The resources in the framework are mostly for the consumption of the framework itself (at least this is in my case). Nevertheless, the resources will be able to be accessed directly in the path ..../YOUAPP.app/YOURFRAMEWORK.bundledframework/resource.xyz so there's no need just to go with the "bundle way".

About xib files, I don't think there would be a problem but I'll have to take a further look into this.

computerpunc commented 12 years ago

I didn't find any problem with xib files. I'm using the following code to to have easy access via a single variable frameworkBundle to the bundle. The init is in my main framework class.

static NSBundle* frameworkBundle;
+(void)initialize {
    NSString* bundlePath=[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"framework.bundle"];
    frameworkBundle=[[NSBundle alloc] initWithPath:bundlePath];
    if (nil!=frameworkBundle) return;
    for (NSBundle* bundle in [NSBundle allBundles]) {
        bundlePath=[[bundle bundlePath] stringByAppendingPathComponent:@"framework.bundle"];
        frameworkBundle=[[NSBundle alloc] initWithPath:bundlePath];
        if (nil!=frameworkBundle) return;
    }
    frameworkBundle=[[NSBundle mainBundle] retain];
}