I am building a module for React Native, as a part of this, there is some native iOS code that is wrapped in a cocoapod. I have this working fine, and I can install the cocoapod and see the native classes from the RN side no problem. One of the native classes is trying to get the path to a local mp3 file inside a sub folder proj/Audio/file.mp3. Using the following ObjC code: NSString *path = [[NSBundle mainBundle] pathForResource:#"file" ofType:#"mp3" inDirectory:#"Audio"];
This is returning nil and as such causing an error when trying to get the NSURL for the file. I have the mp3 extension added to the podspec # s.source_files = "ios/**/*.{h,m,swift,mp3}" so it is moving the file over. However, I assume I have to be missing something as it ultimately cannot find the file.
I have gone into the source xcode project and added the mp3 file to the Copy files phase in build phases. I have also made sure that the file was linked to the target. I am not sure what else I could be missing at this point for it to not be able to be found.
Instead of putting the mp3 file in source_files of your podspec, try using resource_bundles; see the documentation here. Basically it lets you define resource bundle files that CocoaPods creates for you with the assets that you specify, for example:
s.resource_bundles = {
'Audio' => ['ios/**/*.mp3']
}
You can load the bundle file resource that CocoaPods created (create a NSBundle object from its URL by its name - Audio in the above example, and extension - bundle), then get a path from resources inside this bundle (the same method that you used on the mainBundle).
I know this is an old post, but I was struggling with this myself. I completely agree with Artal, to sum up you need to
let bundlePath = Bundle.main.path(forResource: "Audio", ofType: "bundle");
let bundle = Bundle(path: bundlePath!)
maybe guard your the path,
Related
I have created a Swift framework and I'm trying to make it into a CocoaPod.
These are all the files in the framework.
I add all the source files plus the .json file in the podspec like so.
spec.source_files = "CountryPicker"
spec.resource = "CountryPicker/countries.json"
The files do get added.
Or so it seems. Because when I try to load the json file within the framework code like this
let path = Bundle(for: Self.self).path(forResource: "countries", ofType: "json")!
it keeps failing because it's returning nil every time.
I tried all the methods described here but it's not having any effect. Any idea what I'm doing wrong here?
I am able to do this for other assets, assume it will be the same for you.
First, find the name of your Pod's bundle. I have redacted a lot of this, but if you follow the arrows, you can see how to get it via Xcode.
The order would be:
Select the Pods project
Select the target associated with your pod
With General selected, locate the Bundle Identifier
Once you have that, you can then instantiate the Bundle:
let yourPodBundle = Bundle(identifier: "org.cocoapods.your_pod_sname_here")
Now, pull it all together
let path = yourPodBundle?.path(forResource: "countries", ofType: "json")!
My project structure is in such a way that I have 2 projects named as ProjectA and ProjectB. Now for these 2 projects, I have created a framework named as ProjFramework.
I have added common files of these 2 projects inside the framework and then added framework in the projects separately. Till now I am able to access all the files and vars. Now I added the images also in the framework and when I am trying to display them in UI then I am getting an error saying unable to read this .png.
As I know I need to include the framework somehow but I don't know how. Please help me in sharing common images b/w 2 XCode projects.
Thanks in advance.
An alternative to #arunjos007' method is to (a) create a bundle of your images, then (b) retrieve from the bundle.
Let's say you have a Framework called Kernel, and you wish to access two types of files - cikernel and png.
Creating a bundle:
Move all your files/images into a new folder on your desktop. Name it whatever you wish. In my example I named them cikernels and images.
Rename your folders, with a .bundle extension. In my example they became cikernels.bundle and images.bundle. You will see the warning below... choose "Add".
Drag the bundle into your framework project. You can expand the bundle to see the contents. Also, you can add/delete/edit the contents of the bundle.
Retrieving files from the bundle:
I've created two public functions, one to retrieve files and one to retrieve images. They are pretty much the same, except for (a) the return type and (b) error handling. (I probably should add some to the UIImage function - but since I have total control on the code - it's not going to be used by anyone else - it's not critical.)
public func returnImage(_ named:String) -> UIImage {
let myBundle = Bundle.init(identifier: "com.companyName.frameworkName")
let imagePath = (myBundle?.path(forResource: "images", ofType: "bundle"))! + "/" + named
let theImage = UIImage(contentsOfFile: imagePath)
return theImage!
}
public func returnKernel(_ named:String) -> String {
let myBundle = Bundle.init(identifier: "com.companyName.frameworkName")
let kernelPath = (myBundle?.path(forResource: "cikernels", ofType: "bundle"))! + "/" + named + ".cikernel"
do {
return try String(contentsOfFile: kernelPath)
}
catch let error as NSError {
return error.description
}
}
One last note: The identifier is defined in the Framework target's General tab. Typically it's in the form com.companyframework*. Change that line to your's.
Before Building and distributing your framework, you should copy files that need to carry with your framework.
To copy files, Click your framework project target, go to "Build Phases" tab and you can see a section called "Copy Files". Add your files here(See below screenshot)
Then build your framework project, after a successful build your distributable framework will be generated in your Products folder. It will look like YourFrameworkProjectName.framework.
Add this file to other projects which need your framework.
Note: If you just want to run your project by connecting with your framework project, you can be done it by adding build dependency. See StackOverflow question here
I'm up-skilling on swift. I'm writing a framework that will depend on a file that will not be part of the framework. It will be created by the app that imports the framework.
It works fine when running on the simulator but the live rendering in interface builder craps out because it can't find the file. I've done the same thing previously in Objective-c and I know the solution is that the interface builder is using a different bundle. The solution was to use:
[[NSBundle bundleForClass:[self class]] pathForResource:<fileName> ofType:<fileType>]
I've searched online and I believe the equivalent in swift is:
let path:String? = NSBundle(forClass: self.dynamicType).pathForResource(<fileName>, ofType: <fileType>)
however it always returns nil inside the live rendering. While:
let path:String? = NSBundle.mainBundle().pathForResource(<filename>, ofType: <fileType>)
works fine in the simulator, meaning the file is clearly there and part of the finished app. Anyone have any idea why this might be? is there a setting somewhere i'm missing also?
In Swift the code looks like this:
return NSBundle.init(forClass: <ClassName>.self).pathForResource(<FileName>, ofType: <FileType>)
for example, to get localization resources in Arabic from another bundle your code would look like this:
return NSBundle.init(forClass: <ClassName>.self).pathForResource("ar", ofType: "lproj")
I think part of your problem might be that you are trying to hit another bundle but you are accessing the bundle for the current class with your call to [[NSBundle bundleForClass:[self class]].
I haven't written much objective-C but I suspect you will be able to translate this on my behalf.
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.
When I use
NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:#"sqlite"];
The NSBundle class, instead of returning nil, for a given file name when the file is not included in Xcode, seems to be creating the file no matter what. I tried removing file from xcode, it did not work, then I went to the path for simulator for the project (that path is generated by pathForResource) :
/Users/USER_NAME/Library/Application
Support/iPhoneSimulator/6.0/Applications/APP_CODE/APP_NAME.app/sampleDB.sqlite
Before I run program in the debugger, I delete file "sampleDB.sqlite" manually. Every time the method pathForResource is called the file seems to magically reappear in the folder.
The documentation states :
Return type :
The full pathname for the resource file or nil if the file could not be located.
EDIT:
With a pathForResource commented out, files removed - I still get that file magically reappearing in the bundle. Any Ideas?
Make a clean build to make sure that the file gets removed from the app bundle.