Get Ready for June 2nd

There’s no doubt in my mind that Apple is going to overhaul the look of Mac OS X in the next version. As more and more apps bridge the gap between the desktop and mobile, the lack of consistent branding and design across platforms is becoming a problem.

I fully expect to see flatter user interfaces, squircle icons, a new Dock, and Helvetica Neue as the system font. We’ve already explored a flattened UI and new icons in xScope, but I was still left wondering what the app would look like with Helvetica Neue as the system font. There’s a lot of custom drawing in xScope and I was pretty sure there would be some areas where sizing and placement would be wrong because the metrics for Lucida Grande were assumed.

So I wrote this.

This category swizzles the NSFont class methods to return a different system font. The instance method to initialize a font from an archive (like a XIB) is also swizzled and the font is replaced if it’s Lucida Grande. The MAC_OS_X_VERSION_NT definition is both an inside joke and a way to make sure your code can adapt to any font.

Here’s what one of the new tools in xScope 4 looked like before using the category:

Before

And here it is with Helvetica Neue as the new system font:

After

As you can see, there are lots of small misalignments, both in my custom controls and the ones provided by Apple.

Changing the system font will be a bit like the transition to the Retina Display: lots of small tweaks to keep our apps looking perfect. Now would be a good time to start looking for areas where your app is going to need work.

Counting Beans with AppViz 3

In my last post about AppViz, I mentioned that I spent about six months creating an internal accounting tool called BeanCounter. Why the hell did I do that?

Because I don’t want to run my business on financial guesses based on iTunes Connect sales reports.

The Need For Financial Accuracy

For many app developers and iBook publishers, income from iTunes Connect is a significant part of the business’ financial statement. In many cases, the App Store is a developer’s only distribution channel, so it’s responsible for 100% of gross revenue.

When you have a financial statement, you want it to be exact. If your local tax collector comes calling and you show them guestimates, you’re in for a rude awakening. You’ve got a paper trail that’s fishy and that’s going to invite closer scrutiny. It’s the reason every piece of accounting software ever written has a reconciliation feature.

Publishers pay author royalties and many app developers split revenue with a designer. When it comes time to share the monthly Apple ACH deposit, financial guesses are also a problem. Not only will you be giving your partners the wrong amount of money, you’ll eventually be reporting it incorrectly on a 1099-MISC. Your estimated payments can be off by thousands of dollars:

Sales Reports Are Not Accurate

The root of the problem is that all services except AppViz 3 use fluctuating values like fiscal calendar ending dates, payment clearing dates, and currency exchange rates. If you do, you’re making financial guesses.

Don’t take my word for it, here’s what App Annie has to say:

Why do my sales reports in App Annie not exactly match my financial reports in iTunes Connect?
App Annie fetches the sales data from the iTunes Connect “Sales and Trends” section. There are a few reasons why the sales data doesn’t match Apple’s “Financial Reports” and the amount of money you receive from Apple.
Fiscal calendar. Apple uses fiscal months rather than calendar months for payouts. To see Apple’s fiscal calendar, go to “Payments and Financial Reports” and click the “Fiscal Calendar” link. For example, fiscal March 2011 starts on Feb. 27 and ends on Mar. 26.
Clearing of payments. What matters in the case of financial reports is what payments were made during a fiscal month, not how many downloads were made. Since most people use credit cards to buy apps, it can take up to 2-3 days for a payment to go through. Also, some payments never go through!

Currency conversions. Apple’s “Financial Reports” use Apple’s own currency rates, whereas App Annie always uses today’s exchange rate.

Remember that the last two points above have a certain degree of unpredictability, which makes the figures we get from Apple’s “Sales and Trends” slightly different from the figures in Apple’s “Financial Reports”.

That last item is particularly bad: currency fluctuations will give you wildly inaccurate accounting. For example, let’s say you sold €10,000 of product and used the rate on October 28th, 2013 (1.38) to convert that amount to $13,800. Then, Apple deposited $13,400 into your account on November 7th using that day’s 1.34 rate. Hope you didn’t pay your partners using that financial guestimate of $13,800!

