Behind The App: Flare 2

Here’s what I’ve been pouring my heart and soul into since the day WWDC 2014 ended: Flare 2.

We started working on this project well before WWDC. A significant redesign that put content first had been completed. A lot of code had been written and the app was working well.

But…

WWDC was a cornucopia for developers. There were suddenly so many new things we could do on both iOS and OS X. It was overwhelming and exciting at the same time.

And…

Three things stood out for us: the new look for Yosemite, iOS 8 extensions, and CloudKit. We had always wanted to do something with Flare that needed these things. It really felt like we won the Apple developer lottery.

We could now create great photographic effects on our Macs and apply them to the photos taken with the camera that’s in our pocket. Perfect. Simple.

But even with a simple and perfect goal, execution is never easy. I think there’s always a lot to learn by looking back at the struggles you encounter during product development, so here are some things Anthony, Talos, Travis, Wolfgang, Sean and I encountered during our journey.

Yosemite’s User Interface

The Flattening

As I noted above, we’re acutely aware of the direction that OS X and iOS user interfaces are heading. We’ve been striving to put content first for a couple of years now. This effort started with Twitterrific 5.

Note the date of the post in that last link: December 2012 was six months prior to iOS 7 and “flat user interfaces” being announced at WWDC 2013. While everyone else was making interfaces like the one on the left, we created the one on the right:

Twitterrific

Click on the image to see a bigger version

We saw the same opportunity to simplify Flare. It was possible to create an app that put the customer’s content frontmost while retaining advanced controls to adjust the photo when needed.

This is where we were at on May 28th of this year. Anthony’s mockup was already very flat and content-centric:

Twitterrific

Of course, after WWDC we realize we could do even more to simplify the user interface. Here’s how the final product turned out:

Twitterrific

(If you’re at all interested in interface design, I suggest downloading a copy of Flare just to try it out. There are a lot of animations and other effects that can’t be expressed in static screenshots.)

As a company, designing and implementing a user interface for Yosemite is a very important exercise. We have clients who want us to help move their apps in a similar direction, and the only way to become an expert with this stuff is by making it.

Here are a few observations from the “Yosemitification” of Flare. (And yes, we used “Yosemitify” frequently in our internal discussions!)

Tint & Themes

The influence of iOS 8 goes beyond the flatness of the design. We wanted to use control tint color to give the user feedback on the state of the application. The tint color also gave us a visual anchor between the two platforms were Flare runs: the purple tint links the user interfaces on iOS and OS X.

Unfortunately, OS X only supports the notion of two tints: blue or graphite. In the end, we wrote our own control cell classes that used a custom tint color. I’m hoping to have the time to open source this code some day: many products besides ours are embracing multiple platforms and these controls will be very helpful to other developers.

Another subtle touch in the Flare user interface: it supports both the light and dark themes in Yosemite. The theme support in Yosemite allows you to change the entire control hierarchy’s appearance at any time. We use this capability as another way to put the customer’s content first: sometimes their photos look best on a black background, other times a white background.

Vibrancy

There was a very common theme throughout Flare’s development. We would add vibrancy to the interface, and then a couple of weeks later, we’d remove it.

Personally, I think it’s a lovely and subtle effect. But it’s just too easy to use it in a way that interferes with usability. Text and other lightly stroked information (such as icons) can disappear on the subtly colored gradients that you have little control over.

The last vibrant holdout in Flare was the header at the top of the list of effects. In fact, we removed it the day before the app was submitted for review! The thumbnail images looked really cool sliding up underneath a transparent header, but since we don’t have control of the content generated by the thumbnails, it was much too easy to have colors that rendered the icons and text unreadable.

(In the screenshot above, you will notice a slight color shift between the header and the thumbnail content that’s not in the final product: the screenshot was created before we removed the visual effects view.)

Vibrancy does still have a place in our app. It works great in the “guided tour” for displaying help over the content and controls of the interface. This guided tour is also a piece of UI that we’re all very proud of: we wish we could sit down with every customer and say “Hey, look at this!”, but this tour is a really great alternative.

iOS 8 Extensions

Tools

Let’s just say things were a little rough development-wise at the beginning. Extensions are an awesome addition to both OS X and iOS, but as with anything new, they were also fragile. At one point, the only debugging tool was my old friend printf(). Not having Instruments available to track down memory leaks makes you appreciate the awesome power of that tool.

