Exploring watchOS: Using WKInterfaceInlineMovie in SwiftUI and WatchKit

I’m working on a project where I’ve to loop and autoplay a video every-time the WKInterfaceController is shown on the watch screen.

To accomplish this, I usedWKInterfaceInlineMovie. It is an interface element that displays a video’s poster image and supports inline playing of the video.

SwiftUI

I initially wrote this article for WatchKit, but my friend asked for an example in SwiftUI, so here’s a small one.

To use a WatchKit component in SwiftUI, we go back to the bridge that is WKInterfaceObjectRepresentable. This protocol requires us to make an interface object and update it.

From the documentation, we make an object by initialising a WKInterfaceInlineMovie. For our requirement, we loop the video, set the URL for it, and play it from the beginning in the update method.

And that’s it! You can use this view by providing it with the URL. Here’s the full sample code for you to go through.

import SwiftUI

struct ContentView: View {
    let path = Bundle.main.path(forResource: "SampleVideo", ofType: "mp4")

    var body: some View {
        if let path = path {
            MovieView(movieURL: URL(fileURLWithPath: path))
        }
    }
}

struct MovieView: WKInterfaceObjectRepresentable {
    var movieURL: URL

    func makeWKInterfaceObject(context: Context) -> WKInterfaceInlineMovie {
        .init()
    }

    func updateWKInterfaceObject(_ movie: WKInterfaceInlineMovie, context: Context) {
        movie.setLoops(true)
        movie.setMovieURL(movieURL)
        movie.playFromBeginning()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

WatchKit

For a direct WatchKit implementation, here are the following steps:

  • Create and connect an IBOutlet for the WKInterfaceInlineMovie object in your Storyboard to your interface controller,
  • Use the awake(withContext:) method to set the video URL,
  • Set loops to true using the setLoops(:) method and play it from the beginning.
@IBOutlet weak var video: WKInterfaceInlineMovie!

This approach worked for the first time it opened the screen, but would not work afterwards.

I added it in willActivate() but it still was not working. I realised that this method was not the correct place to set/play the movie after reading the documentation for it.

The system calls this method when it is getting ready to display your interface controller. Use this method to perform last minute tasks required to ensure your content is up to date. Do not use this method to perform the initial setup of your interface. Your interface should be mostly initialised and ready to use by the time this method is called.

The best place to set the movie ended up in didAppear(). From the documentation,

WatchKit calls this method shortly after the interface controller’s contents appear onscreen. Use this method to configure animations or other interface-related tasks.
override func didAppear() {
    video.setAutoplays(true)
    video.setMovieURL(movieURL)
    video.playFromBeginning()
}

And voila, the video plays every single time the view appears!