Skip to content

Commit bdeb66f

Browse files
committed
Fix video looping: replace AVPlayerLooper with seek-based approach and downgrade to AVPlayer
1 parent dc64673 commit bdeb66f

3 files changed

Lines changed: 24 additions & 16 deletions

File tree

Sources.UIBuilder/UIBuilder/Logic/AdaptyVideoViewModel.swift

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ class AdaptyUIVideoPlayerManager: NSObject, ObservableObject {
3939
}
4040

4141
@Published var playerState: PlayerState = .invalid
42-
@Published var player: AVQueuePlayer?
42+
@Published var player: AVPlayer?
4343

4444
private let onStateUpdated: (PlayerState) -> Void
4545

46-
private var playerLooper: AVPlayerLooper?
4746
private var playerStatusObservation: NSKeyValueObservation?
47+
private nonisolated(unsafe) var loopObserver: (any NSObjectProtocol)?
4848

4949
init(
5050
video: VC.VideoData,
@@ -54,20 +54,25 @@ class AdaptyUIVideoPlayerManager: NSObject, ObservableObject {
5454
) {
5555
let video = video.resolve(with: assetsResolver)
5656
player = video.player
57-
// preview image : video.image
58-
if loop {
59-
playerLooper = AVPlayerLooper(player: video.player, templateItem: video.item)
60-
} else {
61-
playerLooper = nil
62-
}
63-
6457
self.onStateUpdated = onStateUpdated
6558

6659
super.init()
6760

61+
if loop {
62+
video.player.actionAtItemEnd = .none
63+
loopObserver = NotificationCenter.default.addObserver(
64+
forName: .AVPlayerItemDidPlayToEndTime,
65+
object: video.item,
66+
queue: .main
67+
) { [weak self] _ in
68+
self?.player?.seek(to: .zero)
69+
self?.player?.play()
70+
}
71+
}
72+
6873
playerStatusObservation = video.item.observe(
6974
\.status,
70-
options: [.old, .new, .initial, .prior],
75+
options: [.new, .initial],
7176
changeHandler: { [weak self] item, _ in
7277
DispatchQueue.main.async { [weak self] in
7378
self?.playerStatusDidChange(item.status, item: item)
@@ -103,6 +108,9 @@ class AdaptyUIVideoPlayerManager: NSObject, ObservableObject {
103108
deinit {
104109
playerStatusObservation?.invalidate()
105110
playerStatusObservation = nil
111+
if let loopObserver {
112+
NotificationCenter.default.removeObserver(loopObserver)
113+
}
106114
}
107115
}
108116

Sources.UIBuilder/UIBuilder/Rendering/Elements/AdaptyUI+AssetsResolver.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import SwiftUI
1313
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, visionOS 1.0, *)
1414
extension VC.VideoData {
1515
struct Resolved {
16-
let player: AVQueuePlayer
16+
let player: AVPlayer
1717
let item: AVPlayerItem
1818
let image: VC.ImageData.Resolved?
1919
}
@@ -27,7 +27,7 @@ extension VC.VideoData {
2727

2828
private var resolved: Resolved {
2929
let item = AVPlayerItem(url: url)
30-
let player = AVQueuePlayer(items: [item])
30+
let player = AVPlayer(playerItem: item)
3131
player.isMuted = true
3232

3333
return Resolved(
@@ -184,9 +184,9 @@ private extension AdaptyUICustomVideoAsset {
184184
case let .file(url, preview),
185185
let .remote(url, preview):
186186
let playerItem = AVPlayerItem(url: url)
187-
let queuePlayer = AVQueuePlayer(items: [playerItem])
188-
queuePlayer.isMuted = true
189-
return .init(player: queuePlayer, item: playerItem, image: preview.flatMap { $0.resolved })
187+
let player = AVPlayer(playerItem: playerItem)
188+
player.isMuted = true
189+
return .init(player: player, item: playerItem, image: preview.flatMap { $0.resolved })
190190
case let .player(item, player, preview):
191191
return .init(player: player, item: item, image: preview.flatMap { $0.resolved })
192192
}

Sources.UIBuilder/UIBuilder/Rendering/Elements/AdaptyUIVideoPlayerView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ struct AdaptyUIVideoPlayerView: UIViewControllerRepresentable {
5656
#else
5757
playerStatusObservation = playerViewController.observe(
5858
\.isReadyForDisplay,
59-
options: [.old, .new, .initial, .prior],
59+
options: [.new, .initial],
6060
changeHandler: { playerVC, _ in
6161
DispatchQueue.main.async {
6262
if playerVC.isReadyForDisplay {

0 commit comments

Comments
 (0)