Background playback for iOS
With the background playback feature for iOS, you can adapt the player to play media content while other applications are in the foreground. You need to configure your iOS application to enable this background video playback behavior.
You must disconnect the main AVPlayer instance from the current context and store it in your AppDelegate.swift or SceneDelegate.swift file. When you set the FlowplayerView.avPlayer property using the FlowplayerView class, the player disables certain UI features and other processes that aren't needed in the background.
For information related to listening to events, managing media playback, and handling errors, see the following pages:
Enable background playback
This section describes the general process to enable background playback and provides an example of how to accomplish this task using the AppDelegate.swift or SceneDelegate.swift file. By default, the player's enableBackgroundPlayback property is set to false and the player pauses when receding into the background. For more, see the FlowplayerViewAPI properties.
General process
The general process to enable background video playback in your iOS application is outlined in the following steps. For a better understanding, see our example.
- Add a Background Modes capability for your iOS application.
- Specify the Background Modes your application requires. Select Audio, AirPlay, and Picture in Picture .
-
Connect (foreground playback) or disconnect (background playback) the
AVPlayerinstance in the AppDelegate.swift or SceneDelegate.swift file. -
Enable the
enableBackgroundPlaybackproperty of theFlowplayerViewAPIprotocol.
info
To learn more about enabling certain capabilities to perform background operations, see Configure background modes.
View an example
In this example, we set up a UIViewController subclass, then demonstrate how to manage background playback in the AppDelegate.swift or SceneDelegate.swift files. Pick the method that best suits your iOS application.
Warning
Never implement both strategies simultaneously because this will break the player.
-
Start by creating a
MyControllerViewclass that's a subclass ofUIViewController. Within this new class, leverage theFlowplayerViewclass to create aflowplayerViewinstance and enable theenableBackgroundPlaybackproperty. We can use thisflowplayerViewinstance later in the AppDelegate.swift and SceneDelegate.swift files.class MyControllerView: UIViewController { // Declare view and instance of FlowplayerView class public let flowplayerView = FlowplayerView() // Handle view controller's lifecycle override func viewDidLoad() { super.viewDidLoad() view.addSubview(flowplayerView) let someMedia = MediaExternal( url: URL(string: "https://link.to.a.media.file")! ) // Enable background playback flowplayerView.enableBackgroundPlayback = true flowplayerView.load(external: someMedia) } } -
Use the same
MyControllerViewsubclass in the AppDelegate.swift file, enabling playback in the background or foreground. You can similarly handle the sameMyControllerViewsubclass in the SceneDelegate.swift file. Switch between the tabs in the following examples to see each implementation.AppDelegate.swiftSceneDelegate.swift// AppDelegate.swift private var storedPlayerInstance: AVPlayer? func applicationDidEnterBackground(_ application: UIApplication) { let topController = window?.rootViewController as? MyControllerView savedPlayerInstance = topController?.flowplayerView.avPlayer // Disconnect main AVPlayer instance and // Continue playback in background topController?.videoController.avPlayer = nil } func applicationWillEnterForeground(_ application: UIApplication) { guard savedPlayerInstance != nil else { return } // Continue playback in foreground let topController = window?.rootViewController as? MyControllerView // Reconnect main AVPlayer instance topController?.flowplayerView.avPlayer = self.savedPlayerInstance self.savedPlayerInstance = nil }// SceneDelegate.swift var window: UIWindow? var storedPlayer: AVPlayer? func sceneWillEnterForeground(_: UIScene) { guard let navController = window?.rootViewController as? MyControllerView, let flowplayer = viewController.flowplayer else { return } // Continue playback in foreground flowplayer.avPlayer = storedPlayer storedPlayer = nil } func sceneDidEnterBackground(_: UIScene) { guard let navController = window?.rootViewController as? MyControllerView, let flowplayer = viewController.flowplayer else { return } storedPlayer = flowplayer.avPlayer // Continue playback in background flowplayer.avPlayer = nil }
Listen to the background state
By default, the enableBackgroundPlayback property of the player is set to false. This means that when the player moves to the background, it pauses. If it returns to the foreground, it doesn't automatically resume playing your media.
You can modify this behavior and change the video to play when the app containing the player returns to the foreground. To do so, you can observe the background playback state of the player and continue playback.
The following examples capture the background state and use it to resume video playback when the player returns from the background to the foreground. The first tab relies on the FlowplayerDelegate method, while the second tab demonstrates achieving the same goal using notifications.
// Use FlowplayerDelegate to observe playback state change
func player(_ player: FlowplayerAPI, didChangePlaybackState state: PlaybackState) {
print("PlaybackState changed to: \(state)")
// Check if current state is .playing and previous state is .background
let wasInBackground = player.playbackStateList.prefix(2) == [
.playing,
.background
]
// If was in background and transitioning to playing is true,
// and the player is paused, continue playback when returning from the background
if wasInBackground && player.state == .pause {
player.play()
}
}// Declare player variable
var player: FlowplayerAPI?
// Register notification observer and method to be called when notification is received
NotificationCenter.default.addObserver(
self,
selector: #selector(onReceivedState),
name: .flowplayerDidChangePlaybackState,
object: nil
)
// Set up notification selector
// Call onReceivedState method when flowplayerDidChangePlaybackState notification is received
@objc
private func onReceivedState(_ notification: Notification) {
guard let state = notification.object as? PlaybackState else {
return
}
// Check if current state is .playing and previous state is .background
let wasInBackground = player.playbackStateList.prefix(2) == [
.playing,
.background
]
// If was in background and transitioning to playing is true,
// and the player is paused, continue playback when returning from the background
if wasInBackground && player.state == .pause {
player.play()
}
print("myPlayer did change state to: \(state)")
}