productbuild and data files

Okay, so I’ve finally finished my beta testing and I’m ready to submit this thing to the app store, but I’ve hit a snag with productbuild and some data files I’m using.

The data files in question are basically just objects that I’ve serialised to disk (from a custom editor that I created . . . it’s an in-house utility, not intended to be distributed). I have to copy the data files to the app bundle after Unity builds the game, but I do that before any signing. I did all of the code signing, including libmono.0.dylib and so forth, got the entitlements and the sandboxing working perfectly, and did the chmod to make all of the permissions right. The app works perfectly at this point. I created the installer package, and as a test, ran the installer. As a side note, the data files never need to be modified once the app is deployed.

The app doesn’t load ANY of the data files after it’s installed. I noticed that the permissions are different on the data folders, but they seem to be the same as the permissions on all of the other apps in my Applications folder. Just as a test, I took the same installer and installed on my MBP, with the same results. If I copy the data folders from my source tree, to the post-install data folder, it starts working correctly. It only starts working correctly if I copy the folders and the files, and not just the data files.

One other thing I noticed is that if I click Get Info on the data folders from the installed app bundle, it doesn’t display the number of files correctly. It displays the amount of disk space occupied correctly, but shows the number of items to be zero. It shows correctly in the original exported app bundle and in the source tree.

I’m storing the data files in the Resources folder of the application bundle. It doesn’t seem like this should make a difference, but you never know. So I decided to experiment, and moved them to the Data folder instead. Also tried putting them in thier own folders under Contents. Either one of these configurations results in not working after signing. I’m starting to think it may have something to do with the code signing process, but I don’t have any idea where to start troubleshooting that.

What’s going on here? Am I skipping a step somewhere? Is there a different way I should be storing objects on disk? Am I doing this entirely the wrong way?

I’m starting to run out of hair, and I didn’t really have much to begin with.

Wow. If no one knows, then I don’t feel so bad about not being able to figure it out.

Some more information: I believe it may be the sandboxing, but I’m not entirely sure how it’s affecting it. All of the files are in place before I do the signing. The app stops working as soon as I do the code signing steps, so it’s not productbuild that’s doing it. I’ve even tried putting in an error dialogue box in the code to pop up with what the exception is, but I can’t even get it to do that. It’s like it silently fails. I naturally don’t have the Unity editor log at this point, but even my AppLog class won’t work (presumably also because of the sandboxing). I should probably note that I’m using BinaryFormatter.Serialize() and Deserialize() to do the saving and loading. Is there possibly an entitlement that I’m forgetting in my entitlements file? Just in case someone knows off the top of their head, here’s what I have:

<?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>com.apple.security.app-sandbox</key> <true/>
    <key>com.apple.security.device.usb</key> <true/>
</dict>
</plist>

I also tried doing the steps in a different order, e.g., doing the signing first and then copy in the data files. No change. It works just before signing the app bundle, and then doesn’t work right after. That’s what leads me to believe that it’s the code signing step. (After reading Apple’s documentation on code signing, this wouldn’t have made it anyway. The resource files are included in the app seal.)

Anyone have any ideas as to what’s going on? I’ll keep plugging away at it and post whatever I find here. Hopefully if I figure it out it will help someone else.

So I did some tinkering around, and I’ve discovered that not only is it not loading my data files, but it’s failing to run anything other than OnGUI(). Not even Start(). I figured this out by adding a pop-up dialogue to OnGUI() inside a conditional block, and set the conditional variable to true from Start(). I know OnGUI() is working because the mechanics of my interface work fine.

I thought perhaps that there was some entitlement that I was missing, but going through the documentation, I couldn’t really see one that was appropriate, so I tried the shotgun approach and added all of them. As a side-effect, I found that adding the com.apple.security.inherit key actually causes Unity to crash after signing. No bearing on this, but good to know. Unity would probably never need this anyway. The whole exercise didn’t work. Still no data files, nothing working outside of OnGUI(), even with all entitlements added.

I also ran across an option for codesign (which seems to be where the problem really is) --detatched, which creates a detached signature instead of embedding it in the code. However, I can’t seem to find any useful documentation on how to use it in conjunction with the App Store. Does it need to have a specific file name? Where does it need to go?

I really don’t get it. I’m not doing anything out of the ordinary (at least, not that I know of). Still won’t turn away any help if anyone knows. Might even give you a cookie. Of the HTML variety.

A kind soul over on the Apple forums said he thought it might be an incompatibility with sandboxing in my code. I assume that he meant that I might be making some function call or another that was getting blocked by the sandbox, and I would guess that it might cause the execution to halt.

Does anyone have any idea what sorts of function calls might cause this? I’m using Serialize() and Deserialize() to do the saving and loading. They’re methods of the BinaryFormatter class from .Net. It’s always made saving and loading super-easy, but if it’s going to lead to problems like this, then maybe it’s time I came up with my own save/load library.

Okay, so I’ve finally fixed this problem. Here’s what I did. Instead of loading the assets using a FileStream, I created custom assets using AssetDatabase.CreateAsset(). I used this to create an asset that’s nothing more than just a byte array. Then I used Deserialize() on a MemoryStream created from that byte array to convert it at runtime to the objects that I need. This got rid of the sandboxing compatibility issues.

I tried creating custom assets of the objects themselves, but it would just create an empty data structure and not load anything at runtime. Not sure why, and I really didn’t have time to investigate.

Moral of the story is that FileStreams aren’t compatible with the OSX sandbox. I guess that’s what I get for trying to use .Net on Unix. :stuck_out_tongue:

Hope this helps someone else!