Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xcode not copying latest resource file to iPhone

Tags:

xcode

iphone

I'm writing an iPhone app in Objective-C with Xcode and I have some Lua scripts that run on the device.

I'm having an issue where if I edit a Lua script, save, flick over to Xcode and Build and Run (⌘Y) the latest version of that Lua script is copied into the app bundle but not copied to the device.

The scripts aren't in the Xcode project, I edit them in Textmate. I have a build step which copies the scripts into the app bundle and touches the files, this is being run fine and the latest script version is in the app bundle when I run the app. The files have all been touched, but for some reason when copying the bundle to the device Xcode decides not to copy the latest.

If I stop the app and then Build and Run (⌘Y) again, the latest version is copied across.

My workaround is to save the Lua file, then in Xcode do a Build (⌘B) and then Build and Run (⌘Y), so build the app twice. This always seems to copy the latest version to the device.

Update:

As many have noted, one solution is to clean the targets and rebuild. You can do this, you could also build twice as I have noted above. This problem is easily reproducible (in my setup it happens every time, regardless of how recently the targets were cleaned). I'm hoping for a more reliable/permanent solution

like image 648
whatupdave Avatar asked Jan 17 '11 22:01

whatupdave


4 Answers

You should definitely add those files to your Xcode project. You can still edit them in your other editor, but Xcode will include them in your bundle automatically if you add it to the project. If they aren't getting copied when you build, this is how I resolve it:

  • Right click on the file in Xcode and choose "Touch" which updates the timedate stamp on the file, so it looks "new".

  • On the simulator, choose Reset Content and Settings from the File Menu.

  • In Xcode, do a Build Clean

When you build and run after that it should install the file just fine.

EDIT:

To add external folders to your project that will get included in your bundle and preserve the folder structure intact, all you need to do is:

  • Click on the project icon at the top of the file list on the left.

  • Click the Project menu and Add to Project.

  • Select the folder you want to include and click Add.

  • Unchecked the Copy checkbox and change "Recursively create groups for any added folders" to "Create Folder References for any added folders".

  • When the target is built, open up the bundle and your directory structure will exist inside fully intact.

like image 193
Kenny Wyland Avatar answered Oct 19 '22 23:10

Kenny Wyland


First of all: I feel your pain. I haven't found any good documentation on rolling up your sleeves and digging into the iOS build pipeline if you want to do some interesting (or even just simple) data pipelining using custom scripts.

Second of all: I don't agree that you need to, or even should put all your assets in your Xcode project. That's really a matter of personal preference, and if you've got a complicated enough project, Xcode becomes a beast to navigate your code alone as it is, let alone with all your art assets and data files.

Third: Cleaning is a work-around, as is touching an individual source-code file (Xcode will pick up on this and do the signing/touching of the master directory for you without the need to do a clean build -- a clean build is extremely time consuming if you have a large project or significant assets), but these are really just hacks to get the thing to work without fixing the underlying problem: you need to hit the right dependency to get the copy step to kick in.

I had the same issues you're describing here with the following differences: I'm using a gnu make script to process art resources (audio, data files, images) by doing some basic manipulations (compression, stripping out un-needed things, building fonts, etc). I'm using gnu make because 1.) I know it 2.) I find it easier to put all my rules into one script 3.) I like to keep my data folder nice and hierarchical and 4.) Xcode isn't always the way you want to interface/organize/manage all your data! (though I think it does a great job for code and even small amounts of data in a less complex project)

Anyhow, what I found is that I really had 2 problems: 1.) Code signing and 2.) Copying. The copying is easy, all you need to do is touch the build products folder. In my case I added the following to my make file: "touch $(DIR_CONTENTS)" where I defined "$(DIR_CONTENTS)" using the existing env parms provided by Xcode to the shell when my Xcode is executed: "DIR_CONTENTS = $(BUILT_PRODUCTS_DIR)/$(CONTENTS_FOLDER_PATH)" (you can see the full list of env parms if you click on the 3 horizontal lines in the output log). In your case you'd need to do the equivalent in your lua script. Not sure what that entails, I've been purposely dodging lua for years, but I can't imagine it's too crazy.

