Sharing functionality across tvOS and iOS

How to make the most out of your code

Manuel Marcos Regalado
ribot labs

--

Since Apple announced tvOS at WWDC in 2015, there’s been a lot of new helpful tutorials on how to develop and design for tvOS. However, there hasn’t been much written about how to share functionality across platforms and make the most out of your code.

In this article, we’re going to tackle this approach and its concept. This is not a definitive or final solution, but it might give you some insights and inspiration before you start making your next tvOS and iOS Apps.

The article won’t give you a step by step tutorial, so some high-level development knowledge is needed to understand the showcase and proof of concept of sharing functionality across different targets.

The essentials

Share CocoaPods

I’ve used CocoaPods in 90% to 95% of the apps that I’ve developed. I’m guessing it would be the same case for most of the developers out there. CocoaPod is a great dependency manager for Swift and Objective-C Cocoa projects, they make a developer’s life much easier when integrating external libraries.

Most of us have probably shared CocoaPods between different targets but, have you ever thought about sharing your CocoaPods between different platforms targets? Yes, it is possible. You just need to define the platform within each target in your pod file as follows:

# Podfile
source 'https://github.com/CocoaPods/Specs.git'

def shared_pods
pod 'Alamofire', '~> 3.0'
pod 'AlamofireImage', '~> 2.0'
end

target 'iosTarget' do
platform :ios, '9.0'
use_frameworks!
shared_pods
end

target 'tvosTarget' do
platform :tvos, '9.0'
use_frameworks!
shared_pods
end

Then, you will only have one shared CocoaPod project in your workspace. In this example we have only defined “share_pods” but you could add platform specific pods by adding them to each target.

Before you install your pod file, make sure that you are running the latest CocoaPod version, there was an issue in previous versions that wouldn’t let you install the pod file in both targets.

Share files

Most of you have probably shared files between multiple targets. Did you know that you can share files between different platform targets, such as iOS and tvOS, in the same manner as you would share them within the same platform? This is as easy as selecting both targets when creating a new file.

Add file to both targets

Share functionality

This is the most interesting part, it’s where the magic happens. Since tvOS and iOS have loads of libraries in common you are able to take advantage of sharing code between platforms. However, before we go any further into development, I highly recommend you to have a look at this iOS 9.1 to tvOS 9.0 API Diffs so you are aware of what can and can’t be shared.

I’d like to take the opportunity to explain the architecture we normally use in our iOS Apps:

ribot iOS Apps Architecture

The colored oval area is where we would like to share as much stuff as possible between platforms. Keep in mind that there are third party libraries that don’t support tvOS or iOS, then, it would be platform target specific.

Hands-on

Before we get our hands on the sample project provided and what each section shares, I’d like to explain very briefly what the ribot iOS & tvOS Apps do. They have the same functionality which is basically gathering a list of ribots from the ribot’s API and displaying their names along with their ribotars. This idea comes from a similar App that we have internally developed at ribot which helps us find out where every ribot is in our new big and shiny studio by using iBeacons. Check our case study!
By the way, if you are still wondering who the ribots are… let me introduce you to them!

The structure of the project is very simple, we are going to be mainly looking at these 3 groups:

  • Shared group: We will find all the shared classes between iOS target and tvOS target.
  • tvOS group: All the classes tvOS target specific.
  • iOS group: All the classes iOS target specific.

Now, let’s have a look at the structure of the Apps and how we can reuse code for each section.

Third Party Managers:

In this case, we are going to be using SharedNetworkManager. At ribot, we are big fans of descriptive names, regardless of length. By reading the name of the file you can almost tell what you are going to find inside it, so, have a guess :-) Yes! SharedNetworkManager is going to be our shared class in charge of the networking, in this case, specifically talking to the ribot API. If you have a look inside it, you will see that we are just making an API call to retrieve the list of ribots by using the library Alamofire (Well known in Objective-C as AFNetworking). This class would be used by both platforms as the functionality would be exactly the same.

Data Manager:

We always tend to use a Data Manager in all our Apps. It is the brain of our Apps and its aim is to reduce the amount of work that Controllers, Models and Managers have to do by providing data that is ready to display, store or work with. However, as I’d like to call it:

“The middle man — sitting between classes, ensuring harmony across the App by handling everyone’s needs.”

Therefore, in this case, the Data Manager is in charge of asking for a list of ribots to the Network Manager, sorting it and passing it back to the Controller which just needs to send it to the view to be displayed as it’s already sorted. This functionality is exactly the same regardless of what platform the App is running on, therefore, it makes sense to share the code.

Model

Since we are making the same request to the API, retrieving the same collection of objects and displaying the same data for the iOS App and the tvOS App, surely the Model would also be the same, right? Well, not necessarily, this is a very easy and specific case. Sometimes this won’t make much sense as Models can get very complex with multiple extensions and supporting different libraries which may not work for both platforms. However, in my opinion, I think there is always space for sharing some base Models between platforms.

So far, we haven’t had the need of splitting any functionality between platforms. Every task we’ve tackled can be applied to both platforms. This will change when we focus on UI.

Controller

In my opinion, this is the exciting part as it truly defines the concept of taking advantage of sharing base classes between platforms.
If we have a look at SharedRibotTeamViewController we will see that we are using some UIKit classes that are supported by both platforms, such as:

  • UICollectionView
  • UIActivityIndicatorView

It makes sense to implement the basic logic in this controller. However, be aware of the importance of having a good class structure where each function has clear responsibilities. You may want to subclass the controller for each platform so you are able to customise and make the most of UI platform related components.

iOS: An example of an only iOS UI component is UIRefreshControl or AKA Pull to Refresh which will only be available for iOS. How do we add a pull to refresh which just works for the iOS App? Easy, we just need to create a new class under our iOS target, subclass it of SharedRibotTeamViewController and add it to the controller.

Pull to refresh

tvOS: The same happens for tvOS. We now have the ability to customise the UI and make it look more native.

Have you seen those amazing parallax Apple TV effects when on focus yet? They are fairly easy to turn on, you just need to enable “adjust image when focused” in your image views.

Another common Apple TV collection views pattern is that the footer text won’t be visible until the collection view cell is not on focus. To add this functionality you will need to create a new class under your tvOS target, subclass it of SharedRibotTeamViewController and add the desired functionality.

One of the great improvements of Xcode 7, is that it lets you create your tvOS icon parallax effect within Xcode just by providing front, middle and back layers. Once you’ve added them, Xcode lets you preview them within the xcassets folder.

Xcode Apple TV icon parallax preview

For those who don’t have Xcode and still want to play generating parallax effects, you can download Apple’s Parallax Previewer.
I highly recommend you to try this as it is incredibly fun and easy!

Next steps

It’ll be interesting to see how well this could work for all Apple platforms, watchOS, tvOS, OS X, iOS. However, since the UI is very different we will consider just creating a shared layer of logic between the 4.

Have you tried building something like this yet? I’d love to hear your approach! If you wish to share anything or have any questions, feel free to drop me a tweet!

Also, if you liked this article you might also like what I wrote about Using iBeacons to track our team’s location in the new ribot studio.

--

--