Discovering your FireTV and controlling the built-in media player is now easy and reactive
The Amazon Fling SDK lacks a ready to use view controller for discovering FireTVs and controlling the built-in receiver app (media player). That's why I created FireTVKit. It offers a themable view controller for discovering FireTVs in your local network. All the necessary magic happens under the hood. In addition the FireTVKit brings a themable view controller for controlling the built-in media player of a FireTV. Even there all the magic happens under the hood. Thanks to the protocol oriented approach you can easily create your own discovery and player view. If you want to be completely free just use the FireTVManager to do the discovery and get the FireTVs. Then show the FireTVs to your users the way you want it.
The implementation of the FireTVPlayer
and the FireTVSelection
follows the VIPER
architecture pattern. Make yourself comfortable with VIPER
first if you want to implement a custom view.
Feature | |
---|---|
๐ | Themable view controller for FireTV discovery and selection (customize no devices text) |
๐ฎ | Themable view controller for controlling the built-in media player of a FireTV |
๐ถ | FireTVManager to do the discovery and get the list of available FireTVs |
๐ก | Built-in wifi connection validation (customize alert title and message) |
โ | Unit tested |
๐ฝ | Extendable API |
๐ | Written in Swift |
1. FireTV Player Selection with Dark Theme
2. FireTV Player Selection in no devices state
3. FireTV Player Selection in no wifi state
4. FireTV Player with Dark Theme
5. FireTV Player with Light Theme
To run the example project, clone the repo, and run pod install
from the Example directory first.
- Create and present a
FireTVSelectionViewController
import AmazonFling
import FireTVKit
import UIKit
final class ViewController: UIViewController {
private lazy var SAMPLE_VIDEO_METADATA: Metadata = {
var metadata = Metadata(type: .video)
metadata.title = "Testvideo"
metadata.description = "A video for test purposes"
metadata.noreplay = true
return metadata
}()
private let SAMPLE_VIDEO_URL = "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
private lazy var SAMPLE_VIDEO: URL? = {
guard let url = URL(string: SAMPLE_VIDEO_URL) else {
return nil
}
return url
}()
private var selectedPlayer: RemoteMediaPlayer?
override func viewDidLoad() {
super.viewDidLoad()
guard let url = SAMPLE_VIDEO else {
return
}
let media = FireTVMedia(metadata: SAMPLE_VIDEO_METADATA, url: url)
let theme = FireTVSelectionDarkTheme()
let playerId = "amzn.thin.pl"
let fireTVSelectionVC = try FireTVSelectionWireframe.makeViewController(theme: theme, playerId: playerId, media: media, delegate: self)
present(fireTVSelectionVC, animated: true)
}
}
extension ViewController: FireTVSelectionDelegateProtocol {
func didSelectPlayer(_ fireTVSelectionViewController: FireTVSelectionViewController, player: RemoteMediaPlayer) {
fireTVSelectionViewController.dismiss(animated: true, completion: nil)
selectedPlayer = player
}
func didPressCloseButton(_ fireTVSelectionViewController: FireTVSelectionViewController) {
fireTVSelectionViewController.dismiss(animated: true, completion: nil)
}
}
- Create and present a
FireTVPlayerViewController
import AmazonFling
import FireTVKit
import UIKit
final class ViewController: UIViewController {
private var selectedPlayer: RemoteMediaPlayer?
override func viewDidLoad() {
super.viewDidLoad()
guard let selectedPlayer = selectedPlayer else {
return
}
let theme = FireTVPlayerDarkTheme()
let fireTVPlayerVC = try FireTVPlayerWireframe.makeViewController(forPlayer: player, theme: theme, delegate: self)
present(fireTVPlayerVC, animated: true)
}
}
extension ViewController: FireTVPlayerDelegateProtocol {
func didPressCloseButton(_ fireTVPlayerViewController: FireTVPlayerViewController) {
fireTVPlayerViewController.dismiss(animated: true, completion: nil)
}
}
In the following code example you will see how to discover and get the available FireTVs using a FireTVManager
instance. You can control the built-in media player of a FireTV using a PlayerService
instance.
import AmazonFling
import FireTVKit
import RxSwift
import UIKit
final class FireTVManagerExampleViewController: UIViewController {
private var fireTVManager: FireTVManager?
private var disposeBag: DisposeBag?
@IBOutlet private weak var firstPlayerLabel: UILabel!
deinit {
print("FireTVManagerExampleViewController deinit")
}
override func viewDidLoad() {
super.viewDidLoad()
let disposeBag = DisposeBag()
self.disposeBag = disposeBag
do {
fireTVManager = try FireTVManager()
try fireTVManager?.startDiscovery(forPlayerID: "amzn.thin.pl")
fireTVManager?.devicesObservable
.subscribe(onNext: { [weak self] player in
if !player.isEmpty {
self?.firstPlayerLabel?.text = player.first?.name()
} else {
self?.firstPlayerLabel.text = "No player found"
}
}, onError: { error in
print(error)
}).disposed(by: disposeBag)
} catch {
print(error)
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
fireTVManager?.stopDiscovery()
}
@IBAction private func didPressCloseButton(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}
}
Before you start creating your own selection or player view make yourself familiar with the VIPER
architecture pattern. This article is a good starting point.
- You can use the
FireTVSelectionViewProtocol
to create your own view for the fire tv selection. - Use the
FireTVPlayerViewProtocol
to create your custom player view. - With the
FireTVSelectionThemeProtocol
and theFireTVPlayerThemeProtocol
you can build custom themes for the themable selection and player view controller.
To enable logging store a boolean value using the key FireTVKitUserDefaultsKeys.fireTVKitLogging.rawValue
in the UserDefaults
.
If you want to log only a specific event store a LogEvent
enum case as raw value using the key FireTVKitUserDefaultsKeys.fireTVKitLogEvent.rawValue
in the UserDefaults
.
- Currently there is only a reactive implementation. That's why you need
RxSwift
. - Deployment target of your App is >= iOS 9.0 .
- At the moment Bitcode is not supported. I hope that I will make progress in the future.
- To get rid off the cocoapods warning
Transitive dependencies
use the following in yourPodfile
(origin: theAmazonFling
dependency contains a static framework):
pre_install do |installer|
# workaround for https://github.com/CocoaPods/CocoaPods/issues/3289
Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_static_framework_transitive_dependencies) {}
end
FireTVKit is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod 'FireTVKit'
Christian Elies, chris.elies13@gmail.com
FireTVKit is available under the MIT license. See the LICENSE file for more info.