Sample tvOS App

Writing Apps for Apple TV for fun and (no) profit

A new AppleTV

On 9th September 2015 Apple announced a new version of Apple TV, the fourth-generation, and it brings a long awaited feature: Apps.

Many times I asked myself why Apple didn’t enabled Apps on Apple TV. Advantages are obvious to me: iOS is one of the most widespread mobile OS and the one with highest number of Apps. Porting Apps to Apple TV can be really simple and this make it the platform for TV with the higher number of Apps.

Eventually Apple did it and better than I could imagine. Apps for Apple TV can be made with classical approach, like we develop native Apps for other iOS devices, or in a new way based on a specific markup language and JavaScript. The latter is really interesting and at the same time strange for Apple standard, what I’d like to do in this article is make a simple example to explore this new way.

TVML, TVJS and TVMLKit

Apps made with this new way use three new technologies, precisely TVML, a markup language made to create the UI (TVML stands for TV Markup Language). TVJS, a  JavaScript API to display and interact with TVML, and TVMLKit, the native layer to combine all together.  I’m a big fan of learning by examples approach so let’s start with a sample.

A simple tvOS App

Sample tvOS App

Before starting make the example a few words on TVMLKit App’s architecture, this kind of Application is made of two parts: one native and one JavaScript.

TVMLKit App Architecture

In a nutshell native code is something like a container which load startup JavaScript and give control to it. JavaScript and resources can be loaded from a remote server (ie a web server) so our App can be remotely updated after released on the App Store without making a new submission (this is one reason because I wrote this model is strange for Apple). So we’ll start making the native part, I assume You have XCode 7.1 or higher.

Launch XCode a choose tvOS Single View Application.

tvOS App template

Standard template for tvOS Application includes some files we don’t need, so first operation is to trash ViewController.swift and Main.storyboard, these will be not used in our example. We need to change some settings too, default template is made to use storyboard UI, we removed Main.storyboard and so delete “Main” in Main interface setting (You can also remove this by opening Info.plist file and removing “Main storyboard file base name” key). Project settings

Last operation is to permit to the App to make HTTP requests to outside world, with iOS 9 Apple introduced transport security setting and by default it blocks all networks requests. So open Info.plist file and add App Transport Security Setting like in the following image (“Allow Arbitrary Loads” set to YES is the mandatory part).

App Transport Security Setting

 

Let’s write the code

Now it’s time to modify AppDelegate, we have to delete all methods put by XCode, import TVMLKit and make AppDelegate class conform to TVApplicationControllerDelegate.

import UIKit
import TVMLKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, TVApplicationControllerDelegate {
    var window: UIWindow?
}

In this state our App isn’t able to do much so we need to add the code to bootstrap the JavaScript which represents the real core of the App. What we need to do is create a TVApplicationController giving to it necessary info to load the JavaScript code which handle UI.

import UIKit
import TVMLKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, TVApplicationControllerDelegate {

    var window: UIWindow?

    var appController: TVApplicationController?
    static let TVBaseURL = "http://localhost:9001/"
    static let TVBootURL = "\(AppDelegate.TVBaseURL)/app.js"
    
    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        window = UIWindow(frame: UIScreen.mainScreen().bounds)
        
        // Controller context for loading JavaScript
        let appControllerContext = TVApplicationControllerContext()
        // Url from which to load javascript
        appControllerContext.javaScriptApplicationURL = NSURL(string: AppDelegate.TVBootURL)!
        // BASEURL variable will be available in the JavaScript code
        appControllerContext.launchOptions["BASEURL"] = AppDelegate.TVBaseURL
        
        // Standard controller for tvOS Apps based on TVMLKit
        appController = TVApplicationController(context: appControllerContext, window: window, delegate: self)
        return true
    }
}

First we set two variables with the base URL where to load scripts from, TVBaseURL, and the URL of the bootstrap script, TVBootURL. After we need to implement didFinishLaunchingWithOptions, this method is called on Application start and here we did two logical operations:

  1. Create a TVApplicationControllerContext used to load JavaScript
  2. Create a TVApplicationController, passing to it the previous TVApplicationControllerContext, to handle Application lifecycle

That’s all we need for the native part of our App, now it’s time to move to the JavaScript side.

The JavaScript side

Native part of App loads a simple JavaScript, creates a new folder in the root of the project where to put the code. Call it “js”, now creates a app.js file and put the following code in it.

App.onLaunch = function(options) {
  var menu = mainMenu(); 
  navigationDocument.presentModal(menu);
}
 
var mainMenu = function() {
  var tvmlCode = `<?xml version="1.0" encoding="UTF-8" ?>
   <document>
   <mainTemplate>
      <background>
         <img src="https://c1.staticflickr.com/7/6050/6350327968_33f008d9c2_b.jpg" />
      </background>
      <menuBar>
         <section>
            <menuItem>
               <title>PLAY</title>
            </menuItem>
            <menuItem>
               <title>SCENES</title>
            </menuItem>
            <menuItem>
               <title>EXTRAS</title>
            </menuItem>
         </section>
      </menuBar>
   </mainTemplate>
</document>
`
    var parser = new DOMParser();
    var menuDoc = parser.parseFromString(tvmlCode, "application/xml");
    return menuDoc
}

