The Iconfactory

Chameleon

Support Chameleon!

If you'd like to help support the development of this project, use the Donate button to send money to the Iconfactory PayPal account. Thanks!

What is Chameleon?

If you're an iOS developer, you're already familiar with UIKit, the framework used to create apps for the iPhone, iPod and iPad. Chameleon is a drop in replacement for UIKit that runs on Mac OS X. In many cases, your iOS code doesn't need to change at all in order to run on a Mac.

This new framework is a clean room implementation of the work done by Apple for iOS. The only thing Chameleon has in common with UIKit are the public class and method names. The code is based on Apple's documentation and does not use any private APIs or other techniques disallowed by the Mac App Store.

If you've developed for both the iPhone and iPad, you're familiar with the notion of a user interface idiom. At its most basic level, Chameleon adds a new idiom for you to use:

		if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
			// iPhone
		}
		else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
			// iPad
		}
		else {
			// Mac
		}
		

Using this convention, your source code can compile for the Mac and iOS without any changes required.

Since Chameleon relies heavily on Core Animation, a proprietary technology owned by Apple, it can not be used on other platforms such as Android or Windows. It only allows iOS apps to be ported to the Mac.

What is the status of this project?

Chameleon is a work in progress. The framework currently implements about 60% of UIKit after nine months of work.

To see what is possible with this framework, we suggest that you download Twitterrific from the Mac App Store. This product was created with Chameleon.

There are, of course, limitations to what the framework is capable of:

The current source code for Chameleon is available on Github.

Who are we and why did we build this?

The Iconfactory has a long history of releasing products for both the Mac and iPhone. Two of its senior developers are behind Chameleon:

The motivation for creating this framework came from our award-winning Twitterrific product. We had a huge amount of source code that worked great on iOS and were faced with porting much of it for a new Mac version.

Prior to the creation of Chameleon, we were looking at only being able to re-use about 25-30% of our code from iOS in the Mac version (mainly in data models.) By porting UIKit instead of the individual view and controller classes, we were able to re-use 90% of our iOS code.

The biggest advantage, however, is that we now have a source code base where we can add features and do simultaneous releases for both the iOS and Mac App Stores.

We are also in the process of using Chameleon in our other products. The initial port of Pickin' Time from iOS to the Mac took just a few days.

Won't Apple do something similar in Lion?

Apple already has a version of UIKit that runs on the Mac: every time you launch the iOS Simulator, you're using that framework.

As an iPhone developer, you're certainly aware of the limitations of UIKit on a desktop: multiple touch events are awkward and scrolling is non-intuitive. You'll also notice that things you copy to the simulator's pasteboard don't appear on the Mac's clipboard.

This illustrates just a few of the difficulties of bringing UIKit to the Mac. There are also problems going the other way: a Mac user will expect context menus, roll over effects and other user interface events that can't be produced in a multi-touch environment. Window toolbars and the main menu bar must also be incorporated.

The talented engineers at Apple are certainly capable of overcoming these hurdles, but it's clear that their focus these days is on the future. And the next 30 years belong to iOS, not Mac OS X.

Of course, Apple executives may change their priorities when they see how many developers are interested in a tool like Chameleon. Many people have speculated that the popularity of the Jailbreak SDK accelerated the release of the original iPhone SDK. It would be great if history repeated itself.

Finally, we have based this project on information that Apple makes available publicly and don't feel that it infringes on their intellectual property. We also value our relationship with Apple and will shut down this project if they feel differently.

Don't cross-platform toolkits suck?

Yes, they do. Anyone who's used an app that provides a "least common denominator" approach to UI knows how deep this pain goes.

At the Iconfactory, we strive for excellence in UI design, both visually and functionally. Many of our products have won awards for this attention to detail (including one of the first Apple Design Awards for an iPhone app.) We aren't going to build a UI toolkit that sucks.

Our approach with Chameleon was to use native AppKit constructs in the context of UIKit. The glue that holds these two frameworks together is Core Animation.

How does it work?

One of the areas where many cross platform toolkits fail is with the simple task of editing text. If you're a Mac user, you're used to features like Option-right arrow to move to the end of a word, Control-Option-D to bring up a dictionary pop-up, and Control-E to move to the end of the text. You'll also rely on the context menu that appears when you right click on some text.

