Disclaimer: This is just a hack. I’m not in any position to make announcements about stuff, but Xamarin loves F# and I’m sure that better solutions than this are forthcoming. But this was fun to get running, so…
Xamarin just released it’s Preview of Watch Kit support and naturally, I had to see if it was possible to use F# to program the forthcoming Apple Watch. Yes, it is.
As always with Watch Kit Apps, the Xamarin solution consists of three projects:
- A Parent app that is a normal iOS app;
- An Extension that runs on a connected iPhone and executes the program logic; and
- A Watch App that runs on the Watch and is essentially a remote display for the Extension App
You can read much more about this at Xamarin’s Watch Kit Documentation site.
To create an F# Watch solution, first create an F#-based Parent App. Then, add the Extension project to that app, an F#-based Custom Keyboard Extension. Finally, add a Watch App from the C#/iOS/Unified/Apple Watch solution template.
The Watch App consists only of a storyboard and resources. It doesn’t actually have any C# (or F#) code in it.
Follow these instructions to [set project references and identifiers].
Switching the Extension from Custom Keyboard to Watch Kit
You will have to manually edit the info.plist
of the Watch Extension:
- In
NSExtension
, switch theNSExtensionPointIdentifier
tocom.apple.watchkit
; and - Under
NSExtensionAttributes
, add aWKAppBundleIdentifier
key to the identifier of your Watch App (e.g.,com.xamarin.FWatch1.watchkitapp
)
Now you can get rid of the template F# code and replace it with something like this:
[code lang="fsharp"]
namespace WatchX
open System
open UIKit
open Foundation
open WatchKit
type InterfaceController(ip : IntPtr) =
inherit WKInterfaceController(ip)
override this.Awake (context) =
System.Console.WriteLine("Hello F#")
this.myLabel.SetText("F# |> I ♡")
[/code]
Again, this is covered in much more detail in Xamarin’s docs, but every scene in the Watch App’s storyboard is backed by a subtype of WKInterfaceController
. Since it’s loaded from a Storyboard, it uses the constructor that takes an IntPtr
. The Awake
method is called when the controller is instantiated.
The Hacky Part
Xamarin has not yet released designer support for Watch Kit, so for now, you need to edit your Watch App’s Storyboard in XCode Interface Builder.
That’s not the hacky part.
Once you’ve designed your UI, you have to hand-edit the Storyboard XML, adding connections
elements that define your outlets (properties) and actions (event-handlers). You have to set the destination
attribute to refer to the id
of the associated control:
But really, that’s the only ugly part! ;-)
Back in your Extension app, you now have to use attributes to link up your F# code with elements within the Storyboard. The RegisterAttribute
on your WKInterfaceController
links to the customClass
attribute of the controller
element, and the name of your OutletAttribute
properties must correspond to the property
attribute of the outlet
elements. Finally, the selector
attribute of your action
elements must have a corresponding ActionAttribute
:
[code lang="fsharp"]
namespace WatchX
open System
open UIKit
open Foundation
open WatchKit
[<register ("InterfaceController")>]
type InterfaceController(ip : IntPtr) =
inherit WKInterfaceController(ip)
let mutable label : WKInterfaceLabel = null
let mutable button : WKInterfaceButton = null
let mutable clickCount = 0
[<outlet>]
member this.myLabel with get() = label
member this.myLabel with set(v) = label < - v
[<Outlet>]
member this.myButton with get() = button
member this.myButton with set(v) = button < - v
[<Action("OnButtonPress")>]
member this.OnButtonPush () =
clickCount < - clickCount + 1
sprintf "Pressed %d times" clickCount
|> this.myLabel.SetText
override this.Awake (context) =
System.Console.WriteLine("Hello F#")
this.myLabel.SetText("F# |> I ♡")
[/code]
And that’s really all there is to putting F# on your wrist!
[video width="1644" height="1172" mp4="/uploads/2015/01/WatchKitF.mp4"][/video]