iOS_33_音乐播放(后台播放+锁屏歌词)

最终效果图:

应用程序代理(后台播放三步曲)

//
//  BeyondAppDelegate.h
//  33_音效
//
//  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_音效
//
//  Created by beyond on 14-9-10.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "BeyondAppDelegate.h"

@implementation BeyondAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(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.
    // 后台播放三步骤之一:让应用在后台运行
    [application beginBackgroundTaskWithExpirationHandler:nil];
}

@end

控制器

//
//  SongController.h
//  33_音效
//
//  Created by beyond on 14-9-10.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  音乐播放控制器,继承自tableViewCtrl

#import <UIKit/UIKit.h>

@interface SongController : UITableViewController

@end

//
//  SongController.m
//  33_音效
//
//  Created by beyond on 14-9-10.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  音乐播放控制器,继承自tableViewCtrl

#import "SongController.h"
// 核心框架,必须导入,锁屏显歌词
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>

// 模型
#import "Song.h"
// 视图
#import "SongCell.h"
// 工具
#import "SongTool.h"

#pragma mark - 类扩展

@interface SongController () <AVAudioPlayerDelegate>

// 对象数组
@property (strong, nonatomic) NSArray *songArr;
// 当前选中的那一行所对应的播放器(暂没用到)
@property (nonatomic, strong) AVAudioPlayer *currentPlayingAudioPlayer;

// 播放器的代理方法中,没有监听歌曲播放进度的方法
// 只能自己 开一个定时器,实时监听歌曲的播放进度
@property (nonatomic, strong) CADisplayLink *link;

- (IBAction)jump:(id)sender;
@end

@implementation SongController
- (void)viewDidLoad
{
    [super viewDidLoad];
    // 防止被导航栏盖住
    self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0);
}
#pragma mark - 懒加载
- (NSArray *)songArr
{
    if (!_songArr) {
        // 分类方法,一步转对象数组
        self.songArr = [Song objectArrayWithFilename:@"SongArr.plist"];
    }
    return _songArr;
}
// 播放器的代理方法中,没有监听歌曲播放进度的方法
// 只能自己 开一个定时器,实时监听歌曲的播放进度
- (CADisplayLink *)link
{
    if (!_link) {
        self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)];
    }
    return _link;
}

#pragma mark - 时钟方法
// 播放器的代理方法中,没有监听歌曲播放进度的方法
// 只能自己 开一个定时器,实时监听歌曲的播放进度
//  实时更新(1秒中调用60次)
- (void)update
{
    //    NSLog(@"总长:%f 当前播放:%f", self.currentPlayingAudioPlayer.duration, self.currentPlayingAudioPlayer.currentTime);
#warning 调整锁屏时的歌词
}

#pragma mark - 连线方法
- (IBAction)jump:(id)sender
{
    // 控制播放进度(单位:秒)
    self.currentPlayingAudioPlayer.currentTime = self.currentPlayingAudioPlayer.duration - 3;
}

#pragma mark - AVAudioPlayer代理方法
// 一曲播放完毕时调用,停止动画,并跳至下一首播放
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
    // 1.先得当前播放完毕的这首歌的行号,通过它,计算下一行的行号(防越界)
    NSIndexPath *selectedPath = [self.tableView indexPathForSelectedRow];
    int nextRow = selectedPath.row + 1;
    if (nextRow == self.songArr.count) {
        nextRow = 0;
    }

    // 2.停止上一首歌的转圈 (修改模型,并再次传递模型给自定义cell)
    SongCell *cell = (SongCell *)[self.tableView cellForRowAtIndexPath:selectedPath];
    Song *music = self.songArr[selectedPath.row];
    music.playing = NO;
    // 内部会拦截setter方法,并停止转圈动画
    cell.music = music;

    // 3.播放下一首歌 (选中并滚动至对应位置)
    NSIndexPath *nextPath = [NSIndexPath indexPathForRow:nextRow inSection:selectedPath.section];
    // 界面上选中
    [self.tableView selectRowAtIndexPath:nextPath animated:YES scrollPosition:UITableViewScrollPositionTop];
    // 手动调用代理方法
    [self tableView:self.tableView didSelectRowAtIndexPath:nextPath];
}

#pragma mark 播放被打断和恢复
//  音乐播放器被打断 (如开始 打、接电话)
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
{
    // 会自动暂停  do nothing ...
    NSLog(@"audioPlayerBeginInterruption---被打断");
}