As new versions of Xcode came out during the iOS 8 beta, the situation improved steadily. This is why they call it the “bleeding edge.” I just want to know why I always forget this when starting out with something new and shiny :-)

I’ll have some more to say about these tools in the very near future: I’m working on a field guide for iOS extension development.

Memory

As someone who developed an app on the original iPhone using iOS 2.0, I didn’t think there would ever again be so many problems with managing memory. I was wrong.

Creating the Photos Extensions in Flare Effects was a huge challenge. First off, the most recent cameras have very high resolution. For example, the native size on my iPhone 6 is 2448 x 3264 pixels. That’s over 20 MB of source data you need to deal with.

These big images are being handled in an XPC process that runs at the same time as the Photos or Camera processes. You’re not the only one who’s dealing with a lot of pixels.

Compounding this is the fact that you usually need several of these big images around for compositing and other effects. Luckily, a lot of the magic in Flare (and iOS 8 in general) is done with Core Image, so a lot of the heavy memory requirements can be offloaded to the GPU via OpenGL ES. But even then, you have to be very careful: a post on Stack Overflow about managing textures across thread boundaries, literally saved our ass. I owe Max a beer.

Wolfgang did some amazing work to get our very complex filters running smoothly on iOS. Despite the APIs for Core Image being nearly identical between OS X and iOS, the data and parameters you feed the filters have very different requirements. Textures, scaling factors, extents and many other things had to be adjusted for the new platform!

The situation with memory was a constant struggle. In fact, it was even an issue after we had the app approved and ready for sale. We discovered a crashing bug that only happened on the iPhone 6 Plus because it needed a @3x preview image that weighed in at over 20 MB! Rejecting a binary and resubmitting for review the day before an Apple Event is not for the faint of heart.

CloudKit

As developers we often complained about the opaqueness of iCloud. Things would happen and you’d have no idea what was going on behind the scenes.

With CloudKit, that all changed. We’re now responsible for every little thing. Every response, every error, every piece of data. That’s a good thing, but the age-old fact remains: syncing is hard.

Luckily, my colleague Sean likes hard problems and built a syncing system that “just works”. Even then, we’re a little afraid we haven’t covered all the bases: just before submitting the app for review, we discovered an issue where expired tokens weren’t being handled correctly (because we’d switched from the development servers to the production servers.) To be honest here, our fingers are still crossed as we deploy this to millions of potential customers.

Still, the flexibility and breadth of this new API makes it all worthwhile. It makes it possible for us to get cool and free photo effects to folks on iOS even if they don’t use our Mac product. Doing something like that prior to iOS 8 and CloudKit would have been cost prohibitive from an infrastructure point-of-view.

Conclusion

So there you have it, a roundup of all the fun stuff that went into making Flare 2. We hope you enjoy it!

Device Log Douche

The new Devices window in Xcode 6 has been a constant source of grief for the past few months. Getting device logs was an exercise in frustration which usually resulted in me admitting defeat (and without my logs.)

Over the weekend, I found a 2.21 GB answer:

iOS_Device_Logs

I’ve been developing iOS apps since the beginning of time. I had over 7,000 crash logs in my ~/Library/Developer/Xcode/iOS Device Logs folder! Every time I opened the new Devices window Xcode would tell me it processing some very old crash logs: at one point I saw one from 2008 go by! All this useless work prevented me from getting to the most recent reports.

It appears that newer versions of Xcode store the crash reports in a Core Data SQLite database. Both the raw and symbolicated reports are kept in the iOS Device Logs folder:

$ sqlite3 "iOS Device Logs 6.0.1.db"
sqlite> select count(*) from zrawlogtext;
1840
sqlite> select count(*) from zlogtext;
1840

I first tried removing all the old .crash files. Xcode still insisted on processing, so it must be working on stuff already captured in the SQLite database. When I removed the most recent database, I was greeted with an Xcode hang after clicking on the “View Device Logs” button.

A spindump showed that Xcode’s DTDKCrashLogDatabase class was doing a -performBlockAndWait: on the main thread. I’m guessing that Xcode was trying to copy over databases from previous versions as some kind of migration process.

