I have a static library where I need some graphics resources as Images.
In my class I would to add an image in this way:
[UIImage imageNamed:#"myImage.png"]
but it not work...
how can I do it?
You can't provide anything other than code with a static library. This is because .a files are a simple archive of object files, with the added ability under Mac/iOS of supporting multiple CPU architectures.
The only option you have is to create a Framework, which can provide code as well as other resources.
Once you have that bundle, you can access to the resources you have there like this:
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:#"YourBundle" ofType:#"bundle"];
NSString *imagePath = [[NSBundle bundleWithPath:bundlePath] pathForResource:#"yourImage" ofType:#"png"];
UIImage *image= [[UIImage alloc] initWithContentsOfFile:imagePath];
In Xcode, if you link a static library, the code from the library is included directly into your executable. No files are copied to the application bundle, so there's no way to copy the image.
If you have the image file with your static library, you can simply copy it to your application bundle by adding a copy files build phase to your target in Xcode.
I found the solution ..
I explored the bundles directory (compiled) and I've noticed that my images (.png) they had all the iestensione .tiff
To avoid this I set the key HIDPI_COMBINE_IMAGES in my bundle buid setting as NO
..so I can recover my pictures as suggested by e1985
Make a Framework target, not static library.
Make sure "Copy Bundle Resources" exists in Build Phases for your Framework. Add your resource files there.
Then to find the file in the Framework bundle from an outside project I just do this:
NSArray<NSBundle *> * bundles = [NSBundle allFrameworks];
NSString * filePath;
for (int i = 0; i < bundles.count; i++) {
filePath = [[bundles objectAtIndex:i] pathForResource:#"picture" ofType:#"png"];
if (filePath != nil) break; // found
}
Related
So I am creating an iOS static library project that will also support Cocoapods.
This library project will contain js files which you need to ship in a bundle (It won't compile into .a file). In the code, the way I reference these js files are, finding the bundle file first, then get the file from bundle. This works.
NSBundle *bundle = [NSBundle bundleWithURL:[
[NSBundle mainBundle] URLForResource:#"resource" withExtension:#"bundle"]];
NSString* html = [bundle pathForResource:#"foo" ofType:#"js"];
However, in Cocoapods distrubtion, these resource files are configured using
s.ios.resource_bundle = {
'resources' => ['foo.js']
}
And in code, you need to reference it by
[NSBundle mainBundle] pathForResource:...
There will be no custom bundle(resource.bundle) file anymore, all will be merged in mainBundle
Is there an universal way to references these js files? Thanks!
I have images.xcassets listed ounder copy bundle resources, and I did try to just state the file name by itself: MSB_big_icon , before trying to add the path within images.xcassets.
Can anybody tell me what I'm doing wrong?
NSString *path = [[NSBundle mainBundle]pathForResource:#"/Raymio_android_images/MSB_big_icon.imageset/MSB_big_icon" ofType:#"png"];
NSLog(#"path: %#", path);
MSBIcon *tilecon = [MSBIcon iconWithUIImage:[UIImage imageWithContentsOfFile:path] error:&error];
David Ansermot is right that xcassets is a much better approach and strongly preferred. If you can't use that (running on older versions of iOS for instance), still put everything in one directory and use imageNamed:. This has significant caching benefits over hand-loading the file.
An asset catalog (xcassets) is a (relatively) new, unified way of managing image resources. The images are no longer accessible as separate files on the disk. Instead, imageNamed: consults the asset catalog and fetches the correct asset.
Prior to asset catalogs (and still, for non-images), assets were stored in localized directories. All of your unlocalized assets would be put into a directory called Resources (no matter where those files might appear to be in your source tree, and no matter how those files might be arranged in your Xcode folders). Localized files would be stored in directories like English.lproj or French.lproj. When you make NSBundle calls to load MyImage, it looks at each localized directory in the order the user has configured, and if it cannot find it in any of those directories, it looks in Resources.
Now it is possible to store full directories as "a resource" by marking them as directory references in Xcode. In that case, the whole directory would be copied into Resources or the appropriate localized directory. In order to find files inside such a directory you can use the ...inDirectory: version of the NSBundle methods.
So most of the time, you want to just use imageNamed:, which is going to fetch things out of the asset catalog if available, and then search localized directories, and then look in Resources. If you need to find a non-image, or if for some reason you want the real path to the file, you can compute it like this:
NSString *path = [[NSBundle mainBundle] pathForResource:#"MSB_big_icon" ofType:#"png"];
And if that resource were in a directory tree (because it was a directory reference in Xcode), you can access it like this:
NSString *path = [[NSBundle mainBundle] pathForResource:#"MSB_big_icon"
ofType:#"png"
inDirectory:#"Raymio_android_images/MSB_big_icon.imageset"];
Here's a code exemple from one of my apps :
NSString *appKey = #"Applications__GENERIC";
NSString *path = [[NSBundle mainBundle] pathForResource:appKey ofType:#"plist"];
appData = [NSDictionary dictionaryWithContentsOfFile:path];
The "Applications__GENERIC.plist" is stored like this :
Other solutions :
Use the images.xcassets.
Then in your code to load an image, use the code :
UIImage *image = [UIImage imageNamed:#"MyImageWithoutExtension"];
Don't put any path or extension, only the image's name
Try using this:
NSString *path = [[NSBundle mainBundle] pathForResource:#"MSB_big_icon" ofType:#"png" inDirectory:#"Raymio_android_images/MSB_big_icon.imageset"];
What you can also do to debug is to print out
[[NSBundle mainBundle] bundleURL]
Then navigate to that folder and see if the folder structure corresponds to the path you use.
I just struggled with this today, hope it works out for you too.
I have all my images in folder name ImageMe and I like to retrieve image with this name like
[UIImage imageNamed:#"ImageMe/bulk-female.jpg"];
how I get this approach, because I rereiving path name from data base, and in that format it's coming.
If you do not want to modify these images, just create folder name "Resource" under supporting files and save ImageMe folder with your images there. Then use below code to get path of image folder.
NSString *theResourcePath = [NSBundle mainBundle] resourcePath];
NSString *theFilePath = [theResourcePath stringByAppendingPathComponent:#"ImageMe/bulk-female.jpg"];
If you have the images in the main bundle you can get them with
[UIImage imageNamed:#"theNameOfTheImage_WithOutDirecotry"];.
You have to specify only the image name not the directory. This is because when the application is packed in .ipa only the images are copied (the images that are in the Copy Bundle Resources) not the directories.
If you want to pack the images in to one folder you have to create a new bundle but you can not use imageNamed you have to use initWithContentsOfFile:(NSString *)path
Here are some docs UIImage, NSBundle, Bundle Programming Guide
If your all images are present in bundle then you can directly get that images from name.
like this
[UIImage imageNamed:#"1.jpg"];
[UIImage imageNamed:#"2.jpg"]
[UIImage imageNamed:#"3.jpg"]
directly get the images using their names.
And if you want to laod that images to particular folder of bundle.
NSString *Path = [NSBundle mainBundle] resourcePath];
NSString *FilePath = [Path stringByAppendingPathComponent:#"ImageMe/bulk-female.jpg"];
try this one this might be helpful to you.
Add your images in a floder & than add that folder to your project like this
after adding the folder to your project, you can access your images with the following code.
NSString *bundlePath = [NSBundle mainBundle] bundlePath];
NSString *imagePath = [bundlePath stringByAppendingPathComponent:#"ImageFolder/imagename.jpg"];
Hope this will solve your problem
I'm creating a Static Library for iOS applications. I almost completed it, but there is an issue with the resources.
My Static Library uses a lot of images and sound files. How can I transfer it with my Static Library ?
I know we can wrap it on a bundle and give it along the .a file. But I don't know how to wrap Images and sound files in a Bundle file.
What I did:
I searched a lot, but couldn't find any useful links.
I got Conceptual CFBundles reference, but didn't find any solution for my problem.
I checked the file templates available for XCode, but didn't saw any bundle type other than Settings Bundle.
There are several good reasons to build an application with multiple bundles and several different ways to do it. To my experience the best way is open Xcode and create a new bundle project:
Select: File -> New Project… -> Group Mac OSX (!) -> Framework & Library -> Bundle. Add your resource files to the project.
Build the bundle as you build other iPhone apps.
You may add this project to your static library project and rebuild it all the time the library is changed. You must know that the bundle itself will not be linked to your library file.
In your app projects add the .bundle file to your project as an ordinary resource file (Add -> Existing Files… -> find and select the above built .bundle file. Do not copy it).
Example :
// Static library code:
#define MYBUNDLE_NAME #"MyResources.bundle"
#define MYBUNDLE_IDENTIFIER #"eu.oaktree-ce.MyResources"
#define MYBUNDLE_PATH [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: MYBUNDLE_NAME]
#define MYBUNDLE [NSBundle bundleWithPath: MYBUNDLE_PATH]
// Get an image file from your "static library" bundle:
- (NSString *) getMyBundlePathFor: (NSString *) filename
{
NSBundle *libBundle = MYBUNDLE;
if( libBundle && filename ){
return [[libBundle resourcePath] stringByAppendingPathComponent: filename];
}
return nil;
}
// .....
// Get an image file named info.png from the custom bundle
UIImage *imageFromMyBundle = [UIImage imageWithContentsOfFile: [self getMyBundlePathFor: #"info.png"] ];
For more help you can check these good articles
iOS Library With Resources
Resource Bundles
Hope it helps you.
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?
I know this is an old thread, but to keep new people from making the same mistakes here is a note:
As of Xcode 6 and iOS8, Apple has a fully supported first party Dynamic Framework solution built in. For more information look here: https://developer.apple.com/library/ios/documentation/DeveloperTools/Conceptual/WhatsNewXcode/Articles/xcode_6_0.html#//apple_ref/doc/uid/TP40014509-SW14
But the short of it is, create a new project and choose the Cocoa Touch Framework template.
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]];
I don't manually manage frameworks anymore but use and recommend CocoaPods instead.
Original answer:
Use the fake framework #wattson12 mentioned. It will compile and save the resources as well.
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.
In order to load an image from a dynamic framework in Swift 3:
UIImage(named: "name", in: Bundle(for: type(of: self)), compatibleWith: nil)
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
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.
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.