IOS_33 _ playing music (playing in the background + locking screen lyrics) and ios_33 locking Screen
Finally:
Application proxy (three-step background playback)
/// BeyondAppDelegate. h // 33 _ audio effect /// Created by beyond on 14-9-10. // Copyright (c) 2014 com. beyond. all rights reserved. // # import <UIKit/UIKit. h> @ interface BeyondAppDelegate: UIResponder <UIApplicationDelegate> @ property (strong, nonatomic) UIWindow * window; @ end
/// BeyondAppDelegate. m // 33 _ sound effect /// Created by beyond on 14-9-10. // Copyright (c) 2014 com. beyond. all rights reserved. // # import "BeyondAppDelegate. h "@ implementation BeyondAppDelegate-(BOOL) application :( UIApplication *) application didfinishlaunchingwitexceptions :( NSDictionary *) launchOptions {// Override point for customization after application launch. return YES;}-(void) applicationDidEnterBackground :( UIApplication *) application {// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. // one of the three steps for background playback: run the application in the background [application beginBackgroundTaskWithExpirationHandler: nil];} @ end
Controller
//// SongController. h // 33 _ audio effect /// Created by beyond on 14-9-10. // Copyright (c) 2014 com. beyond. all rights reserved. // The music playback controller inherited from tableViewCtrl # import <UIKit/UIKit. h> @ interface SongController: UITableViewController @ end
//// SongController. m // 33 _ sound effect /// Created by beyond on 14-9-10. // Copyright (c) 2014 com. beyond. all rights reserved. // The music playback controller inherited from tableViewCtrl # import "SongController. h "// core framework, which must be imported. The screen lock display lyrics # import <AVFoundation/AVFoundation. h> # import <MediaPlayer/MediaPlayer. h> // model # import "Song. h "// view # import" SongCell. h "// tool # import" SongTool. h "# pragma mark-class extension @ interface SongController () <AVAudioPlayerDelegate> // Object array @ property (strong, nonatomic) NSArray * songArr; // The Player corresponding to the currently selected row (not used currently) @ property (nonatomic, strong) AVAudioPlayer * currentPlayingAudioPlayer; // In the player proxy method, the method for listening to the playing progress of a song is not available. // you can only enable a timer to listen to the playing progress of a song in real time @ property (nonatomic, strong) CADisplayLink * link;-(IBAction) jump :( id) sender; @ end @ implementation SongController-(void) viewDidLoad {[super viewDidLoad]; // prevent self from being covered by the navigation bar. tableView. contentInset = UI EdgeInsetsMake (20, 0, 0, 0) ;}# pragma mark-lazy loading-(NSArray *) songArr {if (! _ SongArr) {// classification method, one-step conversion to object array self. songArr = [Song objectArrayWithFilename: @ "SongArr. plist "];} return _ songArr;} // In the player proxy method, there is no method for listening to the playing progress of a song. // you can only enable one timer on your own, monitors the playing progress of a song in real time-(CADisplayLink *) link {if (! _ Link) {self. link = [CADisplayLink displayLinkWithTarget: self selector: @ selector (update)];} return _ link ;}# pragma mark-clock method // proxy method of the player, no method for listening to the playing progress of a song // you can only enable a timer to listen to the playing progress of the song in real time // real-time update (60 calls in 1 second)-(void) update {// NSLog (@ "total length: % f current playback: % f", self. currentPlayingAudioPlayer. duration, self. currentPlayingAudioPlayer. currentTime); # adjust the lyrics of the lock screen in warning} # pragma mark-connection method-(IBAction) jump :( id) sender {// control the playback progress (single Bit: Second) self. currentPlayingAudioPlayer. currentTime = self. currentPlayingAudioPlayer. duration-3 ;}# pragma mark-AVAudioPlayer proxy method // call it when the playing is complete, stop the animation, and jump to the next playback-(void) audioPlayerDidFinishPlaying :( AVAudioPlayer *) player successfully :( BOOL) flag {// 1. first, you need to calculate the row number of the song that has been played. Use this line to calculate the row number of the next line (cross-border protection) NSIndexPath * selectedPath = [self. tableView indexPathForSelectedRow]; int nextRow = selectedPath. row + 1; if (nextRow = se Lf. songArr. count) {nextRow = 0;} // 2. stop the circle of the last song (modify the model and pass the model to the custom cell again) SongCell * cell = (SongCell *) [self. tableView cellForRowAtIndexPath: selectedPath]; Song * music = self. songArr [selectedPath. row]; music. playing = NO; // The setter method is intercepted internally and the Animation cell is stopped. music = music; // 3. play the next song (select and scroll to the corresponding location) NSIndexPath * nextPath = [NSIndexPath indexPathForRow: nextRow inSection: selectedPath. section]; // select [self. TableView selectRowAtIndexPath: nextPath animated: YES scrollPosition: UITableViewScrollPositionTop]; // manually call the proxy method [self tableView: self. tableView didSelectRowAtIndexPath: nextPath] ;}# The pragma mark is interrupted and restored. // The audio player is interrupted (such as starting a call or answering a phone call)-(void) audioPlayerBeginInterruption :( AVAudioPlayer *) player {// do nothing will be automatically suspended... NSLog (@ "audioPlayerBeginInterruption --- interrupted");} // audio player interruption termination (such as End call and answer phone call)-(void) audioPlayerEndI Nterruption :( AVAudioPlayer *) player witexceptions :( NSUInteger) flags {// manually Resume playback [player play]; NSLog (@ "audioPlayerEndInterruption --- interrupt termination ");} # pragma mark-Data Source // number of rows-(NSInteger) tableView :( UITableView *) tableView numberOfRowsInSection :( NSInteger) section {return self. songArr. count;} // unique cell for each row (passing the model to a custom cell)-(UITableViewCell *) tableView :( UITableView *) tableView cellForRowAtIndexPath :( NSIndexPath *) IndexPath {// 1. customize cell class methods to quickly create cell SongCell * cell = [SongCell cellWithTableView: tableView]; // 2. set the cell data source cell. music = self. songArr [indexPath. row]; // 3. return the generated and filled cell return cell;} // The height of each row-(CGFloat) tableView :( UITableView *) tableView heightForRowAtIndexPath :( NSIndexPath *) indexPath {return 70 ;} # pragma mark-proxy method // select a row and play the corresponding music-(void) tableView :( UITableView *) tableView didSelectRowAtIndexPa Th :( NSIndexPath *) indexPath {// 1. obtain the model corresponding to the row and modify the isPlaying attribute Song * music = self. songArr [indexPath. row]; if (music. isPlaying) {return;} // attribute [Playing] value: true music. playing = YES; // 2. pass the data source model to the tool class to play music AVAudioPlayer * audioPlayer = [SongTool playMusic: music. filename]; audioPlayer. delegate = self; self. currentPlayingAudioPlayer = audioPlayer; // 3. important ~~~ Display the song information on the screen lock page [self showInfoInLockedScreen: music]; // 4. enable the timer to listen to the playback progress (first disable the old one) [self. link invalidate]; self. link = nil; [self. link addToRunLoop: [nsunloop mainRunLoop] forMode: NSDefaultRunLoopMode]; // 5. re-pass the data source model to the custom cell (executing the circled animation) SongCell * cell = (SongCell *) [tableView cellForRowAtIndexPath: indexPath]; cell. music = music;} // when a row is deselected, stop the music. animation-(void) tableView :( UITableView *) tableView didDeselectRowAtIndexPath :( NSIndexPath *) indexPath {// 1. obtain the model corresponding to the row and modify the isPlaying attribute Song * music = self. songArr [indexPath. row]; music. playing = NO; // 2. based on the music name, stop the music (which will be traversed internally) [SongTool stopMusic: music. filename]; // 3. re-pass the data source model to the custom cell (stop the circle) SongCell * cell = (SongCell *) [tableView cellForRowAtIndexPath: indexPath]; cell. music = music;} # pragma mark-display the lyrics on the screen lock // display the song information on the screen lock page (Real-time change of the image MPMediaItemArtwork can achieve real-time change of the lyrics)-(void) showInfoInLockedScreen :( Song *) music {// Robustness: if this class exists, the lyrics if (NSClassFromString (@ "MPNowPlayingInfoCenter") can be displayed when the screen is locked {// core: dictionary NSMutableDictionary * info = [NSMutableDictionary dictionary]; // Title (music name) info [MPMediaItemPropertyTitle] = music. name; // artist info [MPMediaItemPropertyArtist] = music. singer; // album name info [MPMediaItemPropertyAlbumTitle] = music. singer; // image info [MPMediaItemPropertyArtwork] = [[MPMediaItemArtwork alloc] initWithImage: [UIImage imageNamed: music. icon]; // Unique API, Singleton, nowPlayingInfo dictionary [MPNowPlayingInfoCenter defaultCenter]. nowPlayingInfo = info; }}@ end
Model
/// Song. h // 33 _ audio effect /// Created by beyond on 14-9-10. // Copyright (c) 2014 com. beyond. all rights reserved. // model, a song with many members # import <Foundation/Foundation. h> @ interface Song: NSObject // Song name @ property (copy, nonatomic) NSString * name; // file name, for example, @ "a.mp3" @ property (copy, nonatomic) NSString * filename; // artist @ property (copy, nonatomic) NSString * singer; // artist profile @ property (copy, nonatomic) NSString * singerIcon; // artist's big picture (used when locking screen) @ property (copy, nonatomic) NSString * icon; // tag, used to rotate the Avatar @ property (nonatomic, assign, getter = isPlaying) BOOL playing; @ end
Custom View SongCell
//// SongCell. h // 33 _ audio effect /// Created by beyond on 14-9-10. // Copyright (c) 2014 com. beyond. all rights reserved. // View, custom cell, dependent model # import <UIKit/UIKit. h> // View depends on the Model @ class Song; @ interface SongCell: UITableViewCell // Data Source Model @ property (nonatomic, strong) Song * music; // The controller knows the least + (instancetype) cellWithTableView :( UITableView *) tableView; @ end
//// SongCell. m // 33 _ sound effect /// Created by beyond on 14-9-10. // Copyright (c) 2014 com. beyond. all rights reserved. // View, custom cell, dependent model # import "SongCell. h "// model, data source # import" Song. h "# import" Colours. h "# pragma mark-class extension @ interface SongCell () // used for rotating the Avatar CGAffineTransformRotate, 45 degrees per second @ property (nonatomic, strong) CADisplayLink * link; @ end @ implementation SongCell # pragma mark-lazy loading-(CADisplayLink *) link {I F (! _ Link) {self. link = [CADisplayLink displayLinkWithTarget: self selector: @ selector (update)];} return _ link ;}# pragma mark-for external calls + (instancetype) cellWithTableView :( UITableView *) tableView {static NSString * ID = @ "music"; SongCell * cell = [tableView dequeueReusableCellWithIdentifier: ID]; if (cell = nil) {cell = [[SongCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: ID];} return cell;} // intercept the setter method, assign values to the internal sub-control, and perform a circled animation-(void) setMusic :( Song *) music {_ music = music; // set unique data self. textLabel. text = music. name; self. detailTextLabel. text = music. singer; // classification method to create a circle border self. imageView. image = [UIImage circleImageWithName: music. singerIcon borderWidth: 2 borderColor: [UIColor skyBlueColor]; // if the model attribute isPlaying is true, start CGAffineTransformRotate if (music. isPlaying) {[self. link addToRunLoop: [nsunloop mainRunLoop] forMode: NSDefaultRunLoopMode];} else {// If the isPlaying of the model is false, stop the clock animation and set CGAffineTransformRotate to zero [self. link invalidate]; self. link = nil; self. imageView. transform = CGAffineTransformIdentity) update {// deltaAngle = 1/60 seconds * 45 // rotation angle between two calls = time * speed CGFloat angle = self. link. duration * M_PI_4; // core animation is not required, because after entering the background, the animation stops self. imageView. transform = CGAffineTransformRotate (self. imageView. transform, angle) ;}@ end
Music Playing Tool
//// SongTool. h // 33 _ audio effect /// Created by beyond on 14-9-10. // Copyright (c) 2014 com. beyond. all rights reserved. // # import <Foundation/Foundation. h> // music tool class. You must import the main header file of AVFoundation # import <AVFoundation/AVFoundation. h> @ interface SongTool: NSObject // class method, playing music, parameter: music file name such as @ "a.mp3", in order to set proxy for the player AVAudioPlayer object, after creating a Player Object, return it to the caller // After setting the proxy, you can listen to the player being interrupted and resume interruption + (AVAudioPlayer *) playMusic :( NSString *) filename; // class method, pause music, parameter: music file name such as @ "a.mp3" + (void) pauseMusic :( NSString *) filename; // class method, stop music, parameter: for example, if the music file name is @ "a.mp3", remember to remove + (void) stopMusic :( NSString *) filename from the dictionary; // return the currently playing music player, so that you can control it quickly, back or other methods + (AVAudioPlayer *) currentPlayingAudioPlayer; @ end
//// SongTool. m // 33 _ sound effect /// Created by beyond on 14-9-10. // Copyright (c) 2014 com. beyond. all rights reserved. // # import "SongTool. h "@ implementation SongTool // dictionary, which stores all music players. The key is: music name, the value is the corresponding music player object audioPlayer // a song corresponds to a music player static NSMutableDictionary * _ audioPlayerDict; # pragma mark-Life Cycle + (void) initialize {// dictionary, key: music name. The value is the corresponding music player object _ audioPlayerDict = [NSMutableDictionary dictionary]; // sets the background playback function [s Elf suupforbackgroundplay];} // set the background playing + (void) sutuforbackgroundplay {// step 3 of playing the three steps in the background, set the audio session type AVAudioSession * session = [AVAudioSession sharedInstance]; // type: Playing and recording. [session setCategory: AVAudioSessionCategoryPlayAndRecord error: nil]; // You must activate the audio session. [session setActive: YES error: nil];} # pragma mark-for external calls // class method, playing music, parameter: music file name such as @ "a.mp3" // At the same time, in order to be able to set a proxy for the player AVAudioPlayer object, after creating a Player Object, return it to the caller // After setting the proxy, you can Player interruption and restoration interrupt + (AVAudioPlayer *) playMusic :( NSString *) filename {// robustness judgment if (! Filename) return nil; // 1. First, extract the corresponding audioPlayer AVAudioPlayer * audioPlayer = _ audioPlayerDict [filename] from the dictionary based on the music file name; if (! AudioPlayer) {// if no music player exists, create the corresponding music player and save it to the dictionary. // 1.1 load the music file NSURL * url = [[NSBundle mainBundle] URLForResource: filename withExtension: nil]; // determine if (! Url) return nil; // 1.2 Based on the music URL, create the corresponding audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: url error: nil]; // 1.3 start buffering [audioPlayer prepareToPlay]; // if you want to achieve variable speed playback, you must set the following two parameters at the same time // audioPlayer. enableRate = YES; // audioPlayer. rate = 10.0; // 1.4, put it into the dictionary _ audioPlayerDict [filename] = audioPlayer;} // 2. if it is paused or stopped, you need to start playing if (! AudioPlayer. isPlaying) {[audioPlayer play];} // 3. return to the created player, so that the caller can set the proxy and listen to the player progress currentTime return audioPlayer;} // class method to pause the music. Parameter: music file name, such as @ "a.mp3" + (void) pauseMusic :( NSString *) filename {// robustness judgment if (! Filename) return; // 1. first, extract audioPlayer [value] AVAudioPlayer * audioPlayer = _ audioPlayerDict [filename] from the dictionary according to the key [file name]; // 2. if you are playing a video, you need to pause if (audioPlayer. isPlaying) {[audioPlayer pause] ;}// class method to stop music. Parameter: music file name, for example, @ "a.mp3". Remember to remove it from the dictionary + (void) stopMusic :( NSString *) filename {// robustness judgment if (! Filename) return; // 1. first, extract audioPlayer [value] AVAudioPlayer * audioPlayer = _ audioPlayerDict [filename] from the dictionary according to the key [file name]; // 2. to stop if (audioPlayer. isPlaying) {// 2.1 stop [audioPlayer stop]; // 2.2 Finally, remember to remove [_ audioPlayerDict removeObjectForKey: filename] from the dictionary;} // return the current playing music player to facilitate external control of the player's fast forward, backward, or other methods + (AVAudioPlayer *) currentPlayingAudioPlayer {// traverse the dictionary key and then retrieve the value based on the key, if it is playing, the player for (NSString * filename in _ audioPlayerDict) {AVAudioPlayer * audioPlayer = _ audioPlayerDict [filename]; if (audioPlayer. isPlaying) {return audioPlayer;} return nil;} @ end
Classification of images with circle borders
/// UIImage + Circle. h // 33 _ sound effect /// Created by beyond on 14-9-15. // Copyright (c) 2014 com. beyond. all rights reserved. // circular border # import <UIKit/UIKit. h> @ interface UIImage (Circle) + (instancetype) circleImageWithName :( NSString *) name borderWidth :( CGFloat) borderWidth borderColor :( UIColor *) borderColor; @ end
/// UIImage + Circle. m // 33 _ sound effect /// Created by beyond on 14-9-15. // Copyright (c) 2014 com. beyond. all rights reserved. // # import "UIImage + Circle. h "@ implementation UIImage (Circle) + (instancetype) circleImageWithName :( NSString *) name borderWidth :( CGFloat) borderWidth borderColor :( UIColor *) borderColor {// 1. load the source image UIImage * oldImage = [UIImage imageNamed: name]; // 2. enable the context CGFloat imageW = oldImage. size. width + 2 * borderWidth; CGFloat imageH = oldImage. size. height + 2 * borderWidth; CGSize imageSize = CGSizeMake (imageW, imageH); uigraphicsbeginimagecontextwitexceptions (imageSize, NO, 0.0); // 3. obtain the current context CGContextRef ctx = UIGraphicsGetCurrentContext (); // 4. border (large circle) [borderColor set]; CGFloat bigRadius = imageW * 0.5; // large circle radius CGFloat centerX = bigRadius; // center CGFloat centerY = bigRadius; CGContextAddArc (ctx, centerX, centerY, bigRadius, 0, M_PI * 2, 0); CGContextFillPath (ctx); // circle // 5. small Round CGFloat smallRadius = bigRadius-borderWidth; CGContextAddArc (ctx, centerX, centerY, smallRadius, 0, M_PI * 2, 0 ); // crop (the things drawn after the cropping will be affected) CGContextClip (ctx); // 6. drawing [oldImage drawInRect: CGRectMake (borderWidth, borderWidth, oldImage. size. width, oldImage. size. height)]; // 7. figure UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext (); // 8. end context UIGraphicsEndImageContext (); return newImage ;}@ end
The music player on the mobile phone has a unique lock screen, and there are lyrics on the desktop.
Beautiful every day
After the screen lock, the screen is displayed in full screen, with song name + artist + album displayed.
Desktop lyrics can be set separately.
-----------------------------------------------------
The following is an excerpt from Baidu encyclopedia.
The beautiful mobile phone edition is a powerful and completely free mobile phone music playing software. [3] It supports downloading lyrics and Song pictures, changing skin as you like, and more dazzling visual effects, at the same time, a wide range of Preset balancer effects are provided, supporting enhanced sound effects and simple and user-friendly operations, bringing a brand new experience of listening to songs on mobile phones to the pursuit of music quality.
For details, see Baidu Baike: yitian Meimei mobile edition
The iphone music background is turned off, but after the screen is locked, double-click the home Key to see why the Playing Song still exists. Why?
This is normal, and Apple is trying to make it easier to play.