In the end, I removed everything in the iOS Device Logs folder and can now use the Devices window as it was intended.

Note for Apple folks: A Radar with the spindump is here: rdar://18489861.

In-App Browsers Considered Harmful

How many apps on your iPhone or iPad have a built-in browser?

Would it surprise you to know that every one of those apps could eavesdrop on your typing? Even when it’s in a secure login screen with a password field?

Here is a proof-of-concept (ZIP file) that shows how an app can do this. For those of you who don’t have Xcode installed, here’s a video that shows what’s going on:

A few things to note about what you’re seeing:

  • The information at the top of the screen is generated by the app, not the web page. This information could easily be uploaded to remote server.
  • This is not phishing: the site shown is the actual Twitter website. This technique can be applied to any site that has a input form. All the attacker needs to know can easily be obtained by viewing the public facing HTML on the site.
  • The app is stealing your username and password by watching what you type on the site. There’s nothing the site owner can do about this, since the web view has control over JavaScript that runs in the browser.
  • The site content is also modified: the text on the button label is normally “Sign in” and has been changed to “SUCK IT UP”. It seemed appropriate.
  • This technique works in iOS 7 and 8 (and probably earlier versions, but I didn’t have an easy way to test them.)

OMFG APPLE IS HACKING ME

No, this is not a WebKit bug.

The Shadow DOM does a great job of protecting static user content on a web page. It’s not possible to use JavaScript to view the contents of an input field on iOS since the current value attribute is actually being held in a platform-native control. The value of that control is uploaded when the user submits a <form>.

I don’t know for sure, but I suspect that the keyCode attribute of the KeyboardEvent in the JavaScript event handler is provided for backward compatibility. This API has been deprecated but there are still plenty of web pages out there that use it to handle keyboard input.

In fact, both the techniques shown in the sample app can be used for good as well as evil. Changing the content of a web page is a good thing when it’s done to make a page more readable or accessible. Handling keyboard events can also guide a user through a complex form or make viewing a slide show easier.

These are not inherently bad web technologies. The problem is that an iOS app has as much access to these technologies as the developer of the web page.

OAuth To The Rescue. Or Not.

Websites have been dealing with username and password attacks for as long as there have been <input> fields on their pages. One of the primary goals of OAuth was to keep a user’s login information away from an external website or app.

OAuth does this by exchanging cryptographically signed tokens between the site where the user has an account and the app or web service that wants to access that account. A key factor in making this secure is that the exchange of these secure tokens is done through a trusted channel: the user’s web browser. Twitter has required third-party developers to use OAuth since 2010.

As early as 2008, the developers of OAuth recommended the following:

We’re trying to ensure that users are only exposed to the safest way to disclose their location using OAuth. To do this, it’s critical that a fundamental principal of browser-based authentication is followed; that the contexts of the third party application and the web service authentication remain separate. To allow users to grant trust to an application, they must perform the OAuth action within their web browser, not within the applications themselves. Otherwise, there is no way to verify the identity and authenticity of any page which asks for their username and password. Users must not ever enter their username and password into a third party application when a browser-based authentication API like OAuth is available.

There is always a tradeoff between usability and security. Doing the OAuth token exchange with an in-app browser makes it easier for a user to login, but they’ll have no idea if their personal information was captured. That is why Twitterrific did its token exchange in Safari, even though it’s a more complex user interaction and a more difficult technical implementation. As a user, I know that there’s no way for my login to be compromised when the transaction involves Safari.

Unfortunately, Apple’s current App Review policy does not agree with this recommendation or with Twittterrific’s previous implementation. This is why our update for iOS 8 was delayed—it was the first time since the launch of the App Store that we haven’t had a new version on release day.

