Potion Factory Blog

Move to Applications Folder?

After reading John Gruber's "How Should Mac Apps Be Distributed?", I wanted to mention that The Hit List already does by itself what John suggests Apple consider doing with all apps. That is, if you launch The Hit List from a folder that is not an Applications folder, it asks if it should move itself to /Applications.

Why it does this, though, is not for the reason that most people expect.

Screenshot

Zip files are great for distributing Mac software. It's an established format understood by all kinds of software, both Mac and otherwise. Some browsers will even decompress them automatically leaving one single application icon in your Downloads folder. Having seen a few people get confused by disk images and being inspired by Coda, I thought I'd give it a shot.

The switch to Zip went great except for one thing: we started getting a wide variety of mysterious crash reports. They all had something to do with the app not being able to load essential resources such as nib files. A nib file contains data to create user interface elements such as windows, buttons, and so forth. Users aren't going to get very far with a Cocoa app if it can't load its nib files.

It took me some time to connect the dots, but once I did, it was pretty damn obvious. People were moving The Hit List into the Applications folder while it is still running. Mac users think nothing of moving a file while it's being used. Mac OS X does some fancy things to allow this for the majority of cases so I wasn't expecting Cocoa to get tripped up by something that now seems trivial. But alas, it was trying to load files from the old location and freaking out when it couldn't find them.

At first I looked for ways of making Cocoa become aware of the application being moved. After looking at the bug so much it seemed like the best way to fix it. Unable to find a clean work-around, I went for the next best thing and made the application ask if it should move itself on its own terms lessening the chances of the ground getting cut from under its feet. I'm happy to report that although this is not a direct solution, it works well. When I first saw Delicious Library 2 do the very same thing I thought that it was being cute, perhaps even a bit too cute. Now, however, I'd like to think that me and Wil Shipley have fought the same battle.

One last thing. To help other Mac developers who are distributing their applications in a Zip file, I'm releasing into the public domain the code that handles all this app moving business. You can find it here.

Comments

Mark

Perfect. Thanks a lot for this!

Bosse

Finally. Every app developer should do something like this and force Apple to react to the state of things.

Unless "better installation management" is on their list of planned "features" for 10.7, of course.

Billrey

Brilliant. Thanks for sharing

Warren Dodge

Very nice. Thanks!

Kent

Just wanted to say thanks.

Silus Grok

Wonderful move … it's visionary solutions like these that move the whole platform forward.

Jon Shea

We have the same problem when people move ExpanDrive while it’s running. I’m pretty sure that most of the issues we see are from (completely unnecessary) caching that NSBundle (annoyingly) does.

Andy Kim

That is also what I found out. NSBundle could also use kqueues to monitor the move and refresh the cache. It would be nice if Apple did something to fix this eventually.

Gordon Murrison

I've seen many new Mac users struggle with DMG files and no matter how hard I try to explain, they don't get it - ('I thought Macs were supposed to be simple' they say!). We are about to release our next Mac app and I think we're going to distribute it as a zip and include the 'copy to Applications' folder logic. Simple and effective. Thank you for sharing!

Andy Kim

Thinking back on my first experience with software in disk images, I was also one of those confused people. Seeing the simplicity of one file for one app made me forget about it soon, though, and over time, I just accepted it as the ritual. I think it makes more sense to go with Zip now because so many people are new to the Mac these days.

Good luck with your next app. It's my pleasure to be of help, even if in a small way.

RP Stoval

The wording of the dialog is a bit anthropomorphic, but the concept is interesting. Do you have any data on how many users just click the "don't" button out of fear, or if they click "move" and then can't find the app next time?

Andy Kim

No, we don't collect such data. Us small developers have to go with our gut feelings most of the time and hope to get it right. The data that we do have is that nobody has complained and that many people have complimented us about it.

