Have you ever wanted to demo your apps on the big screen, just like Steve Jobs does in his famous keynote speeches? Up until recently, this wasn’t possible to do without jailbreaking your iPhone. Starting in iPhone OS 3.2 and iOS 4.0+, a new set of public APIs exposes the dock connector’s ability to interface with big screen TVs and PC monitors. You can either use the composite / component AV cable or the new VGA dongle accessories to connect to an external display.
The new UIScreen APIs
UIScreen is a new UIKit class that abstracts display interfaces (the one on the device, as well as external ones). You can enumerate the available screens, obtain display modes for each of them (UIScreenMode) and get automatically notified when they are connected or disconnected. An important thing to note is that in order to take part in the rendering pipeline, each screen must have its own root UIWindow instance. For that matter, Apple added a new UIWindow property allowing to switch an entire root window from one screen to another.
How should I use it in my apps
Apple typically recommends using the new UIScreen API to display the main contents of your application (such as videos and pictures) on the external screen. While you would use the device’s multitouch-enabled main screen for displaying auxiliary data and/or controls. In our case, we wanted to use the new APIs so we could demo our apps during meetings or to showcase our work to our clients.
Mirroring the contents of the device’s main screen
In a nutshell
- Automatically detect displays
- Upon detection:
- Setup a root window for the external display
- Schedule a timer that will be fire on screen refresh
- On every screen refresh:
- Copy the device’s main screen to the external screen
Starting in iPhone OS 3.1, the recommended way to periodically refresh screen contents is to use the CADisplayLink class (especially for OpenGL-based games). It is a runloop-based API that is synchronized with Core Animation, the iOS graphics subsystem. The easiest way to copy the contents of the screen is to use the UIGetScreenImage() function. This function used to be a private API, but Apple allowed developers to use it since the fall of 2009. UIGetScreenImage() returns a CGImageRef instance, basically a screenshot of the main screen. Unfortunately, UIGetScreenImage() does not respect the Core Foundation naming conventions, which shows that Apple never really intended to allow public use of this API.
It is important to note that when we schedule our CADisplayLink instance on the runloop, we need to set it so that it fires on NSRunLoopCommonModes input mode. If instead we use the NSDefaultRunLoopMode input mode the timer will not fire when tracking touches (UITrackingRunLoopMode). NSRunLoopCommonModes is a special input mode that combines all input modes, including UITrackingRunLoopMode, but this has a noticeable impact on the performance of screen mirroring. The current generation iPad cannot copy the entire screen to the secondary display buffer without affecting the interface responsiveness.
The UIApplication+ScreenMirroring category
We’ve taken everything we’ve learned while playing with the new UIScreen API and have put together a very simple Objective C category for the UIApplication class. This allows you to add the screen mirroring capability with a single line of code. You would typically call [UIApplication setupScreenMirroring] in your application:didFinishLaunchingWithOptions: method. We have not yet tested this piece of code on the new iPhone 4, but according to the Apple Dev Forum, the new device officially supports the VGA dongle and should work just fine.
The source code for this class is available on Google Code (licensed under New BSD license), along with a sample project showing the various options. For instance, you can get notified when the screen mirroring gets enabled / disabled so can display a visual cue to your users.
A technical article by François Proulx
Software engineer / iOS applications developer


[...] This post was mentioned on Twitter by François Proulx, Thomas Sarlandie. Thomas Sarlandie said: Backelite Blog – Presenting your apps on the big screen – Screen mirroring for iOS – http://bit.ly/bKa1BE [...]
Sweet, does this also work on a 3G with OS4?
Hi, thanks for that. This is awesome! Just wondering if that works 3G, iOS 4.0 AND Apple’s composite/component cables?
I tested few minutes ago and I didn’t get it work. [UIScreen screens] returned just the main screen. It doesn’t recognize my av cable… Any ideas?
PS. Can you email me if you know some kind of solution to this problem?
I tried your code, but I get 4 errors, the errors are caused by the code that uses CATransform3DMakeRotation, and the displayLink
Any ideas?
Also, in the code you say this only works on a iPhone 4, I can’t find in the developer documentation about that, where did you got that info?
//Bart
Undefined symbols:
« _OBJC_CLASS_$_CADisplayLink », referenced from:
objc-class-ref-to-CADisplayLink in UIApplication+ScreenMirroring.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
Ld build/Debug-iphonesimulator/TVOutTest.app/TVOutTest normal i386
cd /Developer/Development/TVOutTest
setenv MACOSX_DEPLOYMENT_TARGET 10.6
setenv PATH « /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin »
/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc-4.2 -arch i386 -isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.0.sdk -L/Developer/Development/TVOutTest/build/Debug-iphonesimulator -F/Developer/Development/TVOutTest/build/Debug-iphonesimulator -filelist /Developer/Development/TVOutTest/build/TVOutTest.build/Debug-iphonesimulator/TVOutTest.build/Objects-normal/i386/TVOutTest.LinkFileList -mmacosx-version-min=10.6 -Xlinker -objc_abi_version -Xlinker 2 -framework Foundation -framework UIKit -framework CoreGraphics -o /Developer/Development/TVOutTest/build/Debug-iphonesimulator/TVOutTest.app/TVOutTest
@Mikko:
No, that’ll only work on OS 3.2 on the iPad or iOS 4 on the new iPhone 4.
@Bart:
Make sure to link against SDK 4.0 (Base SDK in your project config), then make sure you link against the CoreGraphics and QuartzCore frameworks.
Maybe some bad news here : http://www.tuaw.com/2010/07/21/devsugar-rip-uigetscreenimage/ « Apps using UIGetScreenImage will no longer be greenlit for the App Store. Instead, developers will need to use standard Quartz methods (as mentioned aboved) or migrate their camera capture code to AVFoundation. »
Awesome job.. But do you guys know how the DisplayOut app works? I have watched some video on youtube and DisplayOut seems working smoother..
Did they hijacked lower level API’s or something?