Introduction
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() { super.viewDidLoad() // Setup to process external screen notifications setupScreenNotifications() // Load the WKWebView with something to show if let url = NSURL(string: "http://www.spazstik-software.com") { let req = NSURLRequest(URL: url) webView?.loadRequest(req) } // Check to see if there is an external screen already connected if UIScreen.screens().count > 1 { setupExternalScreen(UIScreen.screens()[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 { return } setupExternalScreen(screen) }
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 { return } teardownExternalScreen() }
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 { return } 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.
Facebook Twitter Google+