This is probably easy, but I really can't find or understand how to get notified when a view goes to background and comes back using the SceneDelegate
. If I have a viewController
that goes into background by going back to main menu or something similar, how do I detect that via sceneWillResignActive
?
I found here that one could do something like:
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(appMovedToBackground), name: UIApplication.willResignActiveNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(appBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
More specifically I have this ViewController.swift:
import Foundation
import UIKit
import AVKit
class IntroViewController : UIViewController {
@IBOutlet weak var videoView: UIView!
@IBOutlet weak var introLabel: UILabel!
var player: AVPlayer?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
playVideo()
}
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(self)
if let player = player {
player.pause()
}
player = nil
}
private func playVideo() {
if player != nil {
player!.play()
} else {
guard let path = Bundle.main.path(forResource: "intro_video", ofType:"mp4") else {
debugPrint("intro.MP4 not found")
return
}
player = AVPlayer(url: URL(fileURLWithPath: path))
player!.actionAtItemEnd = .none
let playerFrame = CGRect(x: 0, y: 0, width: videoView.frame.width, height: videoView.frame.height)
NotificationCenter.default.addObserver(self,
selector: #selector(playerItemDidReachEnd(notification:)),
name: .AVPlayerItemDidPlayToEndTime,
object: player!.currentItem)
let playerController = AVPlayerViewController()
playerController.player = player
playerController.videoGravity = .resizeAspectFill
playerController.view.frame = playerFrame
playerController.showsPlaybackControls = false
addChild(playerController)
videoView.addSubview(playerController.view)
playerController.didMove(toParent: self)
player!.play()
player!.rate = 1.3
}
}
@objc func playerItemDidReachEnd(notification: Notification) {
let mainViewController = self.storyboard!.instantiateViewController(withIdentifier: "main_view_controller") as! MainViewController
player!.pause()
present(mainViewController, animated:true, completion:nil)
}
@IBAction func skipVideo(_ sender: Any) {
if player != nil {
player?.pause()
player = nil
}
let mainViewController = self.storyboard!.instantiateViewController(withIdentifier: "main_view_controller") as! MainViewController
present(mainViewController, animated:true, completion:nil)
}
}
Then we have the SceneDelegate.swift
:
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
}
I want to be able to pause and restart the player when the user leaves the app. For starting the player something should somehow be called from sceneDidBecomeActive
as I understand it. What I don't understand is how to in sceneDidBecomeActive
that the viewcontroller that should be presented is the one I want.
sceneDidBecomeActive
is (of course) called each time I go back to the app, no matter from which ViewController
I left it.
In the link which refers to the old way, there seems to be some notification procedure to which you can assign a lambda. If I have a reference to the ViewController
in SceneDelegate
, I must somehow check and see if that is the one that should become active?
I don't find it supertrivial to follow the tutorials I have found about SceneDelegates
. They mostly talk about differences between Appdelegate and what you could do, but never how to actually do it.