avplayer не останавливается при нажатии на кнопку паузы, если экран заблокирован
Если приложение воспроизводит звук, и экран телефона заблокирован, экран управления отображается, как показано ниже. Я не могу предпринимать какие-либо действия на avplayer
В моем приложении я реализовал:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
MPRemoteCommandCenter *rcc = [MPRemoteCommandCenter sharedCommandCenter];
[[rcc skipForwardCommand] setEnabled:NO];
[[rcc skipBackwardCommand] setEnabled:NO];
[[rcc nextTrackCommand] setEnabled:NO];
[[rcc previousTrackCommand] setEnabled:NO];
[[rcc skipForwardCommand] setEnabled:NO];
[[rcc skipBackwardCommand] setEnabled:NO];
rcc.playCommand.enabled = YES;
rcc.pauseCommand.enabled = YES;
[[MPRemoteCommandCenter sharedCommandCenter].playCommand addTarget:self action:@selector(play)];
[[MPRemoteCommandCenter sharedCommandCenter].pauseCommand addTarget:self action:@selector(pause)];
}
- (void) play {
[[MyVideoController instance] play];
}
- (void) pause {
[[MyVideoController instance] pause];
}
Класс MyVideoController состоит из:
- (void) pause {
[self.avPlayer pause];
}
- (void) play {
[self.avPlayer play];
}
Даже если эти методы запущены (добавлены точки останова для проверки), никакие действия с avplayer не предпринимаются. Несмотря ни на что, avplayer не останавливается.
Есть ли способ приостановить avplayer?
РЕДАКТИРОВАТЬ 1: Добавление полного кода
В моем AppDelegate:
- (void) remoteControlReceivedWithEvent: (UIEvent *) event {
[[ZVideoPlayerController instance] eventReceived:event];
if (event.type == UIEventTypeRemoteControl) {
switch (event.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause: {
break;
}
case UIEventSubtypeRemoteControlPlay: {
[[ZVideoPlayerController instance] play];
break;
}
case UIEventSubtypeRemoteControlPause: {
[[ZVideoPlayerController instance] pause];
break;
}
default:
break;
}
}
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
}
Я ПРИНИМАЮ СОБЫТИЯ, НО АУДИО НЕ ОСТАНАВЛИВАЕТСЯ ПРИ МЕТОДЕ ВЫЗОВА ОСТАНОВКИ НА AVPLAYER.
EDIT 2: объявление экземпляра в классе PlayerController
+ (instancetype)instance {
static id instance = nil;
if (instance == nil)
{
static dispatch_once_t onceToken = 0;
dispatch_once(&onceToken, ^(void) {
NSAssert(instance == nil, @"Singleton instance is already allocated.");
instance = [[super allocWithZone:NULL] init];
});
}
return instance;
}
инициализация AVPlayer
AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:url options:nil];
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:avAsset];
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
NSError *activationError = nil;
BOOL success = [[AVAudioSession sharedInstance] setActive: YES error: &activationError];
NSMutableDictionary *songInfo = [[NSMutableDictionary alloc] init];
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage: [UIImage imageNamed:@"Audio_Thumbnail_Play"]];
[songInfo setObject:title forKey:MPMediaItemPropertyTitle];
[songInfo setObject:@"100" forKey:MPMediaItemPropertyPlaybackDuration];
[songInfo setObject:albumArt forKey:MPMediaItemPropertyArtwork];
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo];
self.avPlayer = [AVPlayer playerWithPlayerItem:playerItem];
self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
3 ответа
Я нашел решение проблемы. Поскольку я получал нулевое значение avPlayer, я использовал свой класс PageViewController, чтобы получить экземпляр PlayerController. Затем я использовал экземпляр этого playerController для воспроизведения и приостановки моего avplayer, потому что этот экземпляр содержит ссылку на avPlayer.
- (PlayerController *)getVideoController {
NSArray *controllers = [UtiliyClass getNavigationController].viewControllers;
PageViewController *pageController = nil;
for (UIViewController *cont in controllers) {
if ([cont isKindOfClass:[PageViewController class]]) {
pageController = (PageViewController *)cont;
break;
}
}
if (pageController == nil) {
return nil;
}
NSArray *objectsController =pageController.pageController.viewControllers;
PlayerController *videoPlayerController = nil;
for (UIViewController *item in objectsController) {
if ([item isKindOfClass:[PlayerController class]]) {
videoPlayerController = (PlayerController *)item;
break;
}
}
return videoPlayerController;
}
- (void) pause {
PlayerController *controller = [self getVideoController];
[controller.avPlayer pause];
}
- (void) play {
PlayerController *controller = [self getVideoController];
[controller.avPlayer play];
}
Вам необходимо зарегистрироваться для удаленного уведомления, чтобы обновить состояние игрока, когда приложение заблокировано. Для этого выполните следующие действия:
Добавьте это в ваш AppDelegate, в идеале в applicationDidEnterBackground:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
И это в приложении DidBecomeActive:
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
Получите удаленные уведомления, добавив это в AppDelagate. Это будет слушать все действия, когда телефон заблокирован.
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
if (event.type == UIEventTypeRemoteControl){
// Call method of your player where you want to make change (Pause , Paly),
// I am calling a shared view for example, Its up to your logic how you want to deal it
[[AudioPlayerView sharedPlayerView] remoteControlReceivedWithEvent:event];
}
}
И в этом получить желаемое событие и обновить состояние соответственно
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
if (event.type == UIEventTypeRemoteControl){
switch (event.subtype){
case UIEventSubtypeRemoteControlPlay:
[[MyVideoController instance] play];
break;
case UIEventSubtypeRemoteControlPause:
[[MyVideoController instance] pause];
break;
case UIEventSubtypeRemoteControlTogglePlayPause:
// Check if state is playing , call pause else call play
break;
}
default:
break;
}
}
}
В iOS 7.1 и более поздних версиях используйте общий объект MPRemoteCommandCenter для регистрации событий удаленного управления. Вам не нужно вызывать этот метод при использовании общего объекта командного центра. Этот метод запускает доставку событий дистанционного управления, используя цепочку респондента. События дистанционного управления исходят из команд, выпущенных наушниками и внешними аксессуарами, которые предназначены для управления мультимедиа, представляемого приложением. Чтобы остановить прием событий удаленного управления, вы должны вызвать endReceivingRemoteControlEvents().
Добавьте этот следующий код в didfinishlunching для init аудио сезона и получите событие дистанционного управления:
// Initialize the AVAudioSession here.
if (![[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&myErr]) {
// Handle the error here.
NSLog(@"Audio Session error %@, %@", myErr, [myErr userInfo]);
}
else{
// Since there were no errors initializing the session, we'll allow begin receiving remote control events
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
для получения commadn используйте этот код:
- (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent {
if (receivedEvent.type == UIEventTypeRemoteControl) {
switch (receivedEvent.subtype) {
case UIEventSubtypeRemoteControlPreviousTrack:
break;
case UIEventSubtypeRemoteControlNextTrack:
break;
case UIEventSubtypeRemoteControlPlay:
[[MyVideoController instance] play];
break;
case UIEventSubtypeRemoteControlPause:
[[MyVideoController instance] pause];
break;
default:
break;
}
}
}