We’ve been making award-winning apps since the App Store opened. Now we’re doing it for clients.
Category: Design
A lot can happen in eight years.
The site above was launched on June 26th, 2007—a mere two days before the first iPhone went on sale.
As we all now know, that little device has had quite an effect on our industry, especially on this site, where I immediately started exploring its capabilities.
One of the first things I wrote about was making websites look better on the iPhone using one line of code. As time went on, it was pretty clear that more work was needed and we started working toward responsive designs. The first site to get this treatment was, of course, my beloved factory followed by its blog. I’ve learned a lot about HTML, CSS and JavaScript along the way.
So now it only makes sense that a site that got its start with the iPhone looks great on the iPhone. And in Yosemite. And on Retina displays. And maybe even Android.
Finally.
A new addition is content at the bottom of the page. Sometimes you’ll see information about products or services from my company. Other times you’ll see posts that are my “greatest hits”. I’ve gone to great lengths to keep this site clean: don’t expect to see any crap there.
I’m also set up to do link posts, so those should start showing up as I find interesting stuff. Of course, there’s a full text RSS feed if you’d like to read that way.
Enjoy!
Look at your wrist: notice something missing?
Yeah, it’s “Early 2015” and you still don’t have an Apple Watch. Damn!
Luckily, my colleague Troy Gaul has just released something that can tide you over while you work on your wrist apps: a developer tool called Bezel. Things get even better when you display Bezel’s window with the Mirror in xScope. You’ll have a development environment where you can get instant feedback about the physical aspects of your design.
It’s very likely that the display on the Apple Watch is 326 ppi and that’s conveniently the same as the iPhone’s Retina Display. That means you can get a pixel perfect layout of your wrist app on your iOS device. Here is a photo comparing a printout of Thibaut Sailly’s layout PDF with an image generated by Bezel:
You can even take it a step further and pretend that your app is running on your wrist:
Don’t be afraid to get creative with rubber bands or other types of fasteners to attach your phone to your arm. Note that xScope’s Mirror works fine in landscape orientation if you’re experimenting like this.
And if you’re wondering why xScope doesn’t send taps back to Bezel or the iOS Simulator, I only have two words to say about that: Application Sandbox.
As every Apple developer knows by now, Apple Watch is becoming a reality. If you do nothing else right now, watch the video at that link: it’s a great overview of WatchKit that will only take a half hour of your time.
David Smith put it best: there’s a lot more here than most of us expected. I spent yesterday exploring the APIs and have some thoughts and links to share below.
Software Design
The local and remote nature of WKInterfaceObject feels a lot like the days of a dumb terminal talking to a mainframe. Except this time, the terminal ain’t dumb, and the mainframe fits in your pocket.
But still, there’s RPC going on here, and a lot of the design patterns and limitations are due to that fact. Our IBOulets
and IBActions
are traveling around in thin air: let’s take a look at what that means.
No customization
WKInterfaceObject inherits from NSObject, but don’t let that fool you. There’s absolutely no customization here: you can’t subclass WKInterfaceWhatever.
If you don’t believe me, try to set a Custom Class for one of the objects in Interface Builder. While this is a limitation, it’s also a good thing for a new platform: it forces consistency in the user interface. None of us have even held an Apple Watch before, so constraints will help us to not shoot ourselves in the foot.
One thing that some of us are wondering: why aren’t these classes that can’t be instantiated just protocols? Time will tell, I’m sure.
No properties
In a similar vein, these WKInterfaceObject classes aren’t like other UI objects we’re used to dealing with. There are no @properties
, only setters. Why?
Querying a property would mean a round-trip over Bluetooth to get a control’s current state. It’s more efficient for your iPhone app to keep track of things instead of consuming power with a radio.
Object marshaling
When you set a property using an object, you may be fooled into thinking that object goes over the wire.
Look at UIFont in an attributed string, for example. If you try to instantiate one of the San Francisco fonts that you find in the SDK, you’ll be surprised that it returns nil
. Remember, you’re creating this instance on an iPhone (where the font doesn’t exist) to use on a watch (where it does exist.)
I’m guessing that things like font instances are marshaled over to the device. At this point, it’s important to remember that an object you create may not be the one used in the user interface.
Images
Images are a large part of what makes a great looking app these days. We’ve gotten pretty good at it. Understanding how they work in WatchKit is essential.
It’s best to make your images static resources in the bundle that gets delivered to the watch. It’s expensive to transfer these large assets over Bluetooth. The best experience for the user is to pay that price at the time the watch app is installed.
To get an idea of the extent of this philosophy, download the Lister sample code and look in the Watch App assets for the Glance UI. You’ll find 360 images: one for each degree of the circle’s movement. Your designer is going to love making these images. j/k LOL
Still, there are cases where you’ll need to send images to the watch dynamically. Think about avatars for a social networking service: no amount of memory can hold all the images you’d need for Twitter.
This confused me at first, so I asked someone who’d know. The solution is to use WKInterfaceDevice to add images by name. These can then be used in WKInterfaceImage using the -setImageNamed:
method. The image cache can hold up to 20 MB and is persistent across launches. Think of it as a way to dynamically extend the contents of the bundle you delivered during the install process.
Another approach is to create the image on the iPhone and transfer it directly to WKInterfaceImage using the -setImage:
method. This is reasonably fast in the simulator, but I’ll bet money there’s a significant lag on the actual device.
WKInterfaceGroup
My first impression of the user interfaces you could design in Interface Builder wasn’t entirely positive. I could create designs that were functional, but I couldn’t personalize the layout. That all changed when I figured out how WKInterfaceGroup worked.
The light went on when I saw that a WKInterfaceButton had a content setting for “Text” and “Group”. When you specify “Group”, you get a container where you can place other items. It was only a matter of time until I ended up with this:
The pretty part is the list of objects on the left, not my abuse on the right!
The topmost “Button” uses the group content mode, so it’s layout is defined with a container. That container includes three more items: another blue button with an “A”, a WKInterfaceTimer that counts down, and an image with the “check-all.png” graphic. The Group container uses a red background with another transparent image (the teal arc.)
The interesting thing here is that while you only get one IBAction
for the button, you can set up multiple IBOutlets
for the items in the container. As a test, I hooked up the button’s action to change the background color of the group, reset the timer, and swap one of the images.
In Interface Builder, the Size and Position settings in WKInterfaceObject’s Attribute inspector let you define where the items in the container are placed and how much space they should use. Since you don’t know if you’re going to be running on a 38mm or 42mm device, think in fractions. The example above uses 0.25 for the button and the timer, and 0.5 for the image.
Power Consumption
Bluetooth Low Energy must be really low power: the design of WKInterfaceObject means it’s going to be on a lot. Every interaction with the watch has the potential to move actions and data between your pocket and wrist using the radio.
But more importantly, this API design gives Apple a simple way to put a cap on power consumption. We saw this approach in the early days of the iPhone and that worked out pretty well, didn’t it?
One final thought about the API design: your code never runs on the watch.
Physical Design
In addition to new APIs, more information about the physical characteristics of the watch have been made available. We now know that the 42mm model has a 312×390 pixel display and that its 38mm counterpart uses 272×340 pixels.
Screen resolution
In addition to its size, the placement of the display on the face of the watch has been documented in the layout section of the Human Interface Guidelines. That has led some of us to estimate the screen resolution.
My calculations put the resolution somewhere above 300 ppi:
Since we’re not dealing with engineering drawings here, it’s impossible to be precise. For one thing, we don’t know where Apple is measuring 38 and 42 millimeters. Traditionally, it’s measured from the center of the lugs, but since the Apple Watch uses a different mechanism, it could be the size of the sapphire crystal.
John Gruber, who has a stellar record at this guessing game, thinks the display will be 326 ppi, just like on the iPhone 6.
But you’ve got bigger problems than pixel perfect design now anyway…
Screen size
The display layout drawings give us enough information to create a reasonable physical facsimile of the watch.
It’s small. Very small.
Much smaller than you think if you’ve been looking at it in the simulator.
You’ll want to download this PDF created by Thibaut Sailly and print it out at 100%. My first thoughts were that my finger covered more than half the screen and that I could fit eight of these displays on my iPhone 6!
After this “physical contact” with the Apple Watch, some of the controls that we see in the simulator feel ridiculously small. There’s no way you’re going to tap the back arrow in the nav controller with your finger: I’m guessing that control is there solely for developers who are using mice and trackpads to develop their apps.
Mockups
Once you have the PDF to give you an idea of the physical size, you can then start to see how your design works at that scale. Thibaut has already made the world’s ugliest watch and it’s doing important information design work. Here it is showing a simulated scroll view and exploring glance interactions.
You can even take these mockups a step further and strap a phone to your wrist. While it may look and feel a bit strange, there are definitely some interesting insights being discovered in that Dribbble post. The Mirror tool in xScope could be very handy for this kind of work: design in Photoshop, view on your wrist and learn.
These physical interactions with your designs are incredibly important at this point. Wondering why the scroll indicator only appears in the upper-right corner while you scroll your view? I was until I realized that’s where the digital crown is physically located.
Orientation
One thing that none of us are going to miss in WatchKit: you don’t have to worry about device orientation changes.
As my friend, and party pooper, John Siracusa points out, this is probably just a temporary situation. As a fashion accessory, Apple Watch could easily become a pendant watch.
Where to go from here
So there you have it: a day spent with another revolutionary set of APIs. If you’re just starting out, the links to the HIG and sample code above are great places to start learning.
If design interests you as much as code, you’ll also want to download the Apple Watch Design Resources (the link is at the bottom of that page.) You’ll find all the fonts and Photoshop documents you need to start pushing pixels. But as you saw above, make every effort to put those pixels into physical perspective.
As Apple has stated, this is only the initial phase of the API rollout: fully native apps will be possible later this year. Even though this is a first step, it’s a really good one.
All that’s left to do now is start making awesome apps.
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.)