2013-09-24 4 views
24

Я провел много исследований, как в Google, так и в StackOverflow. Все ответы, которые я нашел, не работают в iOS 7. Я начал писать новое приложение в iOS 7 SDK с Xcode 5.iOS 7 SDK не соответствует фону аудио

Все, что я пытаюсь сделать, это воспроизвести аудио в приложении из файла, хранящегося в комплекте приложения (не из музыкальной библиотеки). Я хочу, чтобы звук воспроизводился в фоновом режиме и контролировался, когда экран заблокирован. (в дополнение к Control Center).

Я установил ключ APPNAME-Info.plist, UIBackgroundModes, до аудио. Он не обрабатывает вещи в делегате приложения; все делается внутри ViewController

@interface ViewController : UIViewController <AVAudioPlayerDelegate> 

В viewDidAppear: методе реализация языка я называю супер, а затем следующий код:

// Once the view has loaded then we can register to begin receiving controls and we can become the first responder 
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; 
[self becomeFirstResponder]; 

В viewWillDisappear: методе моей реализации, я следующий код:

// End receiving events 
[[UIApplication sharedApplication] endReceivingRemoteControlEvents]; 
[self resignFirstResponder]; 

Я также внедрил метод canBecomeFirstResponder, который возвращает ДА. Затем я реализовал remoteControlReceivedWithEvent: метод:

- (void)remoteControlReceivedWithEvent:(UIEvent *)event { 
    // If it is a remote control event handle it correctly 
    if (event.type == UIEventTypeRemoteControl) { 
     if (event.subtype == UIEventSubtypeRemoteControlPlay) { 
      [self playPauseAudio:self]; 
     } else if (event.subtype == UIEventSubtypeRemoteControlPause) { 
      [self playPauseAudio:self]; 
     } else if (event.subtype == UIEventSubtypeRemoteControlTogglePlayPause) { 
      [self playPauseAudio:self]; 
     } 
    } 
} 

Смущает меня, что это точно такая же установка работает нормально на прошивке 6. На прошивке 7, не работает. Раньше это было так просто в iOS 6. Что-то принципиально изменилось в iOS 7 SDK. Что мне не хватает?

ответ

16

мне удалось решить эту проблему, и, чтобы сохранить таскание за волосы другой бедной души здесь идет:

Во-первых, убедитесь, что ваш Info.plist правильно перечислены аудио в фоновом режиме.

(Если вы не знаете, что я говорю о том, выберите YOURAPPNAME-Info.plist выберите что. Нажмите ойн знака плюса и добавить новый ключ с именем UIBackgroundModes и расширить его. Добавьте значение с именем audio.)

Вам понадобится ссылка на любой объект воспроизведения, создающий аудио.Так как я только воспроизведение аудио и AVPlayer не пребывающая на фоне аудио, используйте это в заголовке вашего зрения контроллера:

@property (nonatomic, retain) MPMoviePlayerController *audioPlayer; 

В реализации, выполните следующие действия:

[super viewDidAppear:animated]; 

    //Once the view has loaded then we can register to begin recieving controls and we can become the first responder 
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; 
    [self becomeFirstResponder]; 

и

