ATV-Bilibili-demo icon indicating copy to clipboard operation
ATV-Bilibili-demo copied to clipboard

Issue about subclassing AVPlayerViewController

Open Kyle-Ye opened this issue 1 year ago • 8 comments

The current VC inheritance chain is VideoPlayerViewController -> CommonPlayerViewController -> AVPlayerViewController.

But Apple's AVKit documentation states that "The framework doesn’t support subclassing AVPlayerViewController."

But AVKit is written by ObjectiveC, AVPlayerViewController can't marked as final class to stop us from inheriting it.

Some issue I met before(setting AVPlaybackSpeed and not working) may also be related to our usage of inheritance for AVPlayerViewController.

But anyway using subclass of AVPlayerViewController has some risk that it may not work in future OS update. I'd like to suggest we make CommonPlayerViewController a simple class or a subclass of NSObject and add a property var player: AVPlayerViewController to refactor our codebase.

Kyle-Ye avatar Nov 19 '23 03:11 Kyle-Ye

Try with simply putting AVPlayerViewController as a child controller of CommonPlayerViewController (fix/avplayerVC-child 541d204). But the directional key of the remote is not working or not forwarded to AVPlayerViewController. May need more research with the tvOS event chain.

yichengchen avatar Nov 19 '23 09:11 yichengchen

another propose is make CommonPlayerViewController become a simple util to present avplayerVC only. move all danmuView, maskView and related logic to the overlayContentView of the AVPlayerVC.

yichengchen avatar Nov 19 '23 13:11 yichengchen

If we just make CommonPlayerViewController a simple class or a subclass of NSObject and add a property var player: AVPlayerViewController. How to prevent the CommonPlayerViewController deinit immediately after present the AVPlayerViewController. There is not a view hierarchy to keep it. Or just do some hacky work like the overlayContentView holding the CommonPlayerViewController?

yichengchen avatar Nov 19 '23 13:11 yichengchen

If we just make CommonPlayerViewController a simple class or a subclass of NSObject and add a property var player: AVPlayerViewController. How to prevent the CommonPlayerViewController deinit immediately after present the AVPlayerViewController. There is not a view hierarchy to keep it. Or just do some hacky work like the overlayContentView holding the CommonPlayerViewController?

Take VideoDetailViewController/VideoPlayerViewController as an example:

In VideoDetailViewController, we try to present if from a vc. And when direatlyEnterVideo is true and the present is complete, we'll continue to make VideoDetailViewController to present our VideoPlayerViewController

The original code:

func present(from vc: UIViewController, direatlyEnterVideo: Bool = Settings.direatlyEnterVideo) {
    if !direatlyEnterVideo {
        vc.present(self, animated: true)
    } else {
        vc.present(self, animated: false) { [weak self] in
            guard let self else { return }
            let player = VideoPlayerViewController(playInfo: PlayInfo(aid: self.aid, cid: self.cid, epid: self.epid, isBangumi: self.isBangumi))
            self.present(player, animated: true)
        }
    }
}

The new code can be written as follow

  1. In the init method of VideoPlayerViewController/CommonPlayerViewController, we create a AVPlayerViewController and store it as an unowned(not weak) reference.
unowned var player: AVPlayerViewController

Also we somehow make AVPlayerViewController strongly hold our VideoPlayerViewController/CommonPlayerViewController instance.

  1. Then in the caller side, we just present VideoPlayerViewController.player
func present(from vc: UIViewController, direatlyEnterVideo: Bool = Settings.direatlyEnterVideo) {
    if !direatlyEnterVideo {
        vc.present(self, animated: true)
    } else {
        vc.present(self, animated: false) { [weak self] in
            guard let self else { return }
            let controller = VideoPlayerViewController(playInfo: PlayInfo(aid: self.aid, cid: self.cid, epid: self.epid, isBangumi: self.isBangumi))
            self.present(controller.player, animated: true)
        }
    }
}

Kyle-Ye avatar Nov 19 '23 17:11 Kyle-Ye

yep, I am thinking is there is a simply elegant way to make AVPlayerViewController strongly hold our VideoPlayerViewController/CommonPlayerViewController instance without subclassing. Like use the AVPlayerViewController.overlayContentView to hold the controller, but it's a little strange.

yichengchen avatar Nov 20 '23 00:11 yichengchen

After override the preferredFocusEnvironments of the CommonPlayerViewController, the directional key of the remote works. Maybe we can still put the AVPlayerViewController as the child of the CommonPlayerViewController .

yichengchen avatar Nov 20 '23 01:11 yichengchen

After override the preferredFocusEnvironments of the CommonPlayerViewController, the directional key of the remote works. Maybe we can still put the AVPlayerViewController as the subclass of the CommonPlayerViewController .

Typo here? I guess you mean putting AVPlayerViewController as a child controller of CommonPlayerViewController

Kyle-Ye avatar Nov 20 '23 05:11 Kyle-Ye

After override the preferredFocusEnvironments of the CommonPlayerViewController, the directional key of the remote works. Maybe we can still put the AVPlayerViewController as the subclass of the CommonPlayerViewController .

Typo here? I guess you mean putting AVPlayerViewController as a child controller of CommonPlayerViewController

you are right, now putting AVPlayerViewController as a child controller of CommonPlayerViewController works fine

yichengchen avatar Nov 20 '23 06:11 yichengchen