English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Non ho scritto nulla da molto tempo, ultimamente ho lavorato molto a lungo, oggi ho trovato un momento per organizzare il riproduttore musicale DOUAudioStreamer utilizzato, poiché il progetto precedente utilizzava AVPlayer, questo è anche buono, ma deve essere cacheato per un po' prima di riprodurre, il capo ha guardato e ha richiesto che venga cambiato il cache e la riproduzione (connesso a internet, cliccando sul pulsante di riproduzione si riproduce immediatamente), come potevo non dirlo! Come potevo non dirlo! Come potevo non dirlo! Cosa altro posso fare? Solo perdonarlo, continuare a scrivere codice......(perché non andare direttamente al codice?)
Prima di tutto, importare la libreria di terze parti
pod 'DOUAudioStreamer'
oppure l'indirizzo di download di GitHup:https://github.com/douban/DOUAudioStreamer
Dopo questo
1. Estrarre il file NAKPlaybackIndicatorView e i file MusicIndicator.h e MusicIndicator.m dal demo e importare il file di intestazione
//音乐播放
#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 { //通过按钮获取cell MusicCollectionViewCell *musicCell = (MusicCollectionViewCell *)[[sender superview] superview]; if(_playFirst == 0) { // _playFirst == 0 per la riproduzione iniziale, altri per la pausa NSURL *url = [NSURL URLWithString:HttpImgUrl(musicCell.model.musicUrl)]; _audioTrack.audioFileURL = url; @try { [self removeStreamerObserver]; } @catch(id anException) { } //In DOUAudioStreamer, deve essere impostato su nil prima di riprodurre _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]; } else { [sender setBackgroundImage:[UIImage imageNamed:@"music_stop_icon"] forState:UIControlStateNormal]; [_streamer pause]; } _playFirst++; }
Aggiungere l'osservatore
- (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]; } /// Destroyer del riproduttore - (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]; } [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; break; case DOUAudioStreamerPaused: break; case DOUAudioStreamerIdle: break; case DOUAudioStreamerFinished: break; case DOUAudioStreamerBuffering: _musicIndicator.state = NAKPlaybackIndicatorViewStatePlaying; break; case DOUAudioStreamerError: break; } }
Così potrà essere riprodotto.
Visualizzazione della musica quando la schermata è bloccata, pausa la riproduzione quando si rimuove l'auricolare, ascolto degli eventi di interruzione audio
-(void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; //Accetta il controllo remoto [self becomeFirstResponder]; [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; } //Non dimenticare questo! -(BOOL)canBecomeFirstResponder{ return YES; } - (void)viewDidLoad { [super viewDidLoad]; // Riproduttore musicale [self initPlayer]; } #pragma mark =========================Music Playback============================== // Riproduttore musicale -(void)initPlayer { _audioTrack = [[Track alloc] init]; AVAudioSession *session = [AVAudioSession sharedInstance]; [session setActive:YES error:nil]; [session setCategory:AVAudioSessionCategoryPlayback error:nil]; // Far supportare all'app di accettare eventi di controllo remoto [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; // Aggiungere notifica, sospendere la riproduzione dopo aver tolto l'auricolare [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(routeChange:) name:AVAudioSessionRouteChangeNotification object:nil]; // Monitorare l'evento di interruzione dell'audio [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioSessionWasInterrupted:) name:AVAudioSessionInterruptionNotification object:session]; } // Monitorare l'evento di interruzione dell'audio - (void)audioSessionWasInterrupted:(NSNotification *)notification { // Quando interrotto 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]) { } } // Togliere l'auricolare per sospendere la riproduzione -(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 *)sign WithSigner:(NSString *)signer WithImage:(UIImage *)image { // 1.获取锁屏中心 MPNowPlayingInfoCenter *playingInfoCenter = [MPNowPlayingInfoCenter defaultCenter]; //初始化一个存放音乐信息的字典 NSMutableDictionary *playingInfoDict = [NSMutableDictionary dictionary]; // 2. Set the song name if (sign) { [playingInfoDict setObject:sign forKey:MPMediaItemPropertyAlbumTitle]; } // Set the artist name if (signer) { [playingInfoDict setObject:signer forKey:MPMediaItemPropertyArtist]; } // 3. Set the cover image // UIImage *image = [self getMusicImageWithMusicId:self.currentModel]; if (image) { MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:image]; [playingInfoDict setObject:artwork forKey:MPMediaItemPropertyArtwork]; } // 4. Set the total duration of the song // [playingInfoDict setObject:self.currentModel.detailDuration forKey:MPMediaItemPropertyPlaybackDuration]; // Assign music information to the nowPlayingInfo property of the lock screen center playingInfoCenter.nowPlayingInfo = playingInfoDict; // 5. Enable remote interaction [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; } // Lock screen operation - (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent { if (receivedEvent.type == UIEventTypeRemoteControl) { UIButton *sender = (UIButton *)[self.view viewWithTag:2000]; switch (receivedEvent.subtype) { // Verifica se è un controllo remoto} case UIEventSubtypeRemoteControlPause: [[HYNEntertainmentController sharedInstance].streamer pause]; [sender setBackgroundImage:[UIImage imageNamed:@"music_stop_icon"] forState:UIControlStateNormal]; break; case UIEventSubtypeRemoteControlStop: break; case UIEventSubtypeRemoteControlPlay: [[HYNEntertainmentController sharedInstance].streamer play]; [sender setBackgroundImage:[UIImage imageNamed:@"music_play_icon"] forState:UIControlStateNormal]; break; case UIEventSubtypeRemoteControlTogglePlayPause: break; case UIEventSubtypeRemoteControlNextTrack: break; case UIEventSubtypeRemoteControlPreviousTrack: break; default: break; } } }
Immagine completa:
L'immagine sopra mostra lo stato non riprodotto
L'immagine sopra mostra lo stato di riproduzione
L'immagine sopra mostra lo stato di blocco schermo
Non dovrebbe esserci molto da aggiungere, per ora ci fermiamo. Se ci sono punti deboli, si può discutere nella sezione dei commenti sottostante, grazie per il supporto al tutorial di urla.