//  音乐播放器打断终止 (如结束 打、接电话)
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flags
{
    // 手动恢复播放
    [player play];
    NSLog(@"audioPlayerEndInterruption---打断终止");
}

#pragma mark - 数据源
// 多少行
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.songArr.count;
}
// 每一行独一无二的的cell (给自定义cell传递模型)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 1.自定义cell的类方法,快速创建cell
    SongCell *cell = [SongCell cellWithTableView:tableView];

    // 2.设置cell的数据源
    cell.music = self.songArr[indexPath.row];

    // 3.返回生成并填充好的cell
    return cell;
}
// 每一行的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 70;
}
#pragma mark - 代理方法

// 选中一行,播放对应的音乐
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 1.取得该行对应的模型,并修改其isPlaying属性
    Song *music = self.songArr[indexPath.row];
    if (music.isPlaying) {
        return;
    }

    // 属性【正在播放】赋值为真
    music.playing = YES;
    // 2.传递数据源模型 给工具类播放音乐
    AVAudioPlayer *audioPlayer = [SongTool playMusic:music.filename];
    audioPlayer.delegate = self;
    self.currentPlayingAudioPlayer = audioPlayer;

    // 3.重要~~~在锁屏界面显示歌曲信息
    [self showInfoInLockedScreen:music];

    // 4.开启定时器,监听播放进度 (先关闭旧的)
    [self.link invalidate];
    self.link = nil;
    [self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

    // 5.再次传递数据源模型 给自定义cell(执行转圈动画)
    SongCell *cell = (SongCell *)[tableView cellForRowAtIndexPath:indexPath];
    cell.music = music;
}
// 取消选中一行时,停止音乐,动画
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 1.取得该行对应的模型,并修改其isPlaying属性
    Song *music = self.songArr[indexPath.row];
    music.playing = NO;

    // 2.根据音乐名,停止音乐(内部会遍历)
    [SongTool stopMusic:music.filename];

    // 3.再次传递数据源模型 给自定义cell(停止转圈)
    SongCell *cell = (SongCell *)[tableView cellForRowAtIndexPath:indexPath];
    cell.music = music;
}

#pragma mark - 锁屏显歌词
// 在锁屏界面显示歌曲信息(实时换图片MPMediaItemArtwork可以达到实时换歌词的目的)
- (void)showInfoInLockedScreen:(Song *)music
{
    // 健壮性写法:如果存在这个类,才能在锁屏时,显示歌词
    if (NSClassFromString(@"MPNowPlayingInfoCenter")) {
        // 核心:字典
        NSMutableDictionary *info = [NSMutableDictionary dictionary];

        // 标题(音乐名称)
        info[MPMediaItemPropertyTitle] = music.name;

        // 艺术家
        info[MPMediaItemPropertyArtist] = music.singer;

        // 专辑名称
        info[MPMediaItemPropertyAlbumTitle] = music.singer;

        // 图片
        info[MPMediaItemPropertyArtwork] = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:music.icon]];
        // 唯一的API,单例,nowPlayingInfo字典
        [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = info;
    }
}
@end

模型Model

//
//  Song.h
//  33_音效
//
//  Created by beyond on 14-9-10.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  模型,一首歌曲,成员很多

#import <Foundation/Foundation.h>

@interface Song : NSObject
// 歌名
@property (copy, nonatomic) NSString *name;
// 文件名,如@"a.mp3"
@property (copy, nonatomic) NSString *filename;
// 艺术家
@property (copy, nonatomic) NSString *singer;
// 艺术家头像
@property (copy, nonatomic) NSString *singerIcon;
// 艺术家大图片(锁屏的时候用)
@property (copy, nonatomic) NSString *icon;
// 标记,用于转动头像
@property (nonatomic, assign, getter = isPlaying) BOOL playing;

@end

自定义View   SongCell

//
//  SongCell.h
//  33_音效
//
//  Created by beyond on 14-9-10.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  View,自定义cell,依赖模型

#import <UIKit/UIKit.h>

// View 需依赖模型
@class Song;
@interface SongCell : UITableViewCell

// 数据源模型
@property (nonatomic, strong) Song *music;

// 控制器知道得最少
+ (instancetype)cellWithTableView:(UITableView *)tableView;
@end

