How To Display Custom Content On A External Screen From A iOS Device

Date Published:
Last Modified: by


I rarely use Airplay mirroring to display the screen of a iPad or iPhone on a Apple TV. It is surprisingly simple to give your application this capability. This tutorial goes over the steps required by discussing a simple demo application. This application is located on GitHub.

Steps To Enable Mirroring On iOS

It is pretty simple to enable screen mirroring on a iPad or iPhone. To enable screen mirroring do the following: 1. Swipe up from the bottom of the screen to bring up control center. Control center has a button for AirPlay. 2. Tap AirPlay. This will bring up a selection menu that lists the possible AirPlay devices. These are all the devices that are connected to the same network that you iPad or iPhone is connected to. 3. Select the name of the Apple TV you want to mirror to. 4. Once the Apple TV is selected, a Mirror slider is displayed. You will need to enable this.

You should now see you iPad or iPhone screen on the TV.

What Does You Application See When This Happens

The UIScreen class has a method called screens that returns an array of UIScreen objects that are enabled on you iPad or iPhone. The first entry in the array is the main screen for the iPad or iPhone. Any additional screens are external screens enabled. Any mirrored screen is contained in this array.

Your application can register for notifications that a screen has connected or disconnected.

To enable support for custom external screen content your application will have to support the following: 1. When your application is starting a view that you wish to support external content, the screens array should be examined during the view controller during the initialization sequence. This supports when the external screen is already enabled on startup. 2. Register for the two system notifications: UIScreenDidConnectNotification, and UIScreenDidDisconnectNotification. This enables support for when your users enable or disable a external screen while you view is already loaded.

iOS Simulator

The iOS simulator supports simulating external displays through its hardware menu item. The external displays menu items allows you to create displays with several different resolutions.

The Sample Application

The sample application accompanying this article is a simple single view application. The storyboard has two view controllers defined. The initial view controller is for displaying web content on the devices screen. The second view controller is used to display the same web content on any external screens.

