English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
죽어도 쓰지 않았던 거예요, 최근에는 과도한 연장 근무로 인해, 오늘 시간을 내서 사용한 음악 플레이어 DOUAudioStreamer를 정리해 보았습니다. 과거 프로젝트에서는 AVPlayer를 사용했지만, 이거도 괜찮아요. 하지만, 먼저缓存를 해야 한다는 것을, 이제야 알았어요! 왜 이제야 알았어요! 왜 이제야 알았어요! 어떻게 해야 하나요? 그냥 용서해야죠, 계속 코드를 치고 있습니다... (그냥 코드를 보여드리자구요)
一、导入三方库
pod 'DOUAudioStreamer'
或者GitHup下载地址:https://github.com/douban/DOUAudioStreamer
二、使用
1.从demo中获取NAKPlaybackIndicatorView文件和MusicIndicator.h和MusicIndicator.m 文件,并导入头文件
//音乐播放
#import "DOUAudioStreamer.h"
#import "NAKPlaybackIndicatorView.h"
#import "MusicIndicator.h"
#import "Track.h"
如图:
2.创建一个Track类,用于音乐播放的URL存储
3.需要的界面.h中,添加DOUAudioStreamer,并用单例来初始化
+ (instancetype)sharedInstance ; @property (nonatomic, strong) DOUAudioStreamer *streamer;
如图:
在.m中实现:
static void *kStatusKVOKey = &kStatusKVOKey; static void *kDurationKVOKey = &kDurationKVOKey; static void *kBufferingRatioKVOKey = &kBufferingRatioKVOKey; @property (strong, nonatomic) MusicIndicator *musicIndicator; @property (nonatomic, strong) Track *audioTrack; + (instancetype)sharedInstance { static HYNEntertainmentController *_sharedMusicVC = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _sharedMusicVC = [[HYNEntertainmentController alloc] init]; _sharedMusicVC.streamer = [[DOUAudioStreamer alloc] init]; }); return _sharedMusicVC; }
재생 버튼 이벤트
#pragma mark ---음악 재생 버튼 -(void)playMusicStart:(UIButton *)sender { //버튼을 통해 셀을 가져옵니다. MusicCollectionViewCell *musicCell = (MusicCollectionViewCell *)[[sender superview] superview]; if(_playFirst == 0){//_playFirst == 0은 첫 번째 재생, 다른 것은 일시 중지 NSURL *_audioTrack.audioFileURL = url; @try { [self removeStreamerObserver]; @catch(id anException){ } } //DOUAudioStreamer가 재생할 때는 먼저 nil로 설정해야 합니다. _streamer = nil; _streamer = [DOUAudioStreamer streamerWithAudioFile:_audioTrack]; [self addStreamerObserver]; [_streamer play]; } if([_streamer status] == DOUAudioStreamerPaused || [_streamer status] == DOUAudioStreamerIdle){ [sender setBackgroundImage:[UIImage imageNamed:@"music_play_icon"] forState:UIControlStateNormal]; [_streamer play]; } [sender setBackgroundImage:[UIImage imageNamed:@"music_stop_icon"] forState:UIControlStateNormal]; [_streamer pause]; } _playFirst++; }
감청을 추가합니다.
- (void)addStreamerObserver { [_streamer addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:kStatusKVOKey]; [_streamer addObserver:self forKeyPath:@"duration" options:NSKeyValueObservingOptionNew context:kDurationKVOKey]; [_streamer addObserver:self forKeyPath:@"bufferingRatio" options:NSKeyValueObservingOptionNew context:kBufferingRatioKVOKey]; } /// 플레이어 파괴 - (void)dealloc{ if (_streamer !=nil) { [_streamer pause]; [_streamer removeObserver:self forKeyPath:@"status" context:kStatusKVOKey]; [_streamer removeObserver:self forKeyPath:@"duration" context:kDurationKVOKey]; [_streamer removeObserver:self forKeyPath:@"bufferingRatio" context:kBufferingRatioKVOKey]; _streamer =nil; } } - (void)removeStreamerObserver { [_streamer removeObserver:self forKeyPath:@"status"]; [_streamer removeObserver:self forKeyPath:@"duration"]; [_streamer removeObserver:self forKeyPath:@"bufferingRatio"]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (context == kStatusKVOKey) { [self performSelector:@selector(updateStatus)] onThread:[NSThread mainThread] withObject:nil waitUntilDone:NO]; } else if (context == kDurationKVOKey) { [self performSelector:@selector(updateSliderValue:) onThread:[NSThread mainThread] withObject:nil waitUntilDone:NO]; } else if (context == kBufferingRatioKVOKey) { [self performSelector:@selector(updateBufferingStatus) onThread:[NSThread mainThread] withObject:nil waitUntilDone:NO]; } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } - (void)updateSliderValue:(id)timer { } -(void)updateBufferingStatus { } - (void)updateStatus { //self.musicIsPlaying = NO; _musicIndicator.state = NAKPlaybackIndicatorViewStateStopped; switch ([_streamer status]) { case DOUAudioStreamerPlaying: // self.musicIsPlaying = YES; _musicIndicator.state = NAKPlaybackIndicatorViewStatePlaying; 브레이크; case DOUAudioStreamerPaused: 브레이크; case DOUAudioStreamerIdle: 브레이크; case DOUAudioStreamerFinished: 브레이크; case DOUAudioStreamerBuffering: _musicIndicator.state = NAKPlaybackIndicatorViewStatePlaying; 브레이크; case DOUAudioStreamerError: 브레이크; } }
이렇게 하면 재생할 수 있습니다.
락스크린 시 음악 표시, 이어폰을 꺼내면 재생 중지, 오디오 중지 이벤트를 감지
-(void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; //원격 제어를 받습니다 [self becomeFirstResponder]; [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; } //이를 잊지 마세요 -(BOOL)canBecomeFirstResponder{ return YES; } - (void)viewDidLoad { [super viewDidLoad]; //음악 플레이어 [self initPlayer]; } #pragma mark =========================음악 재생============================== //음악 플레이어 -(void)initPlayer { _audioTrack = [[Track alloc] init]; AVAudioSession *session = [AVAudioSession sharedInstance]; [session setActive:YES error:nil]; [session setCategory:AVAudioSessionCategoryPlayback error:nil]; //앱이 원격 제어 이벤트를 받을 수 있도록 지원합니다 [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; //이어폰을 꺼내면 재생을 일시 중단하는 알림을 추가합니다 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(routeChange:) name:AVAudioSessionRouteChangeNotification object:nil]; // 오디오 중단 이벤트를 감지하다 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioSessionWasInterrupted:) name:AVAudioSessionInterruptionNotification object:session]; } // 오디오 중단 이벤트를 감지하다 - (void)audioSessionWasInterrupted:(NSNotification *)notification { //때문에 중단되었습니다 if (AVAudioSessionInterruptionTypeBegan == [notification.userInfo[AVAudioSessionInterruptionTypeKey] intValue]) { [_streamer pause]; UIButton *btn = (UIButton *)[self.view viewWithTag:2000]; [btn setBackgroundImage:[UIImage imageNamed:@"music_stop_icon"] forState:UIControlStateNormal]; } else if (AVAudioSessionInterruptionTypeEnded == [notification.userInfo[AVAudioSessionInterruptionTypeKey] intValue])}} { } } // 이어폰을 뽑았을 때 재생을 일시 중지 -(void)routeChange:(NSNotification *)notification{ NSDictionary *dic=notification.userInfo; int changeReason= [dic[AVAudioSessionRouteChangeReasonKey] intValue]; //AVAudioSessionRouteChangeReasonOldDeviceUnavailable과 같으면 기존 출력이 사용할 수 없음을 의미합니다 if (changeReason==AVAudioSessionRouteChangeReasonOldDeviceUnavailable) { AVAudioSessionRouteDescription *routeDescription=dic[AVAudioSessionRouteChangePreviousRouteKey]; AVAudioSessionPortDescription *portDescription= [routeDescription.outputs firstObject]; //원래 장치가 이어폰이면 일시 중지 if ([portDescription.portType isEqualToString:@"Headphones"]) { [_streamer pause]; UIButton *btn = (UIButton *)[self.view viewWithTag:2000]; [btn setBackgroundImage:[UIImage imageNamed:@"music_stop_icon"] forState:UIControlStateNormal]; } } } //락스크린 시 음악 표시(이 메서드는 재생을 클릭할 때 호출할 수 있습니다) - (void)setupLockScreenInfoWithSing:(NSString *)서명 제공자 WithSigner:(NSString *)이미지 제공자 WithImage:(UIImage *)이미지 { // 1.获取锁屏中心 MPNowPlayingInfoCenter *playingInfoCenter = [MPNowPlayingInfoCenter defaultCenter]; //음악 정보를 저장할 딕셔너리를 초기화 NSMutableDictionary *playingInfoDict = [NSMutableDictionary dictionary]; // 2곡 제목 설정 if (sign) { [playingInfoDict setObject:sign forKey:MPMediaItemPropertyAlbumTitle]; } // 가수 이름 설정 if (signer) { [playingInfoDict setObject:signer forKey:MPMediaItemPropertyArtist]; } // 3커버 이미지 설정 //UIImage *image = [self getMusicImageWithMusicId:self.currentModel]; if (image) { MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:image]; [playingInfoDict setObject:artwork forKey:MPMediaItemPropertyArtwork]; } // 4곡의 총 시간을 설정 //[playingInfoDict setObject:self.currentModel.detailDuration forKey:MPMediaItemPropertyPlaybackDuration]; //음악 정보를 잠금화면 센터의 nowPlayingInfo 속성에 할당 playingInfoCenter.nowPlayingInfo = playingInfoDict; // 5.원격 상호작용 시작 [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; } //잠금화면 시 작업 - (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent { if (receivedEvent.type == UIEventTypeRemoteControl) { UIButton *sender = (UIButton') *)[self.view viewWithTag:2000]; switch (receivedEvent.subtype) {//원격 제어 여부를�断하기 케이스 UIEventSubtypeRemoteControlPause: [[HYNEntertainmentController sharedInstance].streamer pause]; [sender setBackgroundImage:[UIImage imageNamed:@"music_stop_icon"] forState:UIControlStateNormal]; 브레이크; 케이스 UIEventSubtypeRemoteControlStop: 브레이크; 케이스 UIEventSubtypeRemoteControlPlay: [[HYNEntertainmentController sharedInstance].streamer play]; [sender setBackgroundImage:[UIImage imageNamed:@"music_play_icon"] forState:UIControlStateNormal]; 브레이크; 케이스 UIEventSubtypeRemoteControlTogglePlayPause: 브레이크; 케이스 UIEventSubtypeRemoteControlNextTrack: 브레이크; 케이스 UIEventSubtypeRemoteControlPreviousTrack: 브레이크; 디폴트: 브레이크; } } }
전체 이미지:
위 이미지는 재생하지 않습니다
위 이미지는 재생 중입니다
위 이미지는 잠금 화면 상태입니다
추가할 것은 없을 것 같아, 일시적으로 마무리합니다. 부족한 점이 있으면 아래의 댓글 부분에서 논의해 주세요. 나비 가이드에 대한 지원에 감사합니다.