As I already wrote JavaScript is the real core of our application. App.launch is the entry point of the code, it’s called when the script is loaded by TVApplicationController. In launch there is a first interaction with TVJS API, navigationDocument. This object is used to present views on the screen in few different ways, it’s something comparable to UINavigationController if You wrote some native code for iOS.

The code is pretty simple, launch method calls mainMenu function, this function uses DOMParser to make a document object starting from a TVML template. The interesting part is tmvCode variable which contains TMVL code to make the user interface. TVML is a custom XML which defines the UI elements, it starts alway with <document> element and contains many different children elements who renders on the screen in different ways. In our simple case we used <background> to put an image on the background and <menuBar> for the menu on the bottom of the screen (menuBar is a complex element with a three of children for define the inside items). A full documentation of TVML is available on Apple Developer Site.

Now we are ready to try our simple App, in the native part we used an URL to load app.js, so we need to serve this script using a web server. The simplest way to make this is to use python which is installed by default on Mac OS X. Before running the App from XCode launch the Terminal and go in the folder with app.js, from here type the following command

python -m SimpleHTTPServer 9001

This command runs a simple web server listening on port 9001 serving files from current folder. Started the web server run the App from XCode the App and it’ll be executed on Apple TV simulator or on the real device if connected to the Mac.

Conclusion

This article is a simple introduction on how simple can be write Apps for tvOS, make real applications it’s obviously more complicated than this. In a future article I’ll describe how to use NodeJS as backend for a TVMLKit App using a template system to handle dynamic TVML generation.

Source code of the app can be found here.

Linking iOS App from Web

Nowadays almost all web sites  match with a mobile Application. Users jump from web to Apps and back, making this experience as fluid as possibile is becoming really important. In this post I’d like to explain the standard approach to this problem and how I get an enhanced solution to it.

Redirect to store to download the App
Redirect to store to download the App

Standard approach

Before describing the standard approach we need to explain how an iOS App can be launched from a web site and how this is typically used.

iOS Apps comes with a configuration file named Info.plist who gives all the parameters needed by the iOS runtime to execute the App itself. Some of these parameters are  App name, supported screen orientations, default language and many others. One of these is URLscheme  who is a powerful system to launch the App from outside.

Looking to a snippet of Info.plist took from my App Pushetta it looks as follow:

<key>CFBundleURLSchemes</key>
<array>
<string>pushetta</string>
</array>

What this mean? It simply says the App can be executed with a custom url, in this case the url is pushetta://. So first step is now clear, if a web page has a link with this url schema, loading it on a device with the App installed and using the link the App is started. WOW this is great!!! But wait a moment, if the App isn’t installed? Ehm, we get an error.

Url scheme error
What happen when App isn’t installed?

Error is self explaining, we tried to open an url Safari doesn’t understand. This freezes our initial enthusiasm.

The standard solutions comes in mind is to check if the App is installed before running the custom url. BEEEEEEEP!!! This isn’t possible! For (obvious) privacy problems a web page can’t inspect the device to known if a specific App is installed.

Ok, so we are at dead end, we know how to execute the App from web page but we don’t know how to be sure is installed before this.

Some clever people made a work around to this problem with a trick based on JavaScript setTimeout function. The idea behind the solution is: we start a timer that when expire executes a function whose redirects the user to a predefined url (it can be for example a landing page with info about the App and a link to the store). Right after the start of the timer the script try to launch the App with the custom url, so we get two scenarios:

  • App is installed: it runs and the timer never fires (this because running the App brings the user outside the browser)
  • App isn’t installed: we get the error but after awhile we get redirected to a predefined page

The code for this solution is

   setTimeout(function(){
                window.location = "http://www.pushetta.com";
              }, 1000);
   document.location = "pushetta://";

The code make exactly what we described: it sets a timer function that after one second (1000 milliseconds) redirects the user to http://www.pushetta.com. Next it tries to run pushetta:// custom url scheme and this implies the two scenarios described.

This is a pretty poor solution, it works but with a bad user experience. This is where I started to look for a better solution, googling around wasn’t productive so I decided to make some tries. My starting point was: I can’t check if the App is installed but if I could handle the error on opening a wrong url this would be enough to resolve the problem. This is simplest to say that to do, window.location gives an error when we try to open a wrong url but it seems not trappable by code. So how can we do? The solution I used is based on a iframe. As many know an iframe is something like an hole (squared) inside the page who loads another url, the idea is: if I create an iframe in the DOM with it’s src set to the custom schema, will it show the error popup when the schema is wrong (ie the App is not installed)? Luckily enough this doesn’t happen and so we can implement the right solution based on this behaviour.

   // timer func to bring the user to a web page if App isn't installed
   setTimeout(function(){
            document.location = "http://www.pushetta.com";
        }, 1000);

   // put an iframe in the DOM with "pushetta://" as src (and 0x0 dimensions)
   ifrm = document.createElement("IFRAME"); 
   ifrm.setAttribute("src", "pushetta://"); 
   ifrm.style.width = 0+"px"; 
   ifrm.style.height = 0+"px"; 
            
   document.body.firstElementChild.appendChild(ifrm);

