Статьи

Многозадачность iOS: фоновое аудио

Это продолжение серии iOS Multitasking. Помимо уведомлений (как обсуждалось на прошлой неделе), многозадачность iOS также предоставляет функцию, называемую Background Audio. Как следует из названия, эта функция позволяет приложениям воспроизводить звук, даже когда приложение находится в фоновом режиме, подобно тому, как работает приложение iPod или Music, прилагаемое к устройству.

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

Сначала создайте новый проект и назовите его NoiseMaker (или другим именем) как приложение на основе вида с настройками по умолчанию.

Как только проект будет создан, перейдите в NoiseMaker-Info.plist и добавьте UIBackgroundModes в качестве новой строки. Затем следует создать массив.

Откройте массив и справа от элемента 0 установите его в аудио . Ваш NoiseMaker-Info.plist должен выглядеть так:

iOS_Background_Audio

Теперь перейдите к настройкам цели и перейдите на вкладку «Фазы сборки».

iOS_Background_Audio

Когда вы закончите последний подэтап, перейдите в Link Binary With Libraries и добавьте инфраструктуру AVFoundation.

iOS_Background_Audio

В центре внимания найдите на вашем Mac файл HeadSpin Long.caf. Найдите файл и переименуйте его, чтобы освободить место.

Перетащите файл в Xcode в каталог NoiseMaker. Убедитесь, что флажок Копировать ресурсы в папку назначения установлен.

В каталоге NoiseMaker выберите файл NoiseMakerViewController.h и добавьте следующий код под объявлением #import.

1
#import <AVFoundation/AVFoundation.h>

Теперь добавьте следующий код под объявлением @interface.

1
2
3
4
5
6
IBOutlet UIButton *playPauseButton;
IBOutlet UISlider *volumeControl;
IBOutlet UILabel *alertLabel;
 
AVAudioPlayer *audioPlayer;

Затем прямо под закрывающей скобкой добавьте следующий код.

01
02
03
04
05
06
07
08
09
10
11
12
13
     
@property (nonatomic, retain) IBOutlet UIButton *playPauseButton;
@property (nonatomic, retain) IBOutlet UISlider *volumeControl;
@property (nonatomic, retain) IBOutlet UILabel *alertLabel;
 
@property (nonatomic, retain) AVAudioPlayer *audioPlayer;
 
— (IBAction)volumeDidChange:(id)slider;
— (IBAction)togglePlayingState:(id)button;
 
— (void)playAudio;
— (void)pauseAudio;
— (void)togglePlayPause;

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
     
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
 
@interface NoiseMakerViewController : UIViewController {
    IBOutlet UIButton *playPauseButton;
    IBOutlet UISlider *volumeControl;
    IBOutlet UILabel *alertLabel;
     
    AVAudioPlayer *audioPlayer;
}
 
@property (nonatomic, retain) IBOutlet UIButton *playPauseButton;
@property (nonatomic, retain) IBOutlet UISlider *volumeControl;
@property (nonatomic, retain) IBOutlet UILabel *alertLabel;
 
@property (nonatomic, retain) AVAudioPlayer *audioPlayer;
 
— (IBAction)volumeDidChange:(id)slider;
— (IBAction)togglePlayingState:(id)button;
 
— (void)playAudio;
— (void)pauseAudio;
— (void)togglePlayPause;
 
@end

Теперь откройте NoiseMakerViewController.xib. Сначала добавьте UILabel где-нибудь в представлении. В Инспекторе Атрибутов выберите опцию, чтобы сделать текст UILabel центрированным, и стереть весь текст UILabel. Теперь перейдите в инспектор размера и установите позицию X на 20, позицию Y на 100, ширину на 280 и высоту на 21.

Затем перейдите в инспектор подключений и перетащите ссылку на владелец файлов и выберите параметр alertLabel.

iOS_Background_Audio
iOS_Background_Audio
iOS_Background_Audio

Теперь добавьте UIB-кнопку к представлению и установите текст кнопки на Play. Перейдите в Инспектор размеров и установите «Положение X» на 86, «Положение Y» на 211, ширину на 150 и высоту на 37. Затем в инспекторе соединений перетащите действие TouchUpInside на владельцев файлов и выберите параметр togglePlayingState:.

