Using top shelf layouts with tvOS (Part 3/3)

Teddy Georgieva
Dev Labs
Published in
8 min readMay 31, 2017

--

Overview

Much like the iPhone/iPad’s dock, where you can place some of your most used apps, Apple TV’s top shelf allows the user to keep his favorite apps atop all others for ease of access.

Contrary to the dock, however, the top shelf gives you the ability to showcase imagery from your app, either to entice the user with new and attractive offers, or to provide him quick access to his content.

In this tutorial we’ll explore the top shelf’s layouts and make some to showcase our catalogue’s content.

Download the images used in this tutorial here.

This is the last part of a tutorial that started with Creating a catalogue style TableView with tvOS (Part 1/3) and continues in Using Parallax images and Focus Guides in tvOS (Part 2/3). You can use those as a starting point if you wish or apply this tutorial to a new tvOS project.

Section content row

The first type of top shelf content we can show presents a single row of sectioned content. You can place a user’s favorite or recently viewed episodes. There is a label that shows when an item is focused. You can add deep link scheme to handle a selection of an item and launch your app to the desired content.

Let’s start by adding a top shelf.

Go to File -> New Target. From the menu select TV Service Extension. Name it top-shelf and click Finish.

At this point you might be presented with the following message:

Select activate to allow the simulator to test your top shelf.

You should see a new target in the Navigator. If you extend the target you’ll see two files — a swift file named ServiceProvider and an Info.plist.

The ServiceProvider.swift file is where you’ll setup our top shelf content. You’ll make a single section with 5 items to showcase a favorite episode for each season of your show.

The topShelfStyle variable defines the type of top shelf layout. It’s default value is sectioned. We’ll leave it like this for now.

The topShelfItems defines an array of TVContentItems. You’ll define your UI items here.

Before we begin creating our top shelf items, we’ll need to import some images. The Parallax effect is default for a TVContentItem’s image property. This means all we need to do is add some plain pictures and the top shelf will add all necessary animations and effects. So, unzip the images.zip folder and import the images to the top-shelf target. Check Copy items if needed to make sure your images are imported.

