使用AVPlayer播放網(wǎng)絡(luò)音頻簡(jiǎn)單易行,但是在使用的時(shí)候我們需要很多時(shí)間的監(jiān)控處理,這里就需要分裝一下,好供我們使用,在不同的地方使用,省去了繁瑣的事件監(jiān)聽(tīng)出,KVO處理不好容易造成多移除崩潰,為移除崩潰,封裝到一個(gè)類(lèi)中,統(tǒng)一處理,簡(jiǎn)單方便,
<創(chuàng)建一個(gè)播放類(lèi)文件>
**PlayerSource.h**
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h> **導(dǎo)入框架**
<*頂一個(gè)枚舉類(lèi)型,記錄播放的狀態(tài)*>
typedef NS_ENUM(NSUInteger, cq_audioPayerState){
cq_audioPayerStateNormal = 0, /**< 未播放狀態(tài) */
cq_audioPayerStatePlaying = 2, /**< 正在播放 */
cq_audioPayerStateCancle = 3, /**< 播放被取消 */
};
<*定義代理方法將播放狀態(tài)傳到出去,方便事件的處理*>
@protocol cqAudioPlayerDelegate <NSObject>
- (void)audioPlayerStatuesDidChanged:(cq_audioPayerState)audioPlayer index:(NSInteger)index;
@end
@interface PlayerSource : NSObject
@property (nonatomic ,copy)NSString *URlString;
@property (nonatomic, assign) NSUInteger index;
@property (nonatomic, weak) id<cqAudioPlayerDelegate>delegate;
@property (nonatomic,strong)AVPlayer *audioPlayer;
@property (nonatomic ,assign)cq_audioPayerState audioStatues;
//記錄是否在播放,方便記錄是否移除了KVO
@property (nonatomic ,assign)BOOL isPlaying;
+ (instancetype)sharePlayer;
/**
播放事件
@param URl 資源鏈接
@param index 記錄當(dāng)前播放的原位置 //例如點(diǎn)擊tableviewCell的一個(gè) index為1 第5個(gè)cell為5
*/
- (void)playAudioWithURLString:(NSString *)URl atindex:(NSUInteger)index;
/**
直接播放事件
@param URlstring 資源鏈接
*/
- (void)playAudioWithWebUrlString:(NSString *)URlstring;
/**
停止事件
*/
- (void)stopAudioPlayer;
@end
<PlayerSource>
/**
這里使用單例模式方便方法的調(diào)用
*/
+ (instancetype)sharePlayer{
static dispatch_once_t onceToken;
static id shareInstance;
dispatch_once(&onceToken, ^{
shareInstance = [[self alloc] init];
});
return shareInstance;
}
- (void)playAudioWithURLString:(NSString *)URl atindex:(NSUInteger)index
{
if (!URl) {
return;
}
if ([self.URlString isEqualToString:URl] && _index == index) {
[self stopAudioPlayer];
[self setAudioStatues:cq_audioPayerStateCancle];
self.StatuesImage.selected = NO;
return;
}
self.URlString = URl;
self.index = index;
dispatch_async(dispatch_get_main_queue(), ^{
[self playAudioWithWebUrlString:URl];
});
}
- (void)playAudioWithWebUrlString:(NSString *)URlstring
{
if (_isPlaying) { //如果在播放 表示KVO未被移除,移除KVO
[_audioPlayer removeObserver:self forKeyPath:@"status"];
_isPlaying = NO;
}
AVAsset *asset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:URlstring] options:nil];
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
_audioPlayer = [AVPlayer playerWithPlayerItem:playerItem];
[[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:nil];
[[AVAudioSession sharedInstance]setActive:YES error:nil];
//添加監(jiān)聽(tīng)博播狀態(tài)的KVO
[_audioPlayer addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
[_audioPlayer play];
_isPlaying = YES; //表示播放,添加了KVO
[self addNotification];
}
//
-(void)setAudioStatues:(cq_audioPayerState)audioStatues
{
_audioStatues = audioStatues;
if (self.delegate && [self.delegate respondsToSelector:@selector(audioPlayerStatuesDidChanged:index:)]) {
[self.delegate audioPlayerStatuesDidChanged:audioStatues index:self.index];
}
if (_audioStatues == cq_audioPayerStateCancle || audioStatues == cq_audioPayerStateNormal) {
_URlString = nil;
_index = NSIntegerMax; //播放完成將數(shù)值改變,防止下次播放時(shí)判斷是同一個(gè)在播放的資源
setAudioStatues:cq_audioPayerStateCancle];
}
}
//
<*添加KVO*>
- (void)addNotification
{
[[NSNotificationCenter defaultCenter]addObserver:self
selector:@selector(playbackFinished:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:_audioPlayer.currentItem];
}
<*監(jiān)測(cè)是否自動(dòng)播放完成*>
- (void)playbackFinished:(NSNotification *)notice
{
[self stopAudioFinish];
}
//事件的監(jiān)聽(tīng)處理
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
if ([keyPath isEqualToString:@"status"]) {
AVPlayerStatus status= [[change objectForKey:@"new"]intValue];
if(status==AVPlayerStatusReadyToPlay){
self.StatuesImage.selected = YES;
[self setAudioStatues:cq_audioPayerStatePlaying];
[_timer invalidate];
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeAction:) userInfo:nil repeats:YES];
}else if (status == AVPlayerStatusUnknown)
{
ReachabilityStatus statues = [GLobalRealReachability currentReachabilityStatus];
if (statues == RealStatusNotReachable) {
[self setAudioStatues:cq_audioPayerStateCancle];
[self stopAudioPlayer];
_hud = [MBProgressHUD showHUDAddedTo:[UIApplication sharedApplication].keyWindow animated:YES];
_hud.mode = MBProgressHUDModeText;
_hud.labelText = @"網(wǎng)絡(luò)連接有誤";
_hud.margin = 10.0f; //提示框的大小
[_hud customView];
_hud.removeFromSuperViewOnHide = YES; //隱藏之后刪除view
[_hud hide:YES afterDelay:0.8]; //多久后隱藏
return;
}else
{
}
}else if (status == AVPlayerStatusFailed)
{
[self setAudioStatues:cq_audioPayerStateNormal];
[self stopAudioPlayer];
_hud = [MBProgressHUD showHUDAddedTo:[UIApplication sharedApplication].keyWindow animated:YES];
_hud.mode = MBProgressHUDModeText;
_hud.labelText = @"播放有誤";
_hud.margin = 10.0f; //提示框的大小
[_hud customView];
_hud.removeFromSuperViewOnHide = YES; //隱藏之后刪除view
[_hud hide:YES afterDelay:0.5]; //多久后隱藏
}
}else if([keyPath isEqualToString:@"loadedTimeRanges"]){
}
}
<*中途暫停的播放事件*>
- (void)stopAudioPlayer
{
if (_audioPlayer) {
if (_audioPlayer.status == AVPlayerStatusReadyToPlay) {
[_audioPlayer pause];
if (_isPlaying) {
[_audioPlayer removeObserver:self forKeyPath:@"status"];
_isPlaying = NO;
}
[_timer setFireDate:[NSDate distantFuture]];
self.StatuesImage.selected = NO;
[[PlayerSource sharePlayer] setAudioStatues:cq_audioPayerStateCancle];
}
}
}
<*正常播放完成的暫停事件*>
- (void)stopAudioFinish
{
if (_audioPlayer) {
if (_audioPlayer.status == AVPlayerStatusReadyToPlay) {
[_audioPlayer pause];
_isfinish = YES;
[[PlayerSource sharePlayer] setAudioStatues:cq_audioPayerStateNormal];
self.StatuesImage.selected = NO;
if (_isPlaying) {
[_audioPlayer removeObserver:self forKeyPath:@"status"];
_isPlaying = NO;
}
_isShowView = NO;
[self.backView removeFromSuperview];
self.backView = nil;
}
}
}
<以上便是播放的內(nèi)容,下面介紹如何使用>
先介紹播放點(diǎn)擊tableViewCell的播放事件
pragma mark ====點(diǎn)擊播放聲音=====
首先在需要播放的類(lèi)這種的viewdidload中先遵循代理
[PlayerSource sharePlayer].delegate = self;
- (void)tapImgaeWithCell:(QuestionTableViewCell *)cell
{
if (IsLogin) {
NSIndexPath *indexPath = [_QuestionTable indexPathForCell:cell];
QuestionStatues *statues = [_DataArray objectAtIndex:indexPath.section];
if (self.index == indexPath.section) {
// [cell setVoicePlayStatues:cq_VoiceplayStatueCancle];
[[PlayerSource sharePlayer]playAudioWithURLString:[detailPublicUrl stringByAppendingString:statues.ansAudio] atindex:indexPath.section];
self.index = NSIntegerMax;
}else
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
_IndexQuesID = statues.queID;
[PlayerSource sharePlayer].timeText = statues.ansAudioSec;
[[PlayerSource sharePlayer]playAudioWithURLString:[detailPublicUrl stringByAppendingString:statues.ansAudio] atindex:indexPath.section];
[[PlayerSource sharePlayer] setTitleLabel:statues.queTitle timeLabel:statues.ansAudioSec];
self.index = indexPath.section;
}
}else
{
[PublickResource showTipAlertViewWith:self title:@"未登錄" message:@"是否立即登錄" CancleTitle:@"取消" downTitle:@"立即登錄" CancelButton:^{
} DownButton:^{
LoginViewController *log = [[LoginViewController alloc]init];
MKNavigationController *nav = [[MKNavigationController alloc]initWithRootViewController:log];
[self presentViewController:nav animated:YES completion:nil];
}];
}
}
<*代理方法監(jiān)聽(tīng)的處理*>
-(void)audioPlayerStatuesDidChanged:(cq_audioPayerState)audioPlayer index:(NSInteger)index
{
if (index < _DataArray.count - 1) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:index];
QuestionStatues *statues = [_DataArray objectAtIndex:index];
QuestionTableViewCell *voiceMessageCell = [_QuestionTable cellForRowAtIndexPath:indexPath];
VoiceImageStatues voiceStatues;
switch (audioPlayer) {
case cq_audioPayerStateCancle:
voiceStatues = cq_VoiceplayStatueCancle;
_isPlaying = NO;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
break;
case cq_audioPayerStatePlaying:
voiceStatues = cq_VoiceplayStatuePlaying;
_isPlaying = YES;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
break;
case cq_audioPayerStateNormal:
_isPlaying = NO;
[self addClickNumberWithID:_IndexQuesID];
NSInteger inter = [statues.clicked integerValue];
inter++;
statues.clicked = [NSString stringWithFormat:@"%ld",(long)inter];
[self.QuestionTable reloadData];
voiceStatues = cq_VoiceplayStatueNormal;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
default:
break;
}
dispatch_async(dispatch_get_main_queue(), ^{
[voiceMessageCell setVoicePlayStatues:voiceStatues];
});
}
}
<*cell中代理與定義的實(shí)現(xiàn)*>
<*cell.h中定義枚舉類(lèi)型*>
typedef NS_ENUM(NSUInteger,VoiceImageStatues){
cq_VoiceplayStatueNormal,/**< 未播放狀態(tài)*/
cq_VoiceplayStatuePlaying,/**< 未播放狀態(tài)*/
cq_VoiceplayStatueCancle,/**< 未播放狀態(tài)*/
};
<*定義代理方法*>
@protocol SelectVoiceImageDelegate <NSObject>
- (void)tapImgaeWithCell:(QuestionTableViewCell *)cell;
@end
<*在cell中聲明枚舉與代理方法*>
@property (nonatomic ,weak)id<SelectVoiceImageDelegate>delegate;
@property (nonatomic ,assign)VoiceImageStatues VoicePlayStatues;
<介紹使用方法直接播放的方法>
<*同樣的需要在類(lèi)中遵循代理*>
[PlayerSource sharePlayer].delegate = self;
播放方法
[[PlayerSource sharePlayer] playAudioWithWebUrlString: @""];
<*代理時(shí)間監(jiān)聽(tīng)處理*>
- (void)audioPlayerStatuesDidChanged:(cq_audioPayerState)audioPlayer index:(NSInteger)index
{
switch (audioPlayer) {
case cq_audioPayerStateCancle:
[_StatuesImage stopAnimating];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
break;
case cq_audioPayerStatePlaying:
[_StatuesImage startAnimating];
_isPlaying = YES;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
break;
case cq_audioPayerStateNormal:
[_StatuesImage stopAnimating];
[self addClickNumberWithID:_QueID];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
default:
break;
}
}