If there are people who tell it to move and can't find it next time, that's okay with me. I want people with a minimum level of awareness using The Hit List. Am I asking for too much there? I mean, even if they don't read anything but the button itself, it's still labeled "Move to Applications Folder".

Ward Chanley

This is totally anecdotal, but I *like* the anthropomorphic wording of the dialog - it made me read the complete text *of* the dialog in this case, because it was novel. I suppose that would wear off seeing it repeatedly, though. Then again, if anthropomorphic dialogs are limited to JUST this particular use - here's the app telling me it wants to do something to ITSELF, not something I'm seeing in the usual use of the application itself, that could be a useful clue, in itself.

Nate Bird

I just downloaded your app so I could test the move to Application folder experience. I really liked it. Thanks for releasing the code to do this under public domain. I really hope this methodology catches on. It is much better than a DMG for a single application. Are you listening Mozilla?!?

Of course it would be more elegant for Apple to auto-detect on the first launch of the application (it already does for downloads, and widgets) and provide a system level solution so this behavior isn't adopted one app at a time.

Anyway, thanks for the great solution!

Simon

This is great. Thanks for releasing the source code too. Hopefully it can become widely used like Sparkle. which is now so widely used that every mac app is expected to auto-update itself.

Cajo

Well done!

Stefan Reitshamer

Thanks for sharing that code, but it didn't seem to work for me. The relaunched app crashed immediately. I'm wondering if OSX is getting confused because an app with the same bundle identifier launched while one was still running.

Anyway, I ended up writing a tiny "relauncher" program to avoid having 2 apps with the same bundle identifier running simultaneously. Seems to solve the problem. I just modified your code to launch "relauncher" instead of the copied app. Here's the whole program:

static double WAIT_SECONDS = 2.0;

int main(int argc, char **argv) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *destinationPath = [NSString stringWithUTF8String:argv[1]];
[NSThread sleepForTimeInterval:WAIT_SECONDS];
[[NSWorkspace sharedWorkspace] launchApplication:destinationPath];
[pool drain];
return 0;
}

Andy Kim

Check out the latest code in the GitHub project. I think it'll solve whatever problem you were having.

Michael Zajac

Feature request: if ~/Applications exists, offer to use that location.

Pierre Lebeaupin