Перетащите ссылочный выход к владельцу файлов и выберите параметр playPauseButton. Теперь перетащите UISlider и поместите его в представление.

Перейдите к Инспектору размера и установите Положение X на 18, Положение Y на 378, ширину на 284 и высоту на 23 (высота по умолчанию). Перейдите в инспектор подключений и перетащите ссылочную точку на владельца файлов и выберите параметр volumeControl. Затем перетащите действие valueChanged к владельцу файлов и выберите параметр volumeDidChange :. Готовый интерфейс должен выглядеть следующим образом.

iOS_Background_Audio

Теперь откройте файл NoiseMakerViewController.m. Под объявлением @implementation добавьте следующие строки.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
     
@synthesize playPauseButton;
@synthesize volumeControl;
@synthesize alertLabel;
@synthesize audioPlayer;
 
— (IBAction)volumeDidChange:(UISlider *)slider {
    //Handle the slider movement
    [audioPlayer setVolume:[slider value]];
}
 
— (IBAction)togglePlayingState:(id)button {
    //Handle the button pressing
    [self togglePlayPause];
}

Теперь в методе dealloc: добавьте следующие строки.

01
02
03
04
05
06
07
08
09
10
11
12
     
//Remove the objects from memory
     
    self.playPauseButton = nil;
    self.volumeControl = nil;
    self.alertLabel = nil;
    self.audioPlayer = nil;
     
    [playPauseButton release];
    [volumeControl release];
    [alertLabel release];
    [audioPlayer release];

Затем добавьте следующий код в метод dealloc :.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
     
— (void)viewDidAppear:(BOOL)animated {
    [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];
}
 
— (void)playAudio {
    //Play the audio and set the button to represent the audio is playing
    [audioPlayer play];
    [playPauseButton setTitle:@»Pause» forState:UIControlStateNormal];
}
 
— (void)pauseAudio {
    //Pause the audio and set the button to represent the audio is paused
    [audioPlayer pause];
    [playPauseButton setTitle:@»Play» forState:UIControlStateNormal];
}
 
— (void)togglePlayPause {
    //Toggle if the music is playing or paused
    if (!self.audioPlayer.playing) {
        [self playAudio];
         
    } else if (self.audioPlayer.playing) {
        [self pauseAudio];
         
    }
}
 
//Make sure we can recieve remote control events
— (BOOL)canBecomeFirstResponder {
    return YES;
}
 
— (void)remoteControlReceivedWithEvent:(UIEvent *)event {
    //if it is a remote control event handle it correctly
    if (event.type == UIEventTypeRemoteControl) {
        if (event.subtype == UIEventSubtypeRemoteControlPlay) {
            [self playAudio];
        } else if (event.subtype == UIEventSubtypeRemoteControlPause) {
            [self pauseAudio];
        } else if (event.subtype == UIEventSubtypeRemoteControlTogglePlayPause) {
            [self togglePlayPause];
        }
    }
}

Теперь в методе viewDidLoad: добавьте следующие строки кода под [super viewDidLoad];

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
     
//Declare the audio file location and settup the player
    NSURL *audioFileLocationURL = [[NSBundle mainBundle] URLForResource:@»HeadspinLong» withExtension:@»caf»];
     
    NSError *error;
    audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileLocationURL error:&amp;error];
    [audioPlayer setNumberOfLoops:-1];
     
    if (error) {
        NSLog(@»%@», [error localizedDescription]);
         
        [[self volumeControl] setEnabled:NO];
        [[self playPauseButton] setEnabled:NO];
         
        [[self alertLabel] setText:@»Unable to load file»];
        [[self alertLabel] setHidden:NO];
    } else {
        [[self alertLabel] setText:[NSString stringWithFormat:@»%@ has loaded», @»HeadspinLong.caf»]];
        [[self alertLabel] setHidden:NO];
         
        //Make sure the system follows our playback status
        [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
        [[AVAudioSession sharedInstance] setActive: YES error: nil];
         
        //Load the audio into memory
        [audioPlayer prepareToPlay];
    }

Спасибо за чтение этого урока. Следующим в серии будет выполнение задачи. Не стесняйтесь комментировать, если у вас возникли проблемы или просто хотите добавить совет.