Can Xcode include application resource files that are generated during the build process? - iphone

I have a bunch of content files for my iPhone app that I generate via shell script. It takes way too long to be a part of the Xcode build process, so I run it periodically.
I don't want to have to continually add these files to my Xcode project in order to get them included my app resources folder. Is there a way to get Xcode to copy the contents of a folder into the app resources at build time? (It'd be a bonus if I could specify other locations, such as the approot documents folder.)
I tried adding a new 'Copy Files Build Phase' to my target, but that didn't seem to work. This seems like a common problem, but I couldn't find anything about it here.
-- Edit (What I did)
Per Jasarien and cdespinosa's suggestions, I did the following in a build script. I decided not to copy to the destination, because that would only work when using the simulator, I don't think that'll work when deploying to a device.
cp -rf "$PROJECT_DIR/mystuff" "$CONFIGURATION_BUILD_DIR/$CONTENTS_FOLDER_PATH/"
-- Edit 2
This doesn't appear to get files onto my iPhone. Any ideas?

You can setup a Run Script build phase in your app's target. Write the script so that it copies the resources into the app bundle.

This is the path i use for output:
${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}
Just copy your files in that directory, it's the bundle (simulator or device).
You can also take a look at my answer here : how to set up a Xcode build rule with a variable output file list?

Related

Xcode Copy Bundle Resources can't find files