- (void)viewWillDisappear:(BOOL)animated { 
    [super viewWillDisappear:animated]; 

    //End recieving events 
    [[UIApplication sharedApplication] endReceivingRemoteControlEvents]; 
    [self resignFirstResponder]; 

добавить два метода

//Make sure we can recieve remote control events 
- (BOOL)canBecomeFirstResponder { 
    return YES; 
} 

- (void) registerForAudioObjectNotifications { 

    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 

    [notificationCenter addObserver: self 
          selector: @selector (handlePlaybackStateChanged:) 
           name: MixerHostAudioObjectPlaybackStateDidChangeNotification 
          object: audioObject]; 
} 

Теперь все важные код - это позволяет ваше приложение для управления аудио из «центра управления» и с экрана блокировки:

- (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent { 

    if (receivedEvent.type == UIEventTypeRemoteControl) { 

     switch (receivedEvent.subtype) { 

      case UIEventSubtypeRemoteControlTogglePlayPause: 
       [self playOrStop: nil]; 
       break; 

      default: 
       break; 
     } 
    } 
} 

вы можете добавить много много типов типов событий здесь и вызвать любой метод.

Типичные события:

UIEventSubtypeRemoteControlPlay     = 100, //Parent EVENT 

// All below are sub events and you can catch them using switch or If /else. 
    UIEventSubtypeRemoteControlPause    = 101, 
    UIEventSubtypeRemoteControlStop     = 102, 
    UIEventSubtypeRemoteControlTogglePlayPause  = 103, 
    UIEventSubtypeRemoteControlNextTrack   = 104, 
    UIEventSubtypeRemoteControlPreviousTrack  = 105, 
    UIEventSubtypeRemoteControlBeginSeekingBackward = 106, 
    UIEventSubtypeRemoteControlEndSeekingBackward = 107, 
    UIEventSubtypeRemoteControlBeginSeekingForward = 108, 
    UIEventSubtypeRemoteControlEndSeekingForward = 109, 

Для отладки помощью вы можете использовать:

MPMoviePlayerController *mp1= (MPMoviePlayerController *)[notification object]; 
    NSLog(@"Movie State is: %d",[mp1 playbackState]); 

    switch ([mp1 playbackState]) { 
     case 0: 
      NSLog(@"******* video has stopped"); 
      break; 
     case 1: 
      NSLog(@"******* video is playing after being paused or moved."); 
         break; 
     case 2: 
      NSLog(@"******* video is paused"); 
       break; 
     case 3: 
      NSLog(@"******* video was interrupted"); 
      break; 
     case 4: 
      NSLog(@"******* video is seeking forward"); 
        break; 
     case 5: 
      NSLog(@"******* video is seeking Backwards"); 
      break; 
     default: 
      break; 

Вот и все - надеюсь, что это помогает кто-то там! - это отлично работает на iOS 7 и iOS 6 с помощью приложения Storyboard, а также управляет с помощью наушников и всего нового центра управления.

+1

К сожалению, это не работает для меня из центра управления. Это тот же самый код, который я плодотворно использовал на iOS6, но с iOS7 что-то сломалось. На самом деле я также видел, что другие приложения, такие как StereoMood и 8Tracks, имеют одинаковую проблему. – super

+0

Вы тестировали это на iOS 7.0.3, работает для меня без проблем. – codejunkie

+0

@codejunkie: У меня был тот же опыт, что и супер. На iOS 7.0.3 он все тот же. Я выполнил большинство шагов, как вы указали, за исключением того, что мой код ответчика находится в AppDelegate, и у меня нет аудио объекта. Центр управления просто не вызывает remoteControlReceivedWithEvent :. Обратите внимание, что мой код работает во всех случаях до iOS7 и все еще работает для пульта дистанционного управления earbud. См. Мой вопрос здесь: http://stackoverflow.com/questions/19686704/how-to-block-ios-7-control-centre-from-controlling-music-app – kakyo

0

Поскольку я также заинтересован в поиске этого решения, я добавлю дополнительную информацию с моей стороны.

У меня такая же проблема, но документация по Apple не изменилась в отношении управления событиями дистанционного управления.

Я попытался переместить что-то, и произошло что-то интересное.

Первоначально я имел управление событиями дистанционного управления в контроллере TabBar. Теперь, когда я переместил все в контроллере просмотра плеера, я вижу, что я могу снова управлять воспроизведением музыки с помощью своей гарнитуры, но не с кнопок на новой панели управления iOS7 (той, которая появляется снизу на экране).

Это довольно странно.

Чтобы решить эту проблему, давайте попробуем обогатить поток нашим тестом.

+0

В настоящее время я тестирую и нахожу работу с использованием MPMPlayerViewController и регистрирую ее с помощью объекта уведомления, и получение этого состояния будет обновляться после того, как я буду работать. – codejunkie

+0

Я не использую MPPlayer, поэтому я не могу зарегистрироваться для этого уведомления. Это безумие, потому что я решил проблему, просто переместив все в AppDelegate, но теперь он больше не работает. – super

4

Одна вещь, чтобы отметить, что отличается от iOS6 к iOS7 с событиями дистанционного управления является то, что в iOS6 игра/пауза события произошли в один UIEventSubtype:
UIEventSubtypeRemoteControlTogglePlayPause
И в iOS7 они приходят в виде двух отдельных подтипов:
UIEventSubtypeRemoteControlPause
UIEventSubtypeRemoteControlPlay

7

Видимо проблема была на стороне Apple, как IOS обновления 7.0.3 исправляет эту проблему. Кроме того, что Алекс заметил о изменениях UIEventSubtype, код, который работал на iOS6, теперь работает на iOS7.

Для полноты, вот мой соответствующий код, который работает как в iOS6, так и в iOS7 - после udpate до 7.0.3. Также включены AVFoundation.framework и MediaPlayer.framework в Project Build Phases -> Link binary с библиотеками. Никакого кода для этого в делегате приложения.

В ViewController .h файле:

#import <AVFoundation/AVFoundation.h> 
#import <MediaPlayer/MediaPlayer.h> 

@interface NewsDetailViewController : UIViewController <UIWebViewDelegate, AVAudioSessionDelegate> 
@property (nonatomic) MPMoviePlayerController *audioPlayer; 

В ViewController .m файл:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    self.audioPlayer = [[MPMoviePlayerController alloc] initWithContentURL:audioUrl]; 
    [self.audioPlayer prepareToPlay]; 
    [self.audioPlayer.view setFrame:CGRectMake(0, 0, self.audioView.frame.size.width,  42)]; 
    self.audioPlayer.view.autoresizingMask = UIViewAutoresizingFlexibleWidth; 
    [self.audioView addSubview:self.audioPlayer.view]; 
    [self.audioPlayer play]; 

    NSError *setCategoryError = nil; 
    NSError *activationError = nil; 
    [[AVAudioSession sharedInstance] setActive:YES error:&activationError]; 
    [[AVAudioSession sharedInstance] setDelegate:self]; 
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError]; 
} 

- (BOOL)canBecomeFirstResponder { 
    return YES; 
} 

- (void)viewDidAppear:(BOOL)animated { 
    [super viewDidAppear:animated]; 

    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; 
    [self becomeFirstResponder]; 
} 

- (void)viewWillDisappear:(BOOL)animated { 
    [self.audioPlayer stop]; 
    [[UIApplication sharedApplication] endReceivingRemoteControlEvents]; 
    [self resignFirstResponder]; 

    [super viewWillDisappear:animated]; 
} 

- (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent { 

    if (receivedEvent.type == UIEventTypeRemoteControl) { 
     switch (receivedEvent.subtype) { 
      case UIEventSubtypeRemoteControlPlay: 
       [self.audioPlayer play]; 
       break; 
      case UIEventSubtypeRemoteControlPause: 
       [self.audioPlayer pause]; 
       break; 
      case UIEventSubtypeRemoteControlTogglePlayPause: 
       if (self.audioPlayer.playbackState == MPMoviePlaybackStatePlaying) { 
        [self.audioPlayer pause]; 
       } 
       else { 
        [self.audioPlayer play]; 
       } 
       break; 
      default: 
       break; 
     } 
    } 
} 
6

Если вы хотите воспроизводить аудио в фоновом режиме в Iphone и симулятора также то вам нужно написать этот код в plist и во-первых, убедитесь, что ваш Info.plist правильно отображает аудио в качестве фонового режима.

(Если вы не знаете, что я говорю о выборе YOURAPPNAME-Info.plist, выберите это. Нажмите на знак плюса и введите ключ UIBackgroundModes и введите. Добавьте значение под названием «Приложение воспроизводит аудио» (для симулятора) или «Приложение воспроизводит аудио или передает аудио/видео с помощью AirPlay» (для iphone).)

enter image description here

в AppDelegate.m

- (void)applicationDidEnterBackground:(UIApplication *)application 
{ 
    __block UIBackgroundTaskIdentifier task = 0; 
    task=[application beginBackgroundTaskWithExpirationHandler:^{ 
    NSLog(@"Expiration handler called %f",[application backgroundTimeRemaining]); 
    [application endBackgroundTask:task]; 
    task=UIBackgroundTaskInvalid; 
    }]; 
} 

Добавить эти два рамки в проекте и некоторые строки кода в ViewController.h

#import <AVFoundation/AVFoundation.h> 
#import <MediaPlayer/MediaPlayer.h> 

@interface ViewController : UIViewController <UIWebViewDelegate, AVAudioSessionDelegate> 
@property (nonatomic) MPMoviePlayerController *audioPlayer; 

Напомним, что эти рамки должны быть добавлены в ваш проект.

Тогда в Viewcontrller.m

- (void)viewDidAppear:(BOOL)animated { 
    [super viewDidAppear:animated]; 

    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; 
    [self becomeFirstResponder]; 
} 

- (void)viewWillDisappear:(BOOL)animated { 
    [self.audioPlayer stop]; 
    [[UIApplication sharedApplication] endReceivingRemoteControlEvents]; 
    [self resignFirstResponder]; 

    [super viewWillDisappear:animated]; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 

    NSURL *audioUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"songName" ofType:@"mp3"]]; 
    self.audioPlayer = [[MPMoviePlayerController alloc] initWithContentURL:audioUrl]; 
    [self.audioPlayer prepareToPlay]; 
    [self.audioPlayer.view setFrame:CGRectMake(0, 0, self.view.frame.size.width-100,  42)]; 
    self.audioPlayer.view.autoresizingMask = UIViewAutoresizingFlexibleWidth; 
    [self.view addSubview:self.audioPlayer.view]; 
    [self.audioPlayer play]; 


    // for run application in background 
    NSError *setCategoryError = nil; 
    NSError *activationError = nil; 
    [[AVAudioSession sharedInstance] setActive:YES error:&activationError]; 
    [[AVAudioSession sharedInstance] setDelegate:self]; 
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError]; 
} 

Я надеюсь, что это поможет вам воспроизводить аудио в фоновом режиме в Iphone и имитатором.

+0

Изменение appdelegate не является хорошей практикой кода, и мы должны стараться держаться подальше от appdelegate, поскольку это зависит от ОС, когда приложение загружается и отбирает контроль над контроллерами приложений. Подробнее читайте здесь: http://www.hollance.com/2012/02/dont-abuse-the-app-delegate/ – codejunkie

+0

отлично работает в фоновом режиме ,,, а как изменится вид? – NullData

+0

У меня есть поп назад к другому виду, но вы хотите воспроизвести тот же звук из предыдущего вида – NullData

Смежные вопросы