//
//  SongCell.m
//  33_音效
//
//  Created by beyond on 14-9-10.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  View,自定义cell,依赖模型

#import "SongCell.h"

// 模型,数据源
#import "Song.h"
#import "Colours.h"

#pragma mark - 类扩展
@interface SongCell ()
// 用于 头像的旋转 CGAffineTransformRotate,一秒钟转45度
@property (nonatomic, strong) CADisplayLink *link;
@end

@implementation SongCell
#pragma mark - 懒加载
- (CADisplayLink *)link
{
    if (!_link) {
        self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)];
    }
    return _link;
}
#pragma mark - 供外界调用
+ (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;
}
// 拦截setter方法,为内部子控件赋值,并进行转圈动画
- (void)setMusic:(Song *)music
{
    _music = music;
    // 设置独一无二的数据
    self.textLabel.text = music.name;
    self.detailTextLabel.text = music.singer;
    // 分类方法,创建一个圆形的边框
    self.imageView.image = [UIImage circleImageWithName:music.singerIcon borderWidth:2 borderColor:[UIColor skyBlueColor]];
    // 如果模型的属性isPlaying为真,则开始CGAffineTransformRotate
    if (music.isPlaying) {
        [self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    } else {
        // 如果模型的isPlaying为假,则停止时钟动画,并将CGAffineTransformRotate归零
        [self.link invalidate];
        self.link = nil;
        self.imageView.transform = CGAffineTransformIdentity;
    }
}

#pragma mark - 时钟方法
// 角速度 :  45°/s  ,即8秒转一圈
- (void)update
{
    // deltaAngle = 1/60秒 * 45
    // 两次调用之间 转动的角度 == 时间 * 速度
    CGFloat angle = self.link.duration * M_PI_4;
    // 不用核心动画,是因为 进入后台之后,动画就停止了
    self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, angle);
}
@end

音乐播放工具类

//
//  SongTool.h
//  33_音效
//
//  Created by beyond on 14-9-10.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import <Foundation/Foundation.h>
// 音乐工具类,必须导入AVFoundation的主头文件
#import <AVFoundation/AVFoundation.h>

@interface SongTool : NSObject

// 类方法, 播放音乐,  参数:音乐文件名 如@"a.mp3",同时为了能够给播放器AVAudioPlayer对象设置代理,在创建好播放器对象后,将其返回给调用者
// 设置代理后,可以监听播放器被打断和恢复打断
+ (AVAudioPlayer *)playMusic:(NSString *)filename;

// 类方法, 暂停音乐,  参数:音乐文件名 如@"a.mp3"
+ (void)pauseMusic:(NSString *)filename;

// 类方法, 停止音乐,  参数:音乐文件名 如@"a.mp3",记得从字典中移除
+ (void)stopMusic:(NSString *)filename;

// 返回当前正在播放的音乐播放器,方便外界控制其快进,后退或其他方法
+ (AVAudioPlayer *)currentPlayingAudioPlayer;

@end

//
//  SongTool.m
//  33_音效
//
//  Created by beyond on 14-9-10.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "SongTool.h"

@implementation SongTool
// 字典,存放所有的音乐播放器,键是:音乐名,值是对应的音乐播放器对象audioPlayer
// 一首歌对应一个音乐播放器
static NSMutableDictionary *_audioPlayerDict;

#pragma mark - Life Cycle
+ (void)initialize
{
    // 字典,键是:音乐名,值是对应的音乐播放器对象
    _audioPlayerDict = [NSMutableDictionary dictionary];

    // 设置后台播放
    [self sutupForBackgroundPlay];
}