The bottom line is this: you cannot rely on estimates in Sales Reports when doing financial reconciliation or partner payouts. Only Financial Reports can be used for this purpose.

Financial Calculations Are Hard

The problem is compounded when you have multiple products with different partners. Figuring out how to divvy up the money turns out to be a hard problem and it’s why everyone else has punted on doing it right. It’s also a competitive advantage for us, so I’m not going to go into any details about how we get the numbers to come out right.

I will, however, give you a peek into the first hurdle you’ll encounter: you can’t use floating point values for financial calculations. If you write code like this, you’ll be in for a world of hurt as errors accumulate:

double subtotal = balanceTotal + 
    (salesTotal + adjustments);
if (subtotal != 0.0) { // is 0.00000001 a zero value?
  rate = deposit / subtotal;
}

Cocoa has an awesome subclass of NSNumber called NSDecimalNumber. Classes like NSDecimalNumber are one of the reasons that “NeXTSTEP had a long history in the financial programming community.”

When using NSDecimalNumber your code will get more verbose than the snippet above. But more importantly, it will now be exact:

NSDecimalNumber *subtotal = [balanceTotal
    decimalNumberByAdding:[salesTotal 
    decimalNumberByAdding:adjustments]];
if ([subtotal compare:[NSDecimalNumber zero]]
    != NSOrderedSame) {
  rate = [deposit decimalNumberByDividingBy:subtotal];
}

It also forces you to think about problems like rounding: do you want to use NSRoundBankers when your code calls -decimalNumberByRoundingAccordingToBehavior:?

Conclusion

I hope you now see why I thought it was wise to spend a lot of time coming up with a system that ensures financial accuracy. I’m also thrilled that this system is now a part of AppViz 3, the app that’s been keeping track of our products on iTunes Connect since the App Store first opened in June 2008.

It also makes me happy that other developers are seeing the same benefits for accurate financial reconciliation. Helping other developers is what makes me tick.

Take a moment to think about how these issues affect your own business and then take a look at AppViz 3. I think your balance sheet, your partners and the tax man will be happy you did.

A Quick Look plug-in for Provisioning

As every iOS developer knows, when your provisioning gets messed up, your life becomes a living hell. I don’t even want to think about how many millions of man hours have been wasted getting broken projects working again.

The root of the problem is always the .mobileprovision files that are kept in your Library > MobileDevice > Provisioning Profiles folder. The file either references a certificate that has expired or a device that no longer exists. There can also be issues with the entitlements that are contained in the profile when Team and App IDs don’t match.

A large part of the problem is that this file is not directly readable in a text editor like all the other parts of our Xcode projects. The file is encoded in the Cryptographic Message Syntax (CMS) described in RFC 3852.

After doing a bit of research, I found that decoding the payload of this file format is very simple thanks to some helpful functions in Apple’s Security framework. And once decoded, these .mobileprovision files contain nothing more than Property List (.plist) with a lot of useful debugging information.

I had previously been using a Quick Look plug-in from MacMation, but that site’s gone offline and the plug-in no longer worked in Mavericks. I had originally thought the problems on Mavericks were due to the new code signing requirements, but the root of the issue was that the content type UTI changed from com.apple.iphone.mobileprovision to just com.apple.mobileprovision so Quick Look ignored the old plug-in.

Eventually, I decided to write my own Quick Look plug-in and add a bunch of new stuff that I had been wanting to display:

  • Developer certificates: Making it easier to verify that your keychain items match what’s in the profile.
  • Provisioning Profile UUID: When someone on the project team checks in a new Provisioning Profile in the Build Settings, the only information you have is that UUID of that new file. Showing the UUID lets you find the right match.
  • Entitlements: Checking the Push Notification environment, ubiquity container identifiers, and keychain access groups is essential for any app that uses Apple’s services.
  • Links: Whenever the provisioning is broken you spend a lot of time in various sections of the Dev Center. Why not make it easy to get there?

The results of a few days work can be found on GitHub. If you’re lazy like I am, just download the .qlgenerator file and pop it in your Library > QuickLook folder. To get Quick Look to recognize the new plug-in you’ll need to either logout or poke Quick Look from the command line:

