You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何根据后端标识限制AVPlayer快进快退并获取视频完成时间

Hey there! Let's walk through how to implement both of your requirements for your AVPlayer-based app. I'll tie everything to your existing AVPlayerViewController setup so it fits right in.

1. Restricting Fast-Forward/Rewind for Specific Videos

First, you'll use the flag from your backend to toggle seek functionality. Here's a reliable approach that gives you full control:

Step 1: Track the Restriction Flag

Add properties to your view controller to track if seeking is allowed, plus another to keep the last valid playback time (to block unwanted seeks):

@property (nonatomic, assign) BOOL allowsSeek;
@property (nonatomic, assign) CMTime lastValidPlaybackTime;

Step 2: Configure Controls Based on the Flag

When you receive video data from your backend, use the restriction flag to set up the player:

// Assume `isSeekRestricted` is the boolean flag from your backend response
self.allowsSeek = !isSeekRestricted;

if (!self.allowsSeek) {
    // Hide system controls to disable the default progress bar
    self.videoPlayerViewController.showsPlaybackControls = NO;
    
    // Add a custom play/pause button (adjust frame and styling as needed)
    UIButton *playPauseBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
    playPauseBtn.center = self.videoPlayerViewController.view.center;
    playPauseBtn.tag = 100; // Use a tag to reference it later
    [playPauseBtn setImage:[UIImage systemImageNamed:@"play.fill"] forState:UIControlStateNormal];
    [playPauseBtn setImage:[UIImage systemImageNamed:@"pause.fill"] forState:UIControlStateSelected];
    [playPauseBtn addTarget:self action:@selector(togglePlayPause:) forControlEvents:UIControlEventTouchUpInside];
    [self.videoPlayerViewController.view addSubview:playPauseBtn];
    
    // Listen to playback status to update the button state
    [self.videoPlayerViewController.player addObserver:self forKeyPath:@"timeControlStatus" options:NSKeyValueObservingOptionNew context:nil];
    
    // Track initial playback time to block unwanted seeks
    self.lastValidPlaybackTime = self.videoPlayerViewController.player.currentItem.currentTime;
    [self.videoPlayerViewController.player.currentItem addObserver:self forKeyPath:@"currentTime" options:NSKeyValueObservingOptionNew context:nil];
} else {
    // Re-enable system controls for unrestricted videos
    self.videoPlayerViewController.showsPlaybackControls = YES;
    
    // Clean up observers if they were added previously
    [self.videoPlayerViewController.player removeObserver:self forKeyPath:@"timeControlStatus"];
    if (self.videoPlayerViewController.player.currentItem) {
        [self.videoPlayerViewController.player.currentItem removeObserver:self forKeyPath:@"currentTime"];
    }
}

Step 3: Handle KVO Observations and Play/Pause

Implement the observer method to enforce the seek restriction and update the play/pause button:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"timeControlStatus"]) {
        // Update play/pause button based on current playback state
        AVPlayerTimeControlStatus status = [change[NSKeyValueChangeNewKey] integerValue];
        UIButton *playPauseBtn = [self.videoPlayerViewController.view viewWithTag:100];
        playPauseBtn.selected = (status == AVPlayerTimeControlStatusPlaying);
    } else if ([keyPath isEqualToString:@"currentTime"]) {
        if (!self.allowsSeek) {
            CMTime newTime = [change[NSKeyValueChangeNewKey] CMTimeValue];
            // If time changed unexpectedly (user tried to seek), reset to last valid time
            if (CMTimeCompare(newTime, self.lastValidPlaybackTime) != 0) {
                [self.videoPlayerViewController.player seekToTime:self.lastValidPlaybackTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
            } else {
                // Update valid time as video plays normally
                self.lastValidPlaybackTime = newTime;
            }
        }
    }
}

- (void)togglePlayPause:(UIButton *)sender {
    sender.selected = !sender.selected;
    if (sender.selected) {
        [self.videoPlayerViewController.player play];
    } else {
        [self.videoPlayerViewController.player pause];
    }
}
2. Detect When a Video Finishes Playing

To get notified when a video completes, use AVPlayer's built-in notification system:

Step 1: Add a Notification Observer

When setting up your AVPlayerItem, register for the finish notification:

// Assume `videoURLString` is the URL from your backend
NSURL *videoURL = [NSURL URLWithString:videoURLString];
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:videoURL];

// Register for the finish notification
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(videoDidFinishPlaying:)
                                             name:AVPlayerItemDidPlayToEndTimeNotification
                                           object:playerItem];

// Assign the item to your player
self.videoPlayerViewController.player = [AVPlayer playerWithPlayerItem:playerItem];

Step 2: Handle the Finish Event

Implement the selector to capture the finish time and handle post-playback actions:

- (void)videoDidFinishPlaying:(NSNotification *)notification {
    AVPlayerItem *finishedItem = notification.object;
    
    // Get current system time as the finish time
    NSDate *finishTime = [NSDate date];
    NSLog(@"Video completed at %@", finishTime);
    
    // Add your logic here: e.g., report to backend, play next video, etc.
    
    // Clean up observer to avoid memory leaks
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:finishedItem];
}

Step 3: Clean Up Observers

Don't forget to remove all observers in your view controller's dealloc method to prevent memory leaks:

- (void)dealloc {
    [self.videoPlayerViewController.player removeObserver:self forKeyPath:@"timeControlStatus"];
    if (self.videoPlayerViewController.player.currentItem) {
        [self.videoPlayerViewController.player.currentItem removeObserver:self forKeyPath:@"currentTime"];
        [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:self.videoPlayerViewController.player.currentItem];
    }
}

内容的提问来源于stack exchange,提问作者Keshav.K

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 02:33:00