(Apple folks can learn more about this situation by reviewing Radar #18419943)

Recommendations for Apple

Apple has taken a strong and welcome stance on privacy. They’ve recently been implicated in some high profile attacks so they definitely have skin in this game. Hell, they even want to protect us from the US government watching what we do online!

There’s no denying that the behavior demonstrated above could be very harmful in the wrong hands. It’s also Apple’s job as the gatekeeper for iOS to keep malicious apps out of the App Store. But how?

I don’t think it’s feasible to catch misbehaving apps at review time. There are a huge number of apps that need to be reviewed every day, especially when new versions of iOS are released. Many of these apps use in-app browsers which would require extra time and effort to vet. Longer review times benefit no one: developers, Apple and our customers need timely updates.

It’s also very easy to an app to hide any nefarious activity. JavaScript has an eval() function that makes it easy for code to be obfuscated and very difficult to be checked at review time. Look at this page and see if you can guess how the uppercase text was created. Then view the HTML source and see how wrong you were.

Additionally, an app that wants to collect your information can easily implement a remote switch that disables the functionality while the app is in review. App reviewers won’t stand a chance.

Changing how WebKit and UIWebView behave isn’t practical either. To prevent this keylogging technique, Apple would need to release a new version of iOS for each version that included Safari and WebKit. Do you really think they’re going to do a point release of iOS 3?

And this brings me back to protecting users with OAuth. It’s designed to avoid these problems and works well to maintain privacy. Granted, it goes against section 10.6 of the App Store Review Guidelines, but in my opinion, this is a case where user security trumps usability. Apple should change their policy for apps that use OAuth.

Recommendations for Users

Another goal of this essay is to increase user awareness of the potential dangers of using an in-app browser. You should never enter any private information while you’re using an app that’s not Safari.

An in-app browser is a great tool for quickly viewing web content, especially for things like links in Twitterrific’s timeline. But if you should always open a link in Safari if you have any concern that your information might be collected. Safari is the only app on iOS that comes with Apple’s guarantee of security.

(For the record, we never collect any private information in any of the Iconfactory apps. And we never will.)

A documentary

For the past few months, I’ve been helping a couple of talented filmmakers with a new project. I’ve been making introductions, reminding busy people to find some time for an interview, and that kind of thing. Today, the result was made public and it’s better than I ever imagined.

I think this project that looks at our past is important for two reasons: our present and future.

It’s no secret that the art and business of software development has changed radically since that day in January 2007. Listening to my colleagues talk about what that moment meant to them is incredibly helpful for putting today’s situation in perspective. You don’t give a shit how big the next iPhone’s screen is going to be when your peers are talking about how these devices have changed their lives.

By funding this project, you’re also giving your future self a rare gift. I was a young developer when the Mac was announced in 1984, and let me assure you that many of the details of that time have been lost over the course of thirty years. You’re going to look back at this time in your career fondly and wish you remembered more about it.

Something like what Andy Hertzfeld has done at Folklore.org has been a godsend to those of us who were around in the early days of the Mac. But I don’t think that approach would work now: the Internet made the iPhone a world-wide phenomenon, not a project limited to the Texaco Towers. (Did you know that the first person to make money from selling apps was a developer in New Zealand?)

This is your chance to create a record of something that has changed so many lives. Please take a moment to look at what Jake and Jed have done and join me in contributing to this Kickstarter.

Confidence

We witnessed something amazing yesterday: a WWDC keynote that will be remembered for a long time. And not for the reason you might expect.

As developers, it’s easy to focus on the fantastic software that was announced: a UI refresh that’s getting a thumbs up from designers and developers alike, great new user-facing features in iOS and OS X, and literally thousands of new APIs that let developers do new and amazing things with their apps. We even got a new programming language!

**BLINK**

But that all pales in comparison to the undercurrent for all these changes: Apple has a newfound confidence in itself. It’s at the top of its game, and it knows it.

This is personified by the man who ran the show: Craig Federighi. It was only four years ago that we first saw him on stage at an Apple event. His shaking hand is still painful to watch, especially if you’ve felt that same fear while giving a presentation on stage. Yesterday, we saw a different man, one that owned the stage and the products being presented.

With this confidence, we’re starting to see some important cultural change in the company.

  • Legal agreements that lets developers talk about technologies without breaking confidentiality.
  • Opening up proprietary technologies like iCloud: providing more transparent access, without hiding things through opaque APIs.
  • Improvements to the App Store that give developers better ways to manage and sell their products.

This confidence manifests itself in many ways. When was the last time you heard an Apple executive tout the best product line he’s seen in 25 years?

In short, with confidence comes a new kind of openness. As developers, we’ve always struggled with a company that doesn’t want to give anything away. Yesterday, that started to change.