AVAudioPlayer 是在 iOS 裝置中用來播放音樂的一個重要類別,它被包含在 AVFoundation.framework 套件中,透過 AVAudioPlayer 我們除了可以播放音樂之外,還可以取得正在播放的音軌位置、聲音大小或是聲道數目等等,因此,它常被使用來製作音樂撥放器等相關的應用程式。如果你想尋找的是播放單純的「音效」而非「音樂」,請參考 Core Audio 的 System Sound 音效播放一文。
環境設定
既然 AVAudioPlayer 是包含在 AVFoundation.framework 之中,在使用上就別忘了把函式庫和 Framework 加到專案中,對於新增 Framework 有問題的讀者們,請參考 Xcode 4 新增 Framework 的方法一文。
既然 AVAudioPlayer 是包含在 AVFoundation.framework 之中,在使用上就別忘了把函式庫和 Framework 加到專案中,對於新增 Framework 有問題的讀者們,請參考 Xcode 4 新增 Framework 的方法一文。
#import <AVFoundation/AVAudioPlayer.h>
替專案增加 AVFoundation.framework |
接著在實作類別中的 @interface 區段中,建立一個 AVAudioPlayer 型態的全域變數,方便稍後用它來實作播放音樂的總總功能。
AVAudioPlayer *myPlayer;
ps:在類別的 import 上,你可以選擇只匯入關鍵的 AVAudioPlayer.h(如上述的程式碼),或是直接使用 AVFoundation/AVFoundation.h 將整個 AVFoundation.framework 中所有的套件都一次匯入。
載入音樂
在這個部分,我們要將先前宣告的 myPlayer 全域變數與音樂檔案做連結,當然,如果你的音樂檔案不再本機端而是存放於網路,你也可以透過連結網路位置的方式來播放音樂檔案(並非音樂串流)。
//檔案存放於本機
//取得播放檔案的位置
NSURL* url = [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:@"FileName" ofType:@"mp3"]];
//與音樂檔案做連結
NSError* error = nil;
myPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
if (!url || error) {
//錯誤處理常式
}
//檔案存放於網路
//取得播放檔案的位置
NSURL *url = [NSURL URLWithString:@"http://FileName.mp3"];
NSData *myNetworkData = [NSData dataWithContentsOfURL:url];
//與音樂檔案做連結
NSError* error = nil;
myPlayer = [[AVAudioPlayer alloc] initWithData:myNetworkData error:&error];
if (!url || error) {
//錯誤處理常式
}
控制項目與檔案資訊
AVAudioPlayer 的控制項目包含「播放」、「暫停」、「跳轉」與「音量控制」等等,另外在資訊的部份像是「音軌總長度」、「目前播放位置」或是「聲道數目」等等都可以透過 AVAudioPlayer 來取得檔案的相關資訊。
//設定音量0.0~1.0
[myPlayer setVolume:0.5];
//設定播放次數-1為無限循環
[myPlayer setNumberOfLoops:0];
//設定播放位置(重頭播放)
[myPlayer setCurrentTime:0.0];
//播放
[myPlayer play];
//暫停
[myPlayer pause];
//停止
[myPlayer stop];
//相關資訊
NSLog(@"音樂總長度 %f", [myPlayer duration]);
NSLog(@"目前播放位置 %f", [myPlayer currentTime]);
NSLog(@"聲道數目 %d", [myPlayer numberOfChannels]);
你可以自行組合上述這些控制項目來實作簡單的控制應用,像是暫停/播放或是往後快轉數秒的按鈕等等。
//暫停/播放
if ([myPlayer isPlaying]) {
[myPlayer pause];
} else {
[myPlayer play];
}
//往後跳轉1秒
NSTimeInterval currentTime = [myPlayer currentTime];
[myPlayer setCurrentTime:currentTime + 1];
AVAudioPlayerDelegate 協定
在 AVAudioPlayer 的類別中的 AVAudioPlayerDelegate 協定,可以幫助我們捕捉音樂在播放完成時的那個瞬間,也就是當音樂播放完成時(不論成功與否)都會觸發此協定中所定義的方法函式。
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
NSLog(@"播放完畢");
}
另外,在 AVAudioPlayerDelegate 協定之中,還有兩個比較常用的方法函式,像是當電話來時,音樂被強迫中斷,或是當結束通話時恢復音樂播放的瞬間,我們都可以透過下列兩個方法函式來捕捉(需使用實體裝置執行時才會生效)。
//電話中斷
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player {
NSLog(@"被中斷");
}
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flags {
NSLog(@"從中斷中恢復");
}
在使用上,你必須先替實作的類別的 @interface 區段上加上 <AVAudioPlayerDelegate>,並且在程式碼中使用 setDelegate 來決定要實作的位置,關於協定的相關資訊請參考Protocol 協定的使用方式一文。
背景執行(模擬器無法使用)
想要讓音樂能夠在背景執行,必須要具備 iOS 4.0 以上的條件,你可以參考偵測 Device 是否支援多工或背景執行的方法一文,來判斷目前的裝置是否能夠支援此項功能。
在實作上,首先必須先到專案的 info.plist 中增加背景執行的權限 Required background modes,並設定執行的類別為 App plays audio,如下圖。
替專案增加背景執行的權限 |
接著,替專案的 AVAudioSession 做以下設定(在此必須記得 import AVAudioSession.h,如果你先前已經將整個 AVFoundation.h 都匯入,則可以省略此步驟)。
NSError* error = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
if (error) {
//錯誤處理常式
}
error = nil;
[[AVAudioSession sharedInstance] setActive:YES error:&error];
if (error) {
//錯誤處理常式
}
你可以在任何地方安插上述程式碼,但是,必須確保此程式碼在應用程式進入背景作業之前就會被執行到,另外,你可以參考使用 Remote Control 來控制退至背景播放的音樂一文,來控制背景執行中的音樂。
ps:其他有關 AVAudioPlayer 類別的相關資訊,請參考 iOS Developer Library 官方網站。
請問如果是把音樂存在app的Document裡面
回覆刪除有辦法播放嗎?
可以阿~~只要有檔案路徑就可以播放
回覆刪除記得將路徑替換成 Document 的預設位置。
請問一下我應該怎麼做呢?
回覆刪除NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *musicString = [documentPaths objectAtIndex:0];
NSString *urlString = [NSString stringWithFormat:@"%@/到不了的幸福.mp3",musicString];
NSURL *url = [[NSURL alloc]initFileURLWithPath:urlString];
其他的地方都沒變
可是好像沒有辦法播耶...
請問可以幫忙我一下嗎 感謝
你好 可以播了 原來是路徑設定錯了...
回覆刪除謝謝你
另外在順便請問一下
有辦法等歌播完的時候直接跳下一首嗎?
直接跳下一首唷,這我就真的沒研究了~~不過應該有會內建方的方法函式可以知道音樂或是音效是否「播放完畢」,你可以利用這個方法函式來播放你的歌曲,當然,你必須把所有要播放的歌曲建立一個播放清單,它的形態可能會是一個陣列,裡面存放著不同歌曲的路徑,大概就是這樣,希望有幫到你的忙。
刪除-(void)audioPlayerDidFinishPlaying
刪除wow~
刪除感謝你替我解答!
請問可以直接播放網路上的音檔嗎
回覆刪除如果是有支援的格式應該都沒問題,您可以試試看 NSURL *url = [NSURL URLWithString:@"網路位置"]
刪除你好 在請教一個問題
回覆刪除如果我想要再退出app的時候 還是有播放音樂的效果 (就是點home鍵兩下可以直接控制音樂那樣)
請問AVAudioPlayer做的到嗎 還是有別的framework可以處理
謝謝~~
抱歉,關於這個我不是很清楚耶 「home鍵兩下可以直接控制音樂」這應該是 ipod app 的功能
刪除至於您所說的退出 app 還可以聽到音樂,這屬於「背景執行」方面,你可以在 info.plist 內設定 Application does not run in background ,如果你想要判斷你的裝置是否支援背景執行,可以參考「偵測 Device 是否支援多工或背景執行的方法」一文。
再來回答您的問題 AVAudioPlayer 的確可以讓你的音樂背景執行,但是我不確定是否可以按兩下home叫出使用者介面,因為這應該是屬於ipod應用程式的,要看apple有沒有釋出這類的framework。
請問一下AVAudioPlayer要背景播音樂要怎麼做呢?
回覆刪除只要設定Application does not run in background 就好了嗎?
我設定了YES 跟 NO 好像都沒有反應
是不是還需要寫程式碼才能達成
感謝~
應該預設都是會背景執行,我可以推薦你列下列的官方文件,對於背景執行和多工有比較多的說明
刪除http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html#//apple_ref/doc/uid/TP40007072-CH4-SW3
另外這是我之前寫的,確定你的app是在對應的選項內
有些應用程式即使在退到背景之後仍然可以繼續執行,例如電話、導航或是音樂等,這些程式並不會進入先前所說的暫停狀態,反而能與其他應用程式同步執行,如果要製作此類的應用程式可以參考 iOS 官方文件的 UIBackgroundModes,並從 Info.plist 中的 UIBackgroundModes 設定,參數形態為字串陣列的 audio、voip、location 參數值。
你好,我想請問當按下HOME鍵跳出,在切入回程式裡時可否是音樂重新播放?
回覆刪除您好:
刪除按下home之後再跳回來,音樂會接下去播放,如果你想要重新播放(重0:00的位置播放),你可以利用以下方法函式
- (void)applicationWillEnterForeground:(UIApplication *)application
將時間軸設置在0:00的位置,不過這會簽撤到背景作業,你可以前往官方網站了解背景作業的相關說明。
http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html#//apple_ref/doc/uid/TP40007072-CH4-SW3
您好~ 我建立了以下的程式碼 編譯也沒有問題 但是就是無法在模擬器上 播放音樂
回覆刪除我把 mp3 import 到 Xcode 中的 supporting files 的資料夾~ 這樣會有問題嗎?
我有參考上述的設定 ”Required background modes“ 設定完成 仍沒辦法播放~ 希望老師能指點迷津 感謝
NSString *musicFilePath = [[NSBundle mainBundle] pathForResource:@"kids" ofType:@"mp3"];
NSURL *musicURL = [[NSURL alloc] initFileURLWithPath:musicFilePath];
AVAudioPlayer *thePlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL error:nil];
[thePlayer prepareToPlay];
[thePlayer setVolume:1];
thePlayer.numberOfLoops = -1;
[thePlayer play];
你好:
刪除執行上都沒有任何問題?試試看給他一個不存在的檔案名稱,或是網路位置,會不會也是相同結果。
另外,檔案放置的位置沒有錯,而Required background modes只是背景執行的功能而已,就算不設定此參數也應該要能夠播放。
你好,我按Home鍵切換到背景下,音樂是有繼續播放,但此時電話來了,音樂就中斷,通話結束也沒有繼續播放
回覆刪除我有加下面這段(不過只在前景有效...............請問有解嗎??????)
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flags {
NSLog(@"繼續播放"); [music play];
}
您好:
刪除電話來音樂中斷應該也會觸發一個涵式,你要先暫停你的音樂。
由於你的部分已經涉及到背景處理,如果Remote Control無法解決你的問題,你可以要尋找背景中斷的相關議題。
你可以參考,iOS 應用程式狀態的變遷一文找出可能執行到的涵式
http://furnacedigital.blogspot.tw/2013/07/ios.html
不過還是建議你在做此動作之前,先使用中斷點確定程式並沒有跑到您預想的位置。
感謝!
刪除你好
回覆刪除我需要用到網路URL 所以使用了AVPLAYER
我想請問
他是否也適用
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {}
若否
可以請問要如何讓AVPLAYER自動播放下一首
或者是否有類似的協定可以用來知道已播放完畢
你好:
刪除如果是在AVPLAYER中播放的,都適用唷!
(已有在@interface 區段上加上AVAudioPlayerDelegate 協定 )
刪除你好 想在跟你確認一 下
刪除我是用AVPlayer 不是用AVAudioPlayer
是可以正常播放
就是不能進
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {}
您好
刪除要把 delegate指向你實作的controller喔,如果按照上面寫法,要寫成 myPlayer.delegate = self,你新實作的函式才會生效
你好
刪除已剛試過
只是AVPlayer類別的好像沒有delegate可以設
我知道AVAudioPlayer可以設 但是AVPlayer似乎不行
您好:
刪除我誤會你意思了 如果你是用 AVPlayer 的確是沒有這些東西,
參考AVPlayer官方文件「https://developer.apple.com/library/ios//documentation/AVFoundation/Reference/AVPlayer_Class/index.html」
你可以使用 AVPlayerItemDidPlayToEndTimeNotification 來觸發播放結束時的函式,幫你找了一個NSNotificationCenter的範例你參考看
http://stackoverflow.com/questions/27805657/swift-avplayer-how-to-track-when-song-finished-playing
好喔
刪除非常感謝
已解決問題了 ><
恭喜你嘿!
刪除你好
刪除其實建議可以介紹一下observer
我有看過這邊關於notification那篇
只是那個只能主動用程式觸發
後來又去APPLE官網找了一下資料
發現observer其實很好用 (值有變可以被動觸發)
這樣一主動一被動應該會比較完整 ><
好的,感謝您的建議!
刪除您好
回覆刪除請問如果我想用AVAudioPlayer播放本機現有的音樂
要如何搜尋音樂檔案?
你好
刪除你要搜尋整個裝置的檔案 判斷副檔名 才能確定是不是可以播放的檔案
感謝您的回覆
刪除我用MPMeiaQuery把抓到的路徑給AVAudioPlayer就可以播了
不用再確認副檔名
你太客氣了!沒幫上什麼忙
刪除