播放来自Apple TV Top Shelf的视频

时间:2015-10-16 11:28:59

标签: swift url-scheme tvos apple-tv

我创建了一个简单的AppleTV项目,按类别显示多个视频,浏览和播放视频工作正常。它已经被实现为使用TVML和TVJS的客户端 - 服务器应用程序,因此大多数应用程序逻辑都在Javascript文件中。这些是在动态内容的背景下静态生成的。

然后我在应用程序中添加了一个TopShelf扩展,从API中提取了一些特色视频,这也工作正常,按预期拉入视频。

我遇到的问题是检测并响应用户从顶层架子中选择视频。我创建了一个URL方案exampletvapp://我已经在plist文件中注册了。

我还将displayURL和playURL添加到TVContentItems。选择其中一个视频时,我的应用程序会按预期启动,但实际上并不处理该视频的播放。

在我的AppDelegate文件中,我添加了print语句来打印launchOptions并添加了一个openUrl函数,该函数会被调用,但只有在我关闭应用程序并在应用程序关闭之前快速从顶部架子中选择一些内容时才会记录丢失调试会话。

// AppDelegate
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    print("App Launch: \(launchOptions)")
    window = UIWindow(frame: UIScreen.mainScreen().bounds)

    let appControllerContext = TVApplicationControllerContext()

    guard let javaScriptURL = NSURL(string: AppDelegate.TVBootURL) else {
        fatalError("unable to create NSURL")
    }

    appControllerContext.javaScriptApplicationURL = javaScriptURL
    appControllerContext.launchOptions["BASEURL"] = AppDelegate.TVBaseURL

    if let options = launchOptions {
        for (kind, value) in options {
            if let kindStr = kind as? String {
                appControllerContext.launchOptions[kindStr] = value
            }
        }
    }

    appController = TVApplicationController(context: appControllerContext, window: self.window, delegate: self)

    return true
}

    func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {

        guard let javaScriptURL = NSURL(string: AppDelegate.TVBootURL) else {
            fatalError("unable to create NSURL")
        }

        let appControllerContext = TVApplicationControllerContext()
        appControllerContext.javaScriptApplicationURL = javaScriptURL
        appControllerContext.launchOptions["BASEURL"] = AppDelegate.TVBaseURL


        for (kind, value) in options {
            appControllerContext.launchOptions[kind] = value
        }

        appController = TVApplicationController(context: appControllerContext, window: self.window, delegate: self)

        return true
    }

    func application(application: UIApplication, handleOpenURL url: NSURL) -> Bool {
        print("handle Url called")
    }

使用Javascript:

// Application.js
App.onLaunch = function(options) {
    var javascriptFiles = [
        `${options.BASEURL}js/ResourceLoader.js`,
        `${options.BASEURL}js/Presenter.js`
    ];

    console.log("options", options);

我已经在JS文件中添加了一个console.log来检查选项是否被传递,但它没有记录任何内容。我的意图是创建一个Player对象,其中只有TopShelf中所选视频的播放列表。但由于URL似乎只传递了ID,这意味着我需要发出ajax请求来获取视频信息,即使我已经在TVContentItem中使用了它。

所以我的问题是:我是否应该将topshelf中的视频本地添加到播放列表并播放(使用Swift)或将详细信息传递到javascript端以便播放。如果是javascript有没有办法看到console.log的输出?因为我没有看到任何使得它很难使用的东西。

更新

我对此有了进一步了解,我发现(通过Apple Developer Forums)你可以通过Develop>将Safari连接到Apple TV的模拟器中的JS Context。设备菜单。我已经完成了这个,到目前为止,URL没有通过选项传递给JS。 url被传递给openURL委托函数,该函数需要以某种方式传递给JS,或者我需要本地播放视频。

我目前正在研究通过在displayURL中传递所有必需信息来创建TVContentItem来原生播放视频。我无法看到从openURL方法将此对象传递给JS的方法,除非我创建一个新的上下文和控制器的实例(甚至可能无法工作)

2 个答案:

答案 0 :(得分:2)

我终于让这个本地工作了。我也设法通过将openUrl传递给JS来实现它,但对我来说似乎不太可靠。我稍后会进一步研究,我现在只需要这个工作。

下面的代码创建了一个AVPlayer和AVPlayerViewController并呈现了ViewController,并在完成时将其解散。到目前为止,我还没有发现这种方法存在任何问题,但我仍在测试中。

// AppDelegate.swift
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {

    let urlString = "http:\(url.path!)"
    let url = NSURL(string: urlString)!
    print("opening URL: \(url)")

    let item = AVPlayerItem(URL: url)

    // Need to listen to the end of the player so we can dismiss the AVPlayer
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "playerDidFinishPlaying:", name: AVPlayerItemDidPlayToEndTimeNotification, object: item)

    let player = AVPlayer(playerItem: item)
    player.actionAtItemEnd = AVPlayerActionAtItemEnd.None
    let playerVC = AVPlayerViewController()
    playerVC.player = player

    appController?.navigationController.presentViewController(playerVC, animated: true, completion: nil)
    player.play()

    return true
}

func playerDidFinishPlaying (note: NSNotification) {
    // Dimiss the AVPlayer View Controller from the Navigation Controller
    appController?.navigationController.dismissViewControllerAnimated(true, completion: nil)
}

答案 1 :(得分:0)

我也刚刚在基于TVML的应用程序中添加了Top Shelf扩展程序。

如果您使用Apple的TVML Catalog example作为基础,则以下内容应在AppDelegate中使用,以便将URL引入JavaScript上下文:

func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {

    if url.host == nil { return true }

    let urlString = url.absoluteString

    NSLog(urlString) // Log to XCode

    appController?.evaluateInJavaScriptContext({(evaluation: JSContext) -> Void in

        // Log to JS log (Safari)
        evaluation.evaluateScript("console.log('url string: \(urlString)')")

        // obviously we need to do something more interesting here


        },
        completion: {(Bool) -> Void in }

    )

    return true

}

我的计划是在JavaScript中编写一个处理URL的函数,并将结果传递给我选择的TVML模板。我有一个用于现场演出,一个用于录音,这是我在Top Shelf扩展中展示的两个主要项目。