"Mac OS X does some fancy things to allow this for the majority of cases so I wasn't expecting Cocoa to get tripped up by something that now seems trivial."
In fact I've found Cocoa to be rather bad in that aspect (of files, not just the app, moving while they are used), with its use of (urk) paths and the inevitable caching thereof; while some Cocoa classes go out of their way to support this (I think NSDocument does), Carbon APIs do tend to cope better, but Carbon is not where the future is going. Oh, well, in the future it'll be less of a problem with the fancy new NSURLs introduced in Snow Leopard ( http://arstechnica.com/apple/reviews/2009/08/mac-os-x-10-6.ars/7 ).

ManKnowsMac

Add another tickmark to that dialogue box that reads 'Add this to the dock', and what you have here is a Grand Unified Theory of Mac installation.

Dave Richards

An application should definitely point out if it isn't in Applications and why it should be there, and perhaps be able to move itself there.

Thing is, ALL users should know that applications should be moved to /Applications (or ~/Applications). Disk images may be a little confusing, but that's also something all users should understand: they're very powerful. The drag-to-/Applications" method might be a bit confusing, but it re-inforces the good practice that applications belong in /Applications.

That said, arguably, an application should be able to run from any directory, and give the user the option to permanently refuse to move it to the proper directory.

Andy Kim

The code here doesn't stop an application from running from any directory. It also does give the user the option to permanently suppress the dialog window. You'll see this in the screenshot.

Alex

What's the SVN link for this repos? I'd really like to follow all updates to it.

Andy Kim

Sorry, but there is no SVN repository for this. The GitHub project has a feed you can follow though.

Jim Getzen

I like the zip and offer-to-move approach, but I wonder if anybody has considered EULAs. Love 'em or hate 'em, dmg's can automatically show a EULA to which the user must agree before the app can be accessed.

I have read that EULAs have been held to be unenforceable unless the user specifically agrees to it. A EULA document that sits passively alongside an app in a folder or dmg doesn't cut it.

If we assume for a moment that a EULA is actually needed to legally protect the developer, it seems to me that the only other alternative is to present the EULA upon first run of the app, but then of course the horse is already heading out of the barn (the app is already running) and it would make an ugly first impression upon users.

Thoughts? Are EULAs necessary/wise? Andy, how do you handle EULAs?

Andy Kim

My personal opinion is that EULAs are annoying. I say this now because I haven't been sued but I think the chances are pretty low and I'd rather risk it to save the user that one extra click.

I totally understand if you want to protect yourself with a EULA though. In that case, you can either use a self-extracting DMG file or have the app show the EULA on first launch.

daiyami

Personally, I find the EULA just to download and self-extract the dmg extremely annoying. I don't see how that can be a better first impression--"I have to accept a license just to download this!?"--than a EULA on first launch.

peelman

I have to agree with this. The EULA should happen on first launch of the app, and that's it (see: iTunes; but ignore that you have to do it at almost every version).

WebKarnage

"see iTunes"
In the case of iTunes you have to agree to it before the download starts and after installation! the second is obvious (multiple users each having to agree) but the first? Not really necessary.

with best regards,
Karn.

peelman

I was using iTunes specifically as an example of the "show at startup then go away forever". The fact that Apple includes one in the installer as well wasn't pertinent to my point. Though I can't say if those are actually they same EULA, they may in fact be different, one governing the installation of the software and one governing the use? Stupid, yes, but its Apple...

Craig Hunter

I had to tangle with the issue of users moving my app while running as well. The only reliable way I found to do it was via AppleScript:

on bundlePathTest()
try
set pathToMe to (path to me)
on error
display dialog ("The Wx.app bundle has been moved or modified while running! Wx needs to quit now. In the future, please do not move or modify Wx while it's running.") buttons {"Quit"} default button "Quit"
quit
return
end try
end bundlePathTest

This seems to have completely eliminated the problem. I just call this periodically (when running the script won't cause any overhead, but before the app would self-destruct if it had been moved).

Andy Kim

Thanks for sharing this with everyone.

Ifmy

What was wrong with my last post?

I just want to know if you think integrate a menubar icon and a simple note.

I don't understand why you delete my message. Especially since I apologized for the quality of my English and the location of it. Incidentally, others unrelated to the topic ...

Tell me where to put my message for the next time.

Peter

Clever work. Thank you for the post.

Justin

This is definitely a nice piece of code. My thought is that ALL applications should use a zip file and this method to offer to move themselves (including my own apps, which I'll be updating very soon!). It's so much more convenient than doing it manually. I also wish more applications would use Sparkle (I can name a few that don't and it's extremely annoying, even to a developer like me who is used to doing complex things.)

That said, I would like one feature in this and that's the ability to authenticate and move to the /Applications folder instead of the ~/Applications folder. I like to run as a non-admin user but I want all my apps in /Applications. Being able to pull up the authentication panel to authorize a move to /Applications would be a nice feature.

Thanks for the awesome open-source goodness!

P.S. I unfortunately missed the chance to be in the THL iPhone beta program, but if you need another tester, I'm available! I currently own both Things and THL but am waiting to switch over to THL until the iPhone version comes out. I can't wait!

Andy Kim

It'll try to move it to ~/Applications if you have one of those. We thought this is a good default since most people don't have that folder and they would want apps there if they had one.

Normally, it will ask for authentication so that it can move to /Applications if you're a non-admin user.

Justin

Ah, that makes sense. I have the ~/Applications folder so I can put pre-release developmental builds there for testing, so because of that it doesn't ask for authentication and just offers to move it there.