So how does Chameleon provide this native Mac feel with code written for iOS? To answer that question, let's take a quick trip through a typical view hierarchy for a text editing control:

NSWindow and NSView: An app built with Chameleon uses standard AppKit classes for windows and content views. This "outer layer" provides things like native window management, menus, and toolbars. The code to manage these views is something you'll have to add to your existing iOS source. It's usually simple code that merely passes information and events to your existing controllers.

UIKitView: This NSView is the key to getting UIKit code into your Mac app. It acts as the root of the UIKit view hierarchy by providing UIWindow and UIScreen properties. Typically, you'll subclass this view to setup a root view controller by adding its view as a subview to the UIWindow instance (the same thing that most iOS application delegates do.) This is the point where you switch from using AppKit to UIKit.

Since each UIKitView provides a unique instance of a UIScreen, there is a natural mapping of application functionality to the Mac's multiple window environment. For example, Twitterrific on iOS only has one UIScreen to display a view controller that manages table view cells. On the Mac, each window has an instance of UIKitView and UIScreen: allowing multiple root view controllers with subordinate views.

UITextView and UITextField: As a part of your UIKit view hierarchy, you'll have these views to collect text input from a user. Obviously, putting up an on-screen keyboard would be a terrible user experience on the Mac, so this is the point where the framework transitions from UIKit back to AppKit.

UICustomNSTextView: Internally, a customized version of NSTextVIew is used to implement both of the UIKit text views. Since NSTextView provides all the standard features on the Mac, the user experience is identical to AppKit. This is an implementation detail: as a developer you don't need to know how the text fields are implemented. All that matters is your existing UIKit code works as the user expects without any changes.

Grafting NSViews onto UIKit views occurs throughout Chameleon: UIActionSheets and UIMenuControllers are implemented with NSMenus, while UIAlerts use NSAlert for platform consistency. It also works the other way as well: rollover events from AppKit event queue are passed to UIViews so Mac-specific interface feedback can be created.

Will I need to change my code?

In theory, no. But in practice, there are things you'll need to do to make your iOS app feel at home on the Mac. An iOS app doesn't have multiple windows, menubars and many other UI components that a Mac user will expect. If you don't make these changes, chances are that Apple won't accept your app into the Mac App Store.

Luckily, these changes can be made without affecting your base iOS code. Craig recently presented a talk at the Voices That Matter: iPhone Developers Conference in Seattle that explains why Chameleon was created and how it was used to bring Twitterrific to the Mac. The MultiApple example code on github is also shown and discussed:

This 40 minute presentation (slides) outlines the changes required to bring your iOS app to the Mac platform. Please excuse the sound quality: we're software developers, not audio engineers!

VTM conference

We'd like to thank Barbara Gavin and Chuck Toporek for inviting us to speak and record the presentation. Thanks also go to Andrew Carter for producing the video and Brent Simmons for helping with the arrangements.

If you're an iPhone developer, we highly recommend this conference series: a great combination of speakers, information and community.

Where do we go from here?

The Chameleon project is open source and freely available via a BSD-style license. We want the framework, documentation and sample code to be the highest quality possible. We want you to be able to bring your iOS projects to the Mac quickly and affordably.

Unfortunately, the code that is currently in Github is very poorly documented: we know what works and what doesn't, but it will be much harder for you to figure that out. Our goal for the past nine months has been to get Twitterrific released, not to make Chameleon suitable for public consumption.

We've also come up with a set of best practices for getting UIKit to work well in the realm of AppKit. A "porting guide" is sorely needed so developers can get their products onto the Mac App Store with minimum amount of effort. The How does it work? section above isn't enough to get you up and running.

Your financial contribution to this project will help us accomplish these goals more quickly. It will also allow us to spend more time working with the iOS and Mac developer communities to improve Chameleon.

One more thing…

A picture is worth a thousand more words. Here are two videos that show Chameleon in action:

This is an early prototype showing the same code working in the iOS Simulator and an AppKit window.

We have a lot of iOS source code that we have used to test Chameleon. This video shows Ramp Champ running in a normal Mac OS X window (it's not the Simulator.) The window is larger than the 320x480 screen used by the app so you can see how Chameleon (and UIKit) manage Core Animation layers.