Now, open ServiceProvider.swift and replace the topShelfItems variable:

 var topShelfItems: [TVContentItem] { // Create an array of TVContentItems. let latestEpisodesIdentifier = TVContentIdentifier(identifier: "Latest episodes", container: nil)! let latestEpisodesSection = TVContentItem(contentIdentifier: latestEpisodesIdentifier)! latestEpisodesSection.title = "Latest episodes" var newEpisodesItems = [TVContentItem]() for index in 0...4 {  let newApisodeIdentifier = TVContentIdentifier(identifier: "\(index)", container: nil)!  let newEpisodeItem = TVContentItem(contentIdentifier: newApisodeIdentifier)!  newEpisodeItem.title = "Arrow S0\(index + 1)E01"  newEpisodeItem.imageURL =  Bundle.main.url(forResource: "season\(index + 1)", withExtension: "jpg")  newEpisodesItems.append(newEpisodeItem) } latestEpisodesSection.topShelfItems = newEpisodesItems return [latestEpisodesSection]}

Let’s break it down:

  1. You defined a section showing the Latest episodes
  2. You created an array containing your 5 items
  3. You set the sections’s topShelfItems to the array, containing the items

To test your top shelf you can use the scheme generated when you created the top shelf target.

Build and run your app, choosing Top Shelf from the dialog and press Run:

You should see your new top-shelf items. Scroll through them. Cool, right?

Adding deep links

Your top shelf look pretty cool right now. But it’s not complete. Let’s allow your users to actually interact with your items and open up your app when one of them is pressed.

When a user selects one of your top shelf items, AppDelegate will call application(_ app: open: options:) if, of course, your items have a displayURL or a playURL. Those properties store an item’s deep link scheme and allow you to do some custom work when a specific deep link is received.

You’ll start by opening your Info.plist. Make sure to open the catalogue-top-shelf target’s Info.plist.

Add a new row. Name it URL types. Xcode will autocomplete as you type. Press enter once it’s complete and Code will set the correct type for your new property. Then expand it.

You should see another row named Item 0 of type Dictionary. Expand that as well.

Using the + add a new row to the Item 0 dictionary called URL Schemes. Expand that as well. You URL types key should look like this:

Set the value of Item 0 of URL Schemes to catalogueapp, and URL identifier to CatalogueApp URL. Your finalized plist entry should look like this:

These properties allow your app to monitor for and response to calls containing the scheme you placed in URL Schemes. Now you’ll add a URL link to the top shelf items you created and define your app’s behavior whenever a deep link from the defined URL Schemes is detected.

Let’s add a displayURL to out items. Head to ServiceProvider.swift and add this right before appending the newEpisodeItem to the newEpisodesItems array:

 var components = URLComponents() components.scheme = "catalogueapp" components.queryItems = [URLQueryItem(name: "episode", value: "episode\(index + 1)")] newEpisodeItem.displayURL = components.url

Basically, what you’re doing is constructing a url that takes your Info.plist URL scheme and creates a query item that takes the current scheme and appends the number of the TVContentItem to which it’s attached.

The finished query looks like this:

catalogueapp:?episode=1

But you can always change it or make it more specific. In fact, it’s highly recommended that you do.

Now, open AppDelegate and add:

 func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {  print(url)  return true}

Pretty simple and basic functionality — you just want to see that the url you added to the TVContentItem works as expected, so we take the incoming url and print it.

Since you’ve been running the TopShelf scheme until now to test your topShelfItems, for the AppDelegate functionality to work you need to go back to your app’s scheme and run in on a Apple TV simulator.

To navigate to your top shelf after your app has launched you need to exit either by pressing the Esc button on your keyboard or by using the simulator’s Apple TV remote (Hardware — Show Apple TV Remote or Shift + Cmnd + R). After your app is minimized the focus is probably on the Settings app. You need to scroll through to your app, then navigate up to you tiles and select one of them. Your app should launch to it’s main screen and print out the url.

And that’s it. From here on you can open your app at a specific page depending on the episode or start streaming the episode directly. Go ahead and try some out for yourself, like opening up our title details if the user selects episode number 2.

Note: If you’re having difficulties adding this feature, here is the finished project.

Scrolling Inset Banner

The second type of top shelf present content like a scrolling continuity of banners. It shows a chain of large images, filling the entirety of the top shelf. The scroll is automatic but the user can still use the remote control to scroll through them. You can use it to show new content for your game or a banner for a latest episode of your show.

You’ll be glad to hear the sequence for creating this second style of banners is quite similar to what you’ve already done. In fact, you’ll use your existing top shelf project and tweak a few thing to get the best effect with minimal effort.

Head over to ServiceProvider.swift.

First, you need to change the type of the top shelf. Change topShelfStyle to inset.

Then, change the topShelfItems. Since the inset type of top shelf has only one section we basically need to remove the sectioning and leave just the items.

 var topShelfItems: [TVContentItem] { // Create an array of TVContentItems. var newEpisodesItems = [TVContentItem]()   for index in 0...4 {    let newApisodeIdentifier = TVContentIdentifier(identifier: "\(index)", container: nil)!    let newEpisodeItem = TVContentItem(contentIdentifier: newApisodeIdentifier)!    newEpisodeItem.title = "Arrow S0\(index + 1)E01"    newEpisodeItem.imageURL =  Bundle.main.url(forResource: "season\(index + 1)", withExtension: "jpg")    var components = URLComponents()    components.scheme = "catalogueapp"    components.queryItems = [URLQueryItem(name: "episode", value: "\(index + 1)")]    newEpisodeItem.displayURL = components.url    newEpisodesItems.append(newEpisodeItem)   }  return newEpisodesItems}

With that your new top shelf should be available. Build and run your app and enjoy your new scrolling banner top shelf. Now if you choose one of those banners you’ll be asked f you want to open your app. Select open and bask in the glory that’s you. Pats on the back for a job well done.

Note: If you’re having difficulties adding this feature, here is the finished project.

--

--

Comic book fan. DIY enthusiast. iOS Developer. Writer. Aspiring designer.