// 设置后台播放
+ (void)sutupForBackgroundPlay
{
    // 后台播放三步曲之第三步,设置 音频会话类型
    AVAudioSession *session = [AVAudioSession sharedInstance];
    // 类型是:播放和录音
    [session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
    // 而且要激活 音频会话
    [session setActive:YES error:nil];
}

#pragma mark - 供外界调用
// 类方法, 播放音乐,  参数:音乐文件名 如@"a.mp3"
// 同时为了能够给播放器AVAudioPlayer对象设置代理,在创建好播放器对象后,将其返回给调用者
// 设置代理后,可以监听播放器被打断和恢复打断
+ (AVAudioPlayer *)playMusic:(NSString *)filename
{
    // 健壮性判断
    if (!filename) return nil;

    // 1.先从字典中,根据音乐文件名,取出对应的audioPlayer
    AVAudioPlayer *audioPlayer = _audioPlayerDict[filename];
    if (!audioPlayer) {
        // 如果没有,才需创建对应的音乐播放器,并且存入字典
        // 1.1加载音乐文件
        NSURL *url = [[NSBundle mainBundle] URLForResource:filename withExtension:nil];
        // 健壮性判断
        if (!url) return nil;

        // 1.2根据音乐的URL,创建对应的audioPlayer
        audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];

        // 1.3开始缓冲
        [audioPlayer prepareToPlay];
        // 如果要实现变速播放,必须同时设置下面两个参数
        //        audioPlayer.enableRate = YES;
        //        audioPlayer.rate = 10.0;

        // 1.4最后,放入字典
        _audioPlayerDict[filename] = audioPlayer;
    }

    // 2.如果是暂停或停止时,才需要开始播放
    if (!audioPlayer.isPlaying) {
        [audioPlayer play];
    }
    // 3.返回创建好的播放器,方便调用者设置代理,监听播放器的进度currentTime
    return audioPlayer;
}

// 类方法, 暂停音乐,  参数:音乐文件名 如@"a.mp3"
+ (void)pauseMusic:(NSString *)filename
{
    // 健壮性判断
    if (!filename) return;

    // 1.先从字典中,根据key【文件名】,取出audioPlayer【肯定 有 值】
    AVAudioPlayer *audioPlayer = _audioPlayerDict[filename];

    // 2.如果是正在播放,才需要暂停
    if (audioPlayer.isPlaying) {
        [audioPlayer pause];
    }
}

// 类方法, 停止音乐,  参数:音乐文件名 如@"a.mp3",记得从字典中移除
+ (void)stopMusic:(NSString *)filename
{
    // 健壮性判断
    if (!filename) return;

    // 1.先从字典中,根据key【文件名】,取出audioPlayer【肯定 有 值】
    AVAudioPlayer *audioPlayer = _audioPlayerDict[filename];

    // 2.如果是正在播放,才需要停止
    if (audioPlayer.isPlaying) {
        // 2.1停止
        [audioPlayer stop];

        // 2.2最后,记得从字典中移除
        [_audioPlayerDict removeObjectForKey:filename];
    }
}

// 返回当前正在播放的音乐播放器,方便外界控制其快进,后退或其他方法
+ (AVAudioPlayer *)currentPlayingAudioPlayer
{
    // 遍历字典的键,再根据键取出值,如果它是正在播放,则返回该播放器
    for (NSString *filename in _audioPlayerDict) {
        AVAudioPlayer *audioPlayer = _audioPlayerDict[filename];

        if (audioPlayer.isPlaying) {
            return audioPlayer;
        }
    }

    return nil;
}

@end

图片加圆圈边框的分类

//
//  UIImage+Circle.h
//  33_音效
//
//  Created by beyond on 14-9-15.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  圆形边框

#import <UIKit/UIKit.h>

@interface UIImage (Circle)

+ (instancetype)circleImageWithName:(NSString *)name borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor;

@end

//
//  UIImage+Circle.m
//  33_音效
//
//  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.加载原图
    UIImage *oldImage = [UIImage imageNamed:name];

    // 2.开启上下文
    CGFloat imageW = oldImage.size.width + 2 * borderWidth;
    CGFloat imageH = oldImage.size.height + 2 * borderWidth;
    CGSize imageSize = CGSizeMake(imageW, imageH);
    UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0);

    // 3.取得当前的上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // 4.画边框(大圆)
    [borderColor set];
    CGFloat bigRadius = imageW * 0.5; // 大圆半径
    CGFloat centerX = bigRadius; // 圆心
    CGFloat centerY = bigRadius;
    CGContextAddArc(ctx, centerX, centerY, bigRadius, 0, M_PI * 2, 0);
    CGContextFillPath(ctx); // 画圆

    // 5.小圆
    CGFloat smallRadius = bigRadius - borderWidth;
    CGContextAddArc(ctx, centerX, centerY, smallRadius, 0, M_PI * 2, 0);
    // 裁剪(后面画的东西才会受裁剪的影响)
    CGContextClip(ctx);

    // 6.画图
    [oldImage drawInRect:CGRectMake(borderWidth, borderWidth, oldImage.size.width, oldImage.size.height)];

    // 7.取图
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

    // 8.结束上下文
    UIGraphicsEndImageContext();

    return newImage;
}
@end

