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
AVPlayer
instance in the AppDelegate.swift or SceneDelegate.swift file. -
Enable the
enableBackgroundPlayback
property of theFlowplayerViewAPI
protocol.
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
MyControllerView
class that's a subclass ofUIViewController
. Within this new class, leverage theFlowplayerView
class to create aflowplayerView
instance and enable theenableBackgroundPlayback
property. We can use thisflowplayerView
instance 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
MyControllerView
subclass in the AppDelegate.swift file, enabling playback in the background or foreground. You can similarly handle the sameMyControllerView
subclass 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)")
}