The solution seems to work well but I consider it a test to be verified with various scenarios.

App_icon_180

Push notification from Arduino Yún

I have often wished a system to send notifications to cell phones without paying for it (ie SMS) or using emails.

Major mobile operating systems include those that are commonly referred to as push notifications and slowly these are getting available also on Desktop system. The use of push notifications is not trivial because every system (or at least the major ones) requires to develop a custom App as receiver of notifications.

Simply put, notifications aren’t like SMS, where knowing the phone number is enough to send a message, no!! You need to develop an App and use a server provided by manufacturers of mobile operating system (ie Apple, Google, Microsoft, …) but this isn’t enough there are also some security requirements like digital certificates and other pagan rituals.

Back to the top what I needed was a simple notification system and looking around I was not able to find one, so I made Pushetta. The opportunity came from the integration of my pellet stove in Domitio, my home automation system. One of objectives was to get notified when pellet level was below a threshold, this information is important because some stoves fails to start,  when refilled, if pellet has been previously completely exhausted (mine is one of these).

Pellet Stove
Pellet Stove

So, Pushetta is a simple system I made to send notifications to mobile phones (and also desktop in future), components are:

Typical use case is:

  • User interested in send notification register on pushetta.com
  • He /She defines a Channel, that is a node where send notification
  • User wants to be notified downloads the App
  • By the App he seeks interested channels and subscribes them
  • Every time a message is “pushed” to a channel subscribers receive it

Back to my stove I made a custom shield for my Arduino Yún to interact with it, this interfaces Arduino with a ultrasonic sensor that measure pellet level and some relays to controls start and stop of the stove.

Stove controller
Stove controller
Ultrasonic sensor
Ultrasonic sensor

So, stove controller continuously measures pellet level and when under a threshold uses Pushetta to send a notification. Sending notification from Arduino it’s really simple, nothing can explain it better than show a trivial example.

Sample sketch
Sample sketch

Example shown in picture is a modified version of the “Button” example found in Arduino IDE, in this version (made for Arduino Yún) when button connected to pin 2 is pressed a push notification is sent. In my stove automation system I use the same code to send notification when pellet level goes too low.

Pushetta isn’t limited to Arduino, it can be used virtually from any system can make an http post with a json payload. I used it also in an experiment with Raspberry Pi where I made a simple face recognition software who sends a push notification if I’m the subject in the camera.

I’m looking for beta tester because Pushetta is a “spare time” project but I would like to transform it in a production level software, look at www.pushetta.com if You can help me.

Apple WWDC 2014

Apple developer event of this year was really rich and for the first time after many months I see a revamped strategy in Apple plans.

The strategy is clear: focus on ecosystem!

wwdc_banner_promo

Yes, a great advantage of Apple on concurrents it’s a large and consistent ecosystem. Making it more integrate can overtake other ones (Google in primis). Increasing cooperations capabilities of two main platforms can give to end user features that other (aka Android) can’t reach out.

But, letting marketing strategies to Apple, I’d like to point attention to the shift to the new language for App development: Swift.

I spent part of night reading the free eBook downloadable from itunes, and a thought flashed in my mind: is this an Apple’s try to make only one language for client Apps and backend?

Swift appears more suitable of Objective-C in a server side use, and a big problems of today App developers it’s backend. Many App developers can fluently write client software but at same time it can be really problematic for they to write backend one. So what if Apple will offer a backend solution programmable with the same language we use for writing clients Apps? How many developers will use this service? I think many, or rather MANY!

The idea it’s only speculation at this moment but there are some good reasons to let me think can be real in near future:

  1. Apple announce also CloudKit, so backend problem is clear to Apple
  2. Controlling backends of Apps can enhance security
  3. New services can be developed and offered in a straightforward way using internal Cloud
  4. Giving developer a good environment it’s the best way to keep them

It’s not only a language problem, Android is Java based and Java it’s perfectly suitable for server side development. It’s, again, ecosystem related. Backend it’s problematic because it needs system related skills, also using one of many cloud solutions. Developer needs to known about systems and all architectural decisions  are up to him.

What I imagine from Apple instead it’s an integrated solution where developer doesn’t need to care about server system. I imagine an Xcode release where You can write client software together with server one and publish App and server software will be a matter of some clicks.

I really hope these speculations will be real in a near future, work in a so integrated environment will be a big boost in developer’s productivity and I can’t wait to try it 🙂