posted by Phan Ngọc Tiến on 2014-02-06 21:14

Các ứng dụng chạy trên nền iOS hầu như sẽ bị dừng lại khi bạn bấm nút "Home" hoặc bạn chuyển sang chạy một ứng dụng khác, mặc dù nó vẫn còn tồn tại trong bộ nhớ nhưng nó sẽ không chạy bất cứ đoạn mã nào cho đến khi người dùng bật nó lên một lần nữa.

Tuy nhiên trong một số trường hợp cụ thể ứng dụng của bạn có thể tiếp tục chạy các đoạn mã trong chế độ nền. Như bạn đã biết Apple nổi tiếng nhờ sự khó tính và khắc khe với các nhà phát triển ứng dụng do đó các trường hợp chạy ở chế độ nền cũng được Apple quy định rất cụ thể. 

  1. Ứng dựng chơi nhạc
  2. Ứng dụng cập nhật vị trí
  3. Ứng dụng cập nhật dữ liệu định kỳ từ máy chủ (iOS 7)
  4. Ứng dụng chạy trong quầy báo (Newsstand)
  5. Ứng dụng chạy nền với thời gian hữu hạn
  6. Ứng dụng VoIP

Sau đây tôi sẽ giới thiệu một số trường hợp iOS cho phép ứng dụng của bạn chạy trong nền của nó.

Ứng dụng chơi nhạc 

Khi chạy một ứng dụng chơi nhạc, người sử dụng sẽ muốn trình chơi nhạc đó có thể chạy ở chế độ nền đơn giản là vì họ muốn có thể tắt màn hình để tiết kiệm pin hoặc là vừa nghe nhạc vừa lướt web xem tin tức ...

Chính vì thế iOS cho phép các trình chơi nhạc có thể tiếp tục phát ra âm thanh ở trong nền. Có một số người lợi dụng điều này cho ứng dụng phát một bản nhạc không phát ra âm thanh để đổi lại thời gian của CPU. Tuy nhiên trong một số trường hợp thì giải pháp này có thể thực hiện được nhưng nêu đưa ứng dụng này lên App store thì ngay lập tức Apple sẽ từ chối ứng dụng của bạn.

 

Để ứng dụng của bản có thể phát một bản nhạc trong chế độ nền việc bạn cần làm đầu tiên đó là làm cho ứng dụng của bạn có thể chơi nhạc (dĩ nhiên rồi) sau đó thông báo với iOS là ứng dụng của bạn cần phát nhạc ở chế đồ nền.

 

Để phát nhạc bạn cần import các framework sau vào project: AVFoundation,CoreMedia, AudioToolbox.

trong file viewController.m bạn ghi dòng sao vào đầu của file;

#import <AVFoundation/AVFoundation.h>

Tiếp theo khai báo các biến @property sau:

@property (nonatomic, strong) AVQueuePlayer *player;
@property (nonatomic, strong) id timeObserver;

Trong function viewDidLoad thêm cái dòng lệnh sau:

// Set AVAudioSession
NSError *sessionError = nil;
[[AVAudioSession sharedInstance] setDelegate:self];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];
 
// Change the default output audio route
UInt32 doChangeDefaultRoute = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker,
sizeof(doChangeDefaultRoute), &doChangeDefaultRoute);

Đầu tiên khởi tạo phiên âm thanh và đảm bảo âm thanh sẽ được phát qua loa.

 

Tiên theo khơi tạo danh sách bài hát:

NSArray *queue = @[
[AVPlayerItem playerItemWithURL:[[NSBundle mainBundle] URLForResource:@"audio1" withExtension:@"mp3"]],
[AVPlayerItem playerItemWithURL:[[NSBundle mainBundle] URLForResource:@"audio2" withExtension:@"mp3"]],
[AVPlayerItem playerItemWithURL:[[NSBundle mainBundle] URLForResource:@"audio3" withExtension:@"mp3"]]];
 
self.player = [[AVQueuePlayer alloc] initWithItems:queue];
self.player.actionAtItemEnd = AVPlayerActionAtItemEndAdvance;

Bạn thêm dòng sau vào cuối viewDidLoad

[self.player addObserver:self
                  forKeyPath:@"currentItem"
                     options:NSKeyValueObservingOptionNew
                     context:nil];

Điều này giúp class của bạn biết được khi nào thuộc tính "curentItem" thay đổi. Bây giờ bạn thêm một phương thức để quan sát sự thay đổi của thuộc tính "currentItem". Đặt nó dưới viewDidLoad

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"currentItem"])
    {
        AVPlayerItem *item = ((AVPlayer *)object).currentItem;
        self.lblMusicName.text = ((AVURLAsset*)item.asset).URL.pathComponents.lastObject;
        NSLog(@"New music name: %@", self.lblMusicName.text);
    }
}

Bạn thêm tiếp các dòng sau vào cuối viewDidLoad

void (^observerBlock)(CMTime time) = ^(CMTime time) {
NSString *timeString = [NSString stringWithFormat:@"%02.2f", (float)time.value / (float)time.timescale];
if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) {
            self.lblMusicTime.text = timeString;
        } else {
            NSLog(@"App is backgrounded. Time is: %@", timeString);
        }
    };
 
self.timeObserver = [self.player addPeriodicTimeObserverForInterval:CMTimeMake(10, 1000)
                                                                  queue:dispatch_get_main_queue()
                                                             usingBlock:observerBlock];

Khối lệnh trên sẽ được gọi bất cứ khi nào thời gian được cập nhật. Khối trên sẽ tạo một chuổi để cập nhật thời gian của bài hát.

Cuối cùng bạn cần tạo thêm một phương thức để bắt sự kiện bấm vào nút để phát hoặc dừng nhạc.

- (IBAction)didTapPlayPause:(id)sender
{
    self.btnPlayPause.selected = !self.btnPlayPause.selected;
    if (self.btnPlayPause.selected)
    {
        [self.player play];
    }
    else
    {
        [self.player pause];
    }
}

Và chúng ta cũng không nên quên việc khai báo với iOS rằn ứng dụng của chúng ta cần phát nhạc ở chế độ nền. Bạn tìm "Capabilities" tab của màn hình thiết lập dự án. Bật "Background Modes" và chọn các chế độ mà ứng dụng của bạn sẽ sử dụng

 

 

Tận hưởng thành quả nào. Và một điều cần nói với bạn là nó sẽ không phát nhạc ở chế độ nền nếu bạn đang sử dụng simulator, hay thử trên device thật nó sẽ chạy.

 

Các chế độ nền tiếp theo sẽ được hướng dẫn ở các bài sau!


Leave a Comment

Fields with * are required.