Xcode can't find my Storyboards and my Info.plist in my Copy Bundle Resources, So my App doesn't run. I tried to add the Existing files again but they always appear red highlighted. I'm pretty sure it must be a local problem because when i clone the latest update from my repository on my other mac its runs without any problems. I already tried to re-install Xcode, delete files from Xcode/DerivedData and i also deleted the com.apple.Xcode.plist.
Anyone any ideas?
Try to reset your Simulator and then clean your App Build Folder
My experience is that the proposed solution works, but cleaning and re-compiling the entire app whenever a resource has changed is very tedious, especially for larger projects.
Therefore I came up with this solution that forces fresh resources in the app on a per-directory basis, without having to clean or recompile:
Add a 'Run Script Build Phase' (Editor > Add Build Phase > Add Run Script Build Phase)
Copy/paste the following script into the build phase (don't forget to set the actual paths on line 1):
dirsToCopy=("path1/directory1","path2/directory2")
for INPATTERN in "${dirsToCopy[#]}"; do
INDIR=$PROJECT_DIR/$INPATTERN/*
OUTDIR=$TARGET_BUILD_DIR/$CONTENTS_FOLDER_PATH/$INPATTERN
cp -R $INDIR $OUTDIR
done
For those not used to working with shell scripts:
paths on line 1 of the script are relative to the project directory (where the .xcodeproj file resides)
you can add more (or less) paths to the array dirsToCopy if you want
you can change the pattern of files to copy where variable INDIR is defined
you can change how the copying is done (currently, recursive due to -R) by changing the flags to cp in the last line of script within the for block.

xcode: how to save files in "documents" folder in compile/build phase (not via "code on run")?

I have a lot of jpeg+png+html files to add to my app, and of course when i "build" it all my resources files are added/included in myApp mainBundle folder.
I'd like to be able to modify via code, in run time, some of my resources, but:
1) we cannot "write" files via code in run-time in mainBundle
2) we can do it just in "documents" folder (or temp, or...)
3) we can copy files in "Documents" folder just via code in run-time
4) we cannot delete the mainBundle files after coping them in "Documents"
but that means that we will have doubled-sized our app, and in big apps (it's my case) this should be a non-sense, we'll have a lot of big files never used again in the mainBundle...
so i wondered if there was a work-around for this problem (is it just me thinking it's a non-sense?) to add files directly in the "Documents" folder in the "build" phase via xCode, or other similar solutions...
ps
one could be to download all files the first time a user use my app via server/internet directly in "Documents" folder, so my app won't be heavy to download via iTunesStore, but of course this will get a lot of time the first time for end-users, and it could be not well accepted, of course...
Well you can't, since the document directory is created on installing the app. There is no way to do what you want on compile time. Neither you can do it at the install.
Since you needed the file you have to include them in your bundle, i've even included 10MB sqlite database that I copy to to the document direct on first launch. That is just the way it is.
Doesn't work for apps
Copying files to the documents directory during compile time requires you to know that directory in advance. You generally can't know this as the documents directory might not have been created before your app is installed.
Can work for unit tests on the simulator
However, the location of the documents directory depends on the target platform and the kind of bundle you are building. For unit tests based on SenTestingKit executed on the iOS simulator, you can determine the documents directory at compile time by just doing this inside a "Run Script" build phase:
~/Library/Application Support/iPhone\ Simulator/$IPHONEOS_DEPLOYMENT_TARGET/Documents
Note that this really only works for unit test bundles as those are not executed in a dedicated app directory and thus access a "shared" documents directory on the simulator platform.

dyld: Library not loaded - When app run from the command line

I face some difficulties when adding a framework to my project when i run an iPhone app from the command line.
My final goal is to run applications tests from an automated build process.
When i run my app from xCode :
I add a "Copy File" build phase to my target and everything goes fine.
The copy is set to $(BUILT_PRODUCTS_DIR) as "Absolute path"
When i run my app from the terminal (using iphonesim project) i get this error :
dyld: Library not loaded: #rpath/OCMock.framework/Versions/A/OCMock
UIKitApplication:indemnisation[0xb894][26380] Referenced from: /Users/Admin/Library/Application Support/iPhone Simulator/User/Applications/CD5729B5-A674-49B2-91F6-AD398094B6F8/indemINT.app/indemINT
What i dont understand is that the copy build phase just copies the framework files in the same directory as the app.
When i run the app from the command line the framework files are already in the same directory. Does anyone knows why it doesn't work ?
I've also tried to add the OCMock.framework in the following directories (without success) :
/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator3.0.sdk/System/Library
/Library/Frameworks
/Users/Admin/Library/Application Support/iPhone Simulator/User/Applications/CD5729B5-A674-49B2-91F6-AD398094B6F8
Thanks in advance,
Vincent.
I just had this same exact error in Xcode 4.2 (4D199) on Lion. I dragged/dropped the OCMock.framework folder into my project and selected the "copy files" checkbox. I saw the above answers and realized I neglected to add a "Copy Files" build phase to move the framework into place. I added one and dragged it right after the compile files build phase and tried to run my tests again. I couldn't get it to work until I had changed the destination in the "Copy Files" phase to the "Products Directory". Using "Frameworks" or "Shared Frameworks" did not work.
The iPhone does not support traditional Mac OS X frameworks. While the iPhone does use folders that end in ".framework", these folders are structured differently than typical Mac OS X frameworks. Most notably, iPhone frameworks are only permitted to use static libraries, while typical Mac OS X frameworks are dynamically loaded. That the message comes from dyld indicates that you are using a shared libary; however, applications targetting the iPhone may only be statically linked.
OCMock is distributed as a framework, and the iPhone does not allow you build your own arbitrary frameworks (there are good reasons to do this on a device with only 128MB of RAM and no swap).
The solution I see in a lot of places around the web is to put OCMock.framework in /Library/Frameworks or anywhere else in the standard framework search paths. This isn’t a very good solution: your build system is now dependent upon the state of your particular machine. Not good.
Another option would be to add the source for OCMock to your unit test target. This would work but is unnecessary, as your tests will never run on the iPhone,2 so why bother building them for ARM? Executables built for the iPhone simulator, being Mac OS X binaries, can link against dynamic libraries just fine. We can use this to our advantage.
What follows is what I believe is the best way to get OCMock working with iPhone projects:
First, add OCMock.framework to your project. Make sure that it’s being added to your Unit Tests target, not your application.
Next, add a Copy Files phase to your Unit Tests target. Set it up like so:
Destination :Absolute Path
Full Path :$(BUILT_PRODUCTS_DIR)
Now, drag OCMock.framework onto your new Copy Files phase to add it to the list of files to be copied.
Finally, drag the Copy Files phase, which I renamed it to “Copy OCMock”, between the Compile Sources and Link Binary With Libraries phases.
That’s it! Run (and by run I mean build) your tests and everything should work correctly.

Forcing code signing refresh in Xcode

In our environment, we share resources across multiple projects and platforms. When building for iPhone, only a subset of those resources are needed. Since that subset is still considerable, we have a manifest file listing what goes in, which limits the copy. We have our own Python script which does the copy, refreshing only the files which have changed.
I have made a Run Script Phase in Xcode to call that script, but I am having a few issues related to the Code Signing phase.
Since we use a separate manifest file, my Run Script Phase cannot specify any input/output file in the Xcode GUI: it varies depending on what is contained in directories at the time. The side effect of this is that Xcode doesn't strictly know what files will get copied (things happen "under the cover", so to speak).
The problem I have is that if I only modify resource files between builds, rebuilding my app will properly call my script, which copies the appropriate files, only Xcode won't rerun the Code Signing step, and won't re-copy my app to my device.
I found that odd, considering that my resource files are indeed listed in the <app_bundle>/_CodeSignature/CodeResources file, but it looks like Xcode determines rebuilds requirements independent of that (likely only files listed in the project file), which is understandable.
I tried playing tricks by touching my app bundle's directory, or the app's binary itself, but it doesn't quite work. Touching the app's bundle directory doesn't seem to do anything, while touching the binary will work, but NOT FOR THE CURRENT BUILD, only the subsequent one (since no input file requires recompilation, Xcode infers no new binary gets generated, but the next time, it will indeed detect that the binary has been touched, and redo both Code Signing and on).
Still, this is quite an imperfect workaround, because:
Having to build twice is error prone
My dSYM file will needlessly get regenerated
Does anyone know of any way to force the Code Signing step in Xcode (from a Run Script, or elsewhere)?
You can call codesign directly from the command line or a shell script, e.g.
codesign -f -s "iPhone Distribution" --entitlements Entitlements.xcent -vv location/MyApp.app/MyApp
Run man codesign to find out the usage.
You can discover all the internal commands run by viewing the detailed build output in Xcode. Select the Build tab, then click the little icon at the bottom left of that window pane - the one that looks like text (it is next to the warning icon). This will show the full build output in a new pane in Xcode.
I created a shell script calling codesign directly so I could re-sign an existing binary using a new certificate and provisioning profile (e.g. after updating some graphics in the binary).
This turned out to be really complicated as Xcode does some subtle stuff as part of its internal build processes (one example: Xcode embeds the provisioning profile in the resulting app binary, but in the process changes some of its values, e.g. the get-task-allow setting). That meant I had to write a tool to generate an appropriate .xcent file from the provisioning profile, depending on whether a Development/Distribution/App Store build is being done. Hopefully none of that will affect you...

Why can't I just send my zipped Xcode project folder to a friend, and it works?

I always use one folder on my filesystem for an Xcode project. It contains all project files. When I zip it and send it to a friend, she can't just ipen the xcodeproj file. It opens, but all paths are broken and build fails because all the classes don't find the #include'd files. But when I download i.e. some example projects from apple, these work perfectly. What am I doing wrong?
UPDATE:
I'm doing it like this:
1) I create a project and specify an directory on my desktop
2) In that directory I create an "images" directory and add images to it
3) I pull this images directory out and drag it into the Resources Groups&Files. Xcode asks if I want to copy it to destination folder, I click no. Because it's already there. All other things are set to default.
4) all other things are just created within xcode, and xcode just puts all classes in the Classes directory of my project.
5) when I want to add images, I first put them in the directory of the project, and from there drag them into the Images group in xcode. That's to make sure xcode doesn't mess them up with everything else. Otherwise it would just copy them to the root of my project directory rather than inside the Images directory, which doesn't make sense. In fact, the whole Groups&Files filesystem doesn't make sense at all, it's one big mess. Apple's biggest mistake in Xcode so far. That's why I have to do such stupid things.
We don't really know exactly what you're doing so it's hard to see what you're doing wrong.
Perhaps inspect the xcode project files directly, see if you have hardcoded paths. That's a sure fire problem. Make sure you copy resources into the project instead of referencing them externally, etc.
I expect that you have "search path" build setting set to an absolute path on your machine, rather than a path relative to the project. Best way to tell is to post a portion of the build transcript from the failed build and look at the -I directives. If those paths don't exist on your friend's machine, then they should be changed from absolute paths to paths that start with ${SRCROOT}.
Are you just trying to build on the second machine or are you trying to deploy to a device on the second machine? If you are trying to deploy to a device (iPhone or iPod Touch) then it probably has something to do with Code Signing and Certificates.