UIApplication’s buggy openUrl and Budgee’s CSV Export
UPDATE: This bug is fixed with the iPhone OS 3.0 release. It doesn't sounds like Apple plans to ever update the 2.x OS with a patch for this, so check out the suggestions in the comments if you plan to continue 2.x support...some very good stuff there.
To the Budgee Users
First off, to anyone still having CSV export issues with Budgee - I apologize. The bottom line is that there is a bug in the OS itself that is preventing it from working (more detail below if you're interested). After getting a couple of new bug reports since the last update, I've been able to create an example of the problem and have sent it to Apple - but the reality is that the next OS update will be the earliest it will be fixed. I'm looking into alternatives to the current export method at this time, but do not have a solution at this point.
To Developers Thinking of Using mailto: or Currently Seeing Bugs with mailto:
Since the first version of Budgee, I've been using a simple CSV export method that passes the encoded data to the iPhone/iPod Touch's Mail application. It's worked great - no issues at all - until about two months ago. I don't remember which OS update started causing problems...it seems like it was one of the 2.1 releases. The export code is really simple - it goes like this:
- Build NSMutableString with data to export
- Url encode said string so it is safe to use in an url (i.e. convert a space to %20 etc)
- Tack on a mailto: with a subject & body parameter passing in the url encoded data
- Call the shared UIApplication's openUrl method
Pretty basic stuff. Well, as the OS has evolved, the openUrl method has gradually been getting more and more screwed up. There is no feedback as to what went wrong when you call it - it simply returns "NO" randomly now...which means it did not pass the url to the Mail application...which means my customers can't get the CSV data out of the iPhone app.
My first thought was that I didn't encode things properly. Sure enough, there were "reserved" characters getting through the encoding process. I should have done more extensive testing, but from reading the docs (and the method name), one would think using NSString's stringByAddingPercentEscapesUsingEncoding would kinda do what it says. But that wasn't the case...it escapes some things, but not all things.
So the next approach was something I found on the Apple devforums. The suggestion there was to use CFURLCreateStringByAddingPercentEscapes to do the escaping. It certainly looked a little nastier than the NSString method, but whatever works right? Well, the most recent Budgee update used this new method of encoding. On my development device, this new fix did indeed make things better and export started working again. After releasing the update on the App Store, I had several reports of users seeing CSV work again as well - so all was good right? Wrong.
This weekend, I had more reports of CSV breaking. After testing for about 4 hours with all kinds of different data, I saw that openUrl seems to fail arbitrarily. Budgee is a budgeting application where you enter categories and transactions and it tells you how much money you have remaining in your budget. Well, when I added a new category, just one, the export would sometimes work. When I took away that category, the export would sometimes fail. The thing is, the data is more or less the same each time...the is a new record for the new category and the message has a new timestamp, but other than that, nothing changed. But openUrl refused to actually open Mail about 1/2 the time I tried the export. After more testing, it seems that even the timestamp can change the url enough to cause openUrl to fail - so it's not just the category data that is causing the problem.
At this point, I have verifed the URL I'm passing to openUrl is correct and encoded properly. In fact, I went overboard and encoded everything other than basic ASCII letters - that should be overkill, but I saw reports of openUrl failing when periods were in the url (which should be legal)...so I opted to encode the heck out of the thing. I passed the url to openUrl and guess what? No dice - still refuses to open. It does this 100% of the time as long as I hardcode this url into my test application. So, the good news is that I've opened a bug with Apple (bug #6635825 if that is useful to you) and attached sample code that should reproduce this error consistently. Before I opened this bug, there were posts by an Apple employee (also on the devforum) stating that they know there are issues with mailto: links, but they essentially haven't been able to track down what is happening to cause the issue. Maybe the sample code I posted to them will help. The bad news is that my customers still can't export data sometimes and I have no workaround other than to try adding a new category, transaction, etc. and then trying the export again. That is totally unacceptable for me - but the only other workaround I can do is to totally re-write the export to use a method other than a mailto: link...but of course, that's not a trivial thing to do quickly.
The bottom line for developers is that if you're thinking about using a mailto: link to export data, be ready to hit this issue and have to wait on Apple. It still isn't clear what triggers it. It may be the complexity of the data I'm exporting, but it's just not clear. There are quite a few reports around the different forums where people are having similar issues - so I know Budgee isn't the only app exhibiting this problem. It looks like the only reliable way to get this data off the phone is to send it yourself via web service calls, export to google docs, built-in web server, etc...all of which are considerably more involved (for the dev and/or end user) than the mailto: link.
openURL: is pretty badly broken! I found that it doesn't return NO when you pass it an unsupported URL scheme. This means that you have no way of knowing whether a call to, say, TwitterFon, worked or not. This also used to work in the 2.0 days. Not a show-stopper, but does show that Apple has a lot of work to do in this area.
I've run into this same problem. Thanks for reporting the bug and posting this message. It helped me to realize I wasn't going insane. I've tried every work around I could think of and still couldn't get it to work 100% of the time. I will be checking back often to see if you heard back from Apple on this issue since I know so many of the users want this feature.
Thanks for the post ... I am having the exact same problem. Really small changes to the mailto: URL causing a failure for no reason. Have tried encoding differently, and padding to word boundaries etc, with no luck.
Rob
I found the same thing and discovered if I built using the 2.1 or 2.0 SDKs the problem went away. Makes sense as previous versions of my app did not have this problem, and this latest was the first time I built with the 2.2 SDK. I also filed a bug to Apple, so let's hope it gets addressed with 3.0 for sure!
I fixed this issue by adding commas to the email address until the system accepts the URL. I chose commas specifically because the mail app will treat the mailto: target as a list of email addresses separated by commas, and will discard any trailing ones automatically.
Adam - Thanks for posting about this. It's been driving me nuts for some time, with me thinking I was doing something stupid.
Nick - Have implemented your comma padding work-around. Great idea, works a treat. I can now stop pulling out my hair!