$ qlmanage -r

While you’re at the command line, do this to allow text to be copied from any Quick Look plug-in:

$ defaults write com.apple.finder QLEnableTextSelection -bool TRUE
$ killall Finder

(Macworld has more info about this nice hidden setting. Being able to copy text from a PDF preview is pretty damn handy!)

The next time you’re stuck in the Fifth Circle of Provisioning Hell, this simple plug-in may just bring you back to life. Viva!

App Updates for iOS 7

Like many of my fellow developers, I am in the middle of an update of an app for iOS 7. As you’d expect, it’s a lot more work than previous versions of iOS. But results are stunning: both David Lanham and I have commented that our shipping version was “feeling old and clunky.”

While cranking along on the update, a couple of thoughts occurred to me: how many other developers were doing the same thing and were they going to commit fully to iOS 7? The depth and breadth of the changes in iOS 7 makes it difficult to support older versions of the OS.

So I just asked. I also included a simple question that any developer who was actively working on an update would be able to answer as a sort of CAPTCHA.

After a little over 24 hours, I had my answers:

An overwhelming number of developers are updating apps for iOS 7. Of 575 valid responses, 545 developers indicated that they were working on an update for iOS 7. That’s an adoption rate of 95%!

Of those developers who were working on an update, I then calculated how many were going to require iOS 7 (and drop support for iOS 6):

Just over half of developers (284 of 545) were leaving the past behind. Initially I was surprised that this number was so high, but then I remembered how much time and effort I was putting into my own work :-)

If you’re a consumer of apps, this is great news: it’s likely that your favorite apps will be ready for action come this fall. If you’re someone who has a device that’s a couple of years old, now’s the time to start thinking about upgrading. Many apps will require a device capable of running iOS 7.

After I posted the survey, I heard from several game developers who complained that they didn’t know the answer to the trick question: UIView -tintColor is only used in traditional interfaces. Most of the difficulty in adapting apps is changing navigational and content elements to match the new style. Games don’t have this problem: they’re basically all content. Considering these facts, my guess is that games will have much broader support for older versions of iOS.

If you’d like the raw data and my analysis using Numbers, here you go: iOS_7_Updates.numbers

Sandboxing

The recent release of xScope 3.0 is our first product to use the new application sandbox that will soon become a requirement for submission to the Mac App Store. I’d like to share some experiences and advice on how to use it in your own products.

First off, Ivan Krstić and the rest of the team at Apple have done a great job in making the whole process easy to implement. Adding entitlements and signing your code will be the least of your worries as you transition to the new sandbox.

Of course there are some applications that have a harder time than others: primarily if those apps require access to all or part of the filesystem (think about syncing data with Transmit, for example.) Apps that make use of AppleScript for inter-app communication will also have a difficult time: this includes our Take Five app. Apple is actively listening to developers who are encountering these types of issues, so if you haven’t filed a Radar yet, quit bitching.

Speaking of Radar, we encountered a fairly nasty problem after launching xScope. Many of our customers are designers and developers who love SSDs. It’s common to use a symlink in your Home folder to put big datasets like Pictures, Music and Movies on a separate hard drive. When you do this, folder access in the application sandbox container breaks. A small number of users who use symlinks are also getting crashes after launching the app that was downloaded from the Mac App Store:

xpchelper reply message validation: sandbox creation failed: 1002
Container object initialization failed: The file couldn’t be opened.

We also encountered a problem when using Sparkle to update an app running in a sandbox: an app can’t update its own binary. Changing Sparkle so that it uses an XPC service is a major architectural change, so we decided to remove the sandbox for the version we distribute on the website.

Besides being the path of least resistance, it also gives us a version of xScope that doesn’t run into the sandbox bugs reported above. I highly recommend that you give yourself this option for any customers that experience sandbox related problems.

All things considered, adding an application sandbox has been a fairly smooth transition. But it’s also clear that we’ve only just begun putting the genie back in the bottle.

Updated January 27th, 2012: The bug reported above is a duplicate of Radar 9865143.