时间: 2024-10-13 01:32:54

iOS_33_音乐播放(后台播放+锁屏歌词)的相关文章

轻仿QQ音乐之音频歌词播放、锁屏歌词-b

先上效果图 歌词播放界面 音乐播放界面 锁屏歌词界面 一. 项目概述 前面内容实在是太基础..只想看知识点的同学可以直接跳到第三部分的干货 项目播放的mp3文件及lrc文件均来自QQ音乐 本文主要主要讲解锁屏歌词的实现,音频.歌词的播放网上资源略多,因此不做重点讲解,项目也是采取最简单的MVC+storyboard方式 项目GitHub地址: https://github.com/PengfeiWang666/WPFMusicPlayer 音乐模型-->WPFMusic /** 图片 */ @p

AVPlayer 音乐播放后台播放,以及锁屏主题设置

第一步:在appDelegate中通知app支持后台播放:在方法 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {} 中添加如下代码: AVAudioSession *audioSession = [AVAudioSession sharedInstance]; //默认情况下扬声器播放 [audioSession setCa

iOS开发--QQ音乐练习,后台播放和锁屏界面

一.设置后台播放 首先允许程序后台播放 代码实现 1 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 2 3 // 设置后台播放的代码,步骤 4 // 1.获取音频的会话 5 AVAudioSession *session = [AVAudioSession sharedInstance]; 6 // 2.设置后台播放类型

iOS音乐后台播放及锁屏信息显示

实现音乐的后台播放.以及播放时,能够控制其暂停,下一首等操作,以及锁屏图片歌曲名等的显示 此实例须要真机调试.效果图例如以下: project下载:githubproject下载 实现步骤: 1.首先改动info.plist 2.其次引入两个须要的框架 #import <AVFoundation/AVFoundation.h> #import <MediaPlayer/MediaPlayer.h> 3.设置播放器及后台播放 - (void)viewDidLoad { [super

音乐锁屏播放

1.首先要音乐支持后台播放 (1)在info.plist中添加 Required background modes item 0 : App plays audio or streams audio/video using AirPlay (2)设置AVAudioSession: AVAudioSession *session = [AVAudioSession sharedInstance]; [session setActive:YES error:nil]; [session setCat

swift锁屏播放,音乐进度更新,专辑,歌手名显示

我自己用的音乐播放器是自带的AVPlayer 导入头文件#import <MediaPlayer/MediaPlayer.h> 远程控制事件接收与处理- (void)viewWillAppear:(BOOL)animated{[super viewWillAppear:animated];[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];[self becomeFirstResponder];}-(voi

音乐类型APP:如何添加正播放的音乐进度,歌手名,图片等信息显示 到锁屏和控制中心

使用的是豆瓣的音频播放类 导入头文件#import <MediaPlayer/MediaPlayer.h> #import <MediaPlayer/MPNowPlayingInfoCenter.h> #import <MediaPlayer/MPMediaItem.h> 远程控制事件接收与处理- (void)viewWillAppear:(BOOL)animated{[super viewWillAppear:animated];[[UIApplication sha

Android 通话:后台通话过程中锁屏解锁,发现听筒内存在锁屏提示音

[系统版本]:T0316 [ HW ]:p1 [测试前提]:1.卡1插入移动4G卡 [测试步骤]:1.呼入或呼出一通来电,接听: 2.按home返回后台,锁屏解锁查看. [测试结果]:1.后台通话过程中锁屏解锁,发现听筒内存在锁屏提示音 [预期结果]:1.通话过程中不应存在锁屏提示音 [概 率]:必现 solution: 修改文件:./frameworks/av/services/audiopolicy/AudioPolicyManager.cpp status_t AudioPolicyMan

【腾讯Bugly干货分享】浅谈Android自定义锁屏页的发车姿势

本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57875330c9da73584b025873 一.为什么需要自定义锁屏页 锁屏作为一种黑白屏时代就存在的手机功能,至今仍发挥着巨大作用,特别是触屏时代的到来,锁屏的功用被发挥到了极致.多少人曾经在无聊的时候每隔几分钟划开锁屏再关上,孜孜不倦,其酸爽程度不亚于捏气泡膜.确实,一款漂亮的锁屏能为手机增色不少,但锁屏存在的核心目的主要是三个:保护自己手机的隐私,防止误操作,在不关闭