The main view controller has the following viewDidLoad method:

  override func viewDidLoad() {

    // Setup to process external screen notifications

    // Load the WKWebView with something to show
    if let url = NSURL(string: "") {
      let req = NSURLRequest(URL: url)


    // Check to see if there is an external screen already connected
    if UIScreen.screens().count > 1 {

The first thing that happens is that the handlers are registered for handling screen connects/disconnects by calling the setupScreenNotifications method (more on this next).

The UIScreen.screens array is examined after a request is made to load the web content. The external screen is setup if it is already displayed by calling the setupExternalScreen method.

  /// Method used to register the notification handlers for external
  /// screen connects/disconnects
  private func setupScreenNotifications() {
    let center = NSNotificationCenter.defaultCenter()

    center.addObserver(self, selector: #selector(MainScreenViewController.externalScreenDidConnect(_:)), name: UIScreenDidConnectNotification, object: nil)
    center.addObserver(self, selector: #selector(MainScreenViewController.externalScreenDidDisconnect(_:)), name: UIScreenDidDisconnectNotification, object: nil)

The setupScreenNotifications method registers the two methods used to handle the screen connect/disconnect: externalScreenDidConnect(), and externalScreenDidDisconnect. Remember to deregister for these notification in the class deist method!

  /// The method used to handle the external screen connection NSNoticiations.
  /// - parameter notification: A NSNotification object that informs us about
  /// the UIScreen instance that has just become active
  func externalScreenDidConnect(notification: NSNotification) {
    guard let screen = notification.object as? UIScreen else {


The externalScreenDidConnect() method extracts the UIScreen object from the notification object using the guard statement. If successful, it calls the setupExternalScreen() method.

  /// The method used to handle the notification for when a external screen
  /// disconnect.
  /// - parameter notification: A NSNotification object that informs us about
  /// the UIScreen instance that has just disconnected
  func externalScreenDidDisconnect(notification: NSNotification) {
    guard let _ = notification.object as? UIScreen else {


The externalScreenDidDisconnect() method simply calls the teardownExternalScreen() method to disable the external content.

  /// A private method used to setup a external screen with a window
  /// loaded with a ExternalScreenViewController
  /// - parameter screen: A UIScreen object to connect the
  /// ExternalScreenViewController too
  private func setupExternalScreen(screen: UIScreen) {
    guard externalWindow == nil,
      let vc = self.storyboard?.instantiateViewControllerWithIdentifier("ExternalScreen") as? ExternalScreenViewController else {

    externalWindow = UIWindow(frame: screen.bounds)
    externalWindow!.rootViewController = vc
    externalWindow!.screen = screen
    externalWindow!.hidden = false

To setupExternalScreen() method performs the following: 1. Checks to make sure we are not already displaying content on a external screen. 2. Loads an instance of the ExternalScreenViewController from the storyboard. This instance will be used to display on the external screen. 3. Creates a new UIWindow object and set its frame property to the bounds of the screen. 4. Set the root view controller to the new view controller this method created. 5. Sets the UIWindows screen property to the screen object passed in. 6. Makes the new UIWindow object visible by setting it’s hidden property to false.

Thats it. The external screen is now displaying your content!

  /// A private method used to teardown the external UIWindow object
  /// used to display the content on the external screen
  private func teardownExternalScreen() {
    guard let ew = externalWindow else { return }

    ew.hidden = true
    externalWindow = nil

To cleanup the external screen. The teardownExternalScreen simple hides the window created to display the external content. And then nils out the externalWindow property to cause the window and view controller objects to be cleaned up.

In Conclusion

I was surprised at how straight forward this is. The capability is relatively hidden and forgotten, but enables your users to show off in new ways.

Rodger Higgins is the founder of Spazstik Software, LLC. He has created StackCalc, The Visual Touch Calculator and SPZTracker.

Recent Articles

A Reusable Observer Protocol Written In Swift

One design pattern that I use a lot is the observer pattern. The observer pattern is used when you have an object that needs to notify a list of objects that state changes have happened. This article discusses a reusable component, in Swift, I developed to speed up my development process.

How To: Support User Editable Python Macros In A I Os Application

Last month I published a article on how to use JavascriptCore for extending a iOS application with macro support. While Javascript has many uses, as a way for application customization, it would not be my first choice.

A better choice to me would be a language like Python. Being curious, I wondered what it would take to to use Python. This article discusses what I found.

How To Example: Extend A I Os Using Javascript Core As A Macro Engine

JavascriptCore is a framework that offers the ability for a iOS application to interact with javascript code. Primarily used for cross platform code sharing, it can also be used to extend a iOS application with macro capabilities. This framework offers a world of possibilities for extending any iOS application.

How To: Custom I Os Activity Tracker View Using Ca Layers

The Apple Watch shipped with a captivating activity tracker. The center piece is a really cool spiral animation scheme showing the amount of activity during the day. This image is also shown on the matching iPhone Activity App. I have always wanted to see what it would take to implement this myself. The examples that I see typically use a custom drawRect override, but I always wanted to see what it would take to do with CAShapeLayers.

Implementing a 0-100% control is straight forward when using CAShapeLayer. But how do you implement a progress indicator that support progress values greater then 100%? This How To discusses a solution that I came up with along with it’s potential limitations.

How To Display Custom Content On A External Screen From A I Os Device

Being able to display content on a external screen or device is a great capability to add to a iOS application. Especially how easy it is. This article will show the step required to to do this.


Follow us on

Articles by published month

Articles by subject matter

Rails Thor Compass Susy Modernizr Rspec Capybara Bettererrors Railspanel Aws Rack Railscasts Http Aws-elastic-beanstalk Ruby-on-rails Rack-rewrite Http-response-codes Pow-amazon-route-53 Stackcalc Iphone Ios Mobile Application Skeumorphic Dns Web-site Elastic-beanstalk Elastic-ip Elastic-load-balancer Tutorial Howto Javascript Javascriptcore Macro Example Swift Design-patterns Observer Python Macros Alamofire External-screen-support Apple-watch Activity-tracker Office Status S100 Cloud Astronomy Picture Mars Apple Usb-c Leonard-nimoy William-shatner Geotag Gps Spztracker Geotagging Photos Secret Marketing Watch Watch-repair Head-transplants Perception Diabeties Sugar Health Rosette-nebula News Spock Comet-lovejoy

Click here to receive free tips and tutorials!

This web site uses javascript exclusively for automating html elements. Please enable javascript to fully experience the features offered on this site.