当视图控制器进入后台时收到通知

Posted

技术标签:

【中文标题】当视图控制器进入后台时收到通知【英文标题】:Getting notification when viewcontroller goes to background 【发布时间】:2021-10-21 05:25:21 【问题描述】:

这可能很容易,但我真的不知道如何在视图进入后台并使用SceneDelegate 返回时获得通知。如果我有一个 viewController 通过返回主菜单或类似的东西进入后台,我如何通过 sceneWillResignActive 检测到它?

我发现 here 可以这样做:

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)

更具体地说,我有这个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)
    

然后我们有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.
    



我希望能够在用户离开应用时暂停并重新启动播放器。据我了解,为了启动播放器,应该以某种方式从sceneDidBecomeActive 调用某些东西。我不明白的是如何在sceneDidBecomeActive 中表明应该呈现的视图控制器是我想要的。

sceneDidBecomeActive(当然)每次我回到应用程序时都会被调用,无论我是从哪个ViewController 离开的。

在引用旧方法的链接中,似乎有一些通知程序可以分配一个 lambda。如果我在SceneDelegate 中有对ViewController 的引用,我必须以某种方式检查它是否应该变为活动状态?

我不觉得遵循我找到的关于SceneDelegates 的教程是一件非常简单的事情。他们主要谈论 Appdelegate 之间的差异以及您可以做什么,但从不谈论如何实际去做。

【问题讨论】:

您能否定义一下“进入后台”对您意味着什么?当用户点击 iPhone 上的主页按钮或打开其他应用程序并返回时,应用程序作为一个整体进入后台并恢复,这也是 AppDelegateSceneDelegate 通知的内容。但是您所指定的问题似乎更像viewWillDisappearviewWillAppear,您可以查看ViewController 生命周期以获取更多详细信息***.com/questions/5562938/… 【参考方案1】:

场景委托中的 resignActive、enterBackground 与应用委托中的相同。您可以做的是在 sceneDelegate 中引用您的视图控制器,并在其中一个场景委托方法运行时调用视图控制器的某些方法(您可以定义视图控制器将实现的协议)。

【讨论】:

我如何知道哪个视图控制器将是活动的? sceneDidBecomeActive 总是在我回去的时候被调用。我有不止一个ViewController,如果我要回到那个,我只会调用特定的方法。 你可以在post找到你想要的东西

以上是关于当视图控制器进入后台时收到通知的主要内容,如果未能解决你的问题,请参考以下文章

收到通知后,我如何才能在应用程序图标点击时获得有效负载?

接收远程推送通知时打开视图控制器

当视图控制器弹出或推入导航控制器堆栈时如何获得通知

如何在IOS中处理多个远程通知点击

如何在后台控制 FCM 消息通知 [重复]

当点击 FCM 推送通知时,如何在选项卡栏中打开特定的视图控制器?