The next bit is trickier, 'cuz what I found was that just because you've updated, doesn't mean that the code signing stuff works nicely. In my case I needed to add a ResourceRules.plist file and add my art directory (art/.*) as a dictionary, with a line to omit and a weight. I couldn't find docs on this anywhere, so I copied the ResourceRules.plist file from the generated folder into my source folder, added it to the project, and then pointed the code signing stuff at it. (This would be in the build rules under Code Signing: it'll be your "Code Signing Resource Rules Path")

This isn't really my ideal solution, by the way. I would rather be able to trigger the code-signing step via my script if my data changes, but as I stated earlier I haven't found any useful docs in apple's developer library on how to really dig into the custom builds. You can do the code signing by hand, but I didn't like it.

Hope that helps.

UPDATE:

I figured I'd add some example code.... here are some relevant excerpts from my makefile:

# Near the beginning, where I do my variables n' such, I define the 
# directory in a variable. Note that BUILD_PRODUCTS_DIR and CONTENTS_FOLDER_PATH
# are environment variables set by XCode and will be filled with the corresponding
# paths
DIR_CONTENTS     = $(BUILT_PRODUCTS_DIR)/$(CONTENTS_FOLDER_PATH)
DIR_DEST_ART     = $(DIR_CONTENTS)/art
DIR_DEST_FONTS   = $(DIR_DEST_ART)/fonts
# ... more folders defined here...
DIR_SRC_FONTS    = $(SRCROOT)/source-art/fonts
# ... more folders defined here...

# ... do some useful build stuff ...

# This is an example of my rule that takes the .png's built by my font script
# and compresses them to .pvrs (note: this isn't final, so YMMV). The thing to
# note here is that if this rule kicks off, the last thing that will happen is
# that I will touch my DIR_CONTENTS folder, which will kick off the copy to the
# device. I find having to touch the folder really annoying, I prefer the way xcopy 
# and similar copy methods recursively travel & update if required.
$(DIR_DEST_FONTS)/%.pvr : $(DIR_SRC_FONTS)/%.png
    @echo == Compress $(subst $(SRCROOT),src,$<) to $(subst $(DIR_DEST_ART),dest,$@) ===
    @mkdir -p $(dir $@)
    @xcrun -sdk iphoneos texturetool -e PVRTC -o $@ -f PVR $<
    @touch $(DIR_CONTENTS)

Then, in order to deal with the code signing problem, I edited my ResourceRules.plist to look like the below. The area to pay attention to is the key that starts with "art/.*"

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>rules</key>
<dict>
    <key>.*</key>
    <true/>
    <key>art/.*</key>
    <dict>
        <key>omit</key>
        <true/>
        <key>weight</key>
        <integer>0</integer>
    </dict>
    <key>Info.plist</key>
    <dict>
        <key>omit</key>
        <true/>
        <key>weight</key>
        <real>10</real>
    </dict>
    <key>ResourceRules.plist</key>
    <dict>
        <key>omit</key>
        <true/>
        <key>weight</key>
        <real>100</real>
    </dict>
</dict>
</dict>
</plist>
like image 38
Mark Avatar answered Oct 19 '22 23:10

Mark


For reasons I am yet to understand, sometimes the build process seems to get forgetful or simply unreliable.

Usual troubleshooting for this type of scenario is to clean all in Xcode, and at the same time delete the app from the phone.

like image 12
aussiegeek Avatar answered Oct 20 '22 01:10

aussiegeek


Why are the scripts not in the Xcode project? They can still be in the project while you use Textmate to edit them. Perhaps including them in the Xcode project will make it more likely that they get transferred to the device?

like image 1
ThomasW Avatar answered Oct 19 '22 23:10

ThomasW