必发88唯一官网 > 88bifa必发唯一官网 > 前台服务播放音乐,拔耳机控制

原标题:前台服务播放音乐,拔耳机控制

浏览次数:123 时间:2019-12-01

iOS_33_前台服务播放音乐,拔耳机控制。音乐播放(后台播放 锁屏歌词卡塔尔

终极效果图: 图片 1
应用程序代理(后台播放三步曲卡塔尔(英语:State of Qatar)

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

#import 

@interface BeyondAppDelegate : UIResponder 

@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 

@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 
#import 

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



#pragma mark - 类扩展

@interface SongController () 

// 对象数组
@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 

@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 

// 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 
// 音乐工具类,必须导入AVFoundation的主头文件
#import 

@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 

@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

卡塔尔 最终效果图: 应用程序代理(后台播放三步曲卡塔尔(英语:State of Qatar) //// BeyondAppDelegate.h// 33_音效//// Created by beyond on 14-9-10.// C...

【Android】MediaPlayer生命周期剖判

前两步是后台播放所不可不安装的,第三步关键用来收纳远程事件,假诺这一步不设置虽让也能够在后台播放,但是不可能获得音频调整权(假诺在行使当前利用早先使用此外播放器播放音乐来说,那个时候假如按耳麦播放键也许调控大旨的播放开关则会播放前五个应用的音频),而且不能够选用耳麦举行音频调控。第一步操作相信大家都比较轻便精晓,假使应用程序要允许运维到后台必得设置,寻常状态下采纳即便步向后台会被挂起,通过该装置能够让应用程序继续在后台运转。

前边两篇随笔已经详细的表明了MediaPlayer的生命周期和平运动用手艺,而那篇文章叙述前台服务播放音乐的兑现。

前台服务

前台服务要动用到以下多个法子:

startForeground(int id, Notification notification)

其风度翩翩措施是运营Notification到前台,日常写在onCreate方法个中。

topForeground(boolean removeNotification)

其生机勃勃法子是终止Notification,平常写在onDestroy方法个中。

#######要想打开后台播放,须要两步

Notification通知

Notification是呈现在文告栏上的框架,平时用于体现通告类的音讯。

貌似景观下是经过NotificationCompat.Builder进行创办。通过NotificationManager进行关押,如撤销文告,更新公告等。可是要专一在开立Notification三要素不能够少,不然将会成立失利也许运维极度,Notification三要素:小Logo、标题、内容。不一样的机型显示的效率也会迥然分歧。

来得一个Notification:

Intent intent = new Intent(this, MainActivity.class);
PendingIntent contentPendingIntent = PendingIntent.getActivity(this, CONTENT_PENDINGINTENT_REQUESTCODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent delIntent = new Intent(this, MediaPlayerService.class);
PendingIntent delPendingIntent = PendingIntent.getService(this, DELETE_PENDINGINTENT_REQUESTCODE, delIntent, PendingIntent.FLAG_UPDATE_CURRENT);

Bitmap largeIcon = BitmapFactory.decodeResource(getResources(), R.drawable.test_bg);
// 初始化Notification,Notification三要素:小图标、标题、内容
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
          // 设置小图标,不展开时显示,当展开时现在在左侧
          .setSmallIcon(R.mipmap.ic_launcher)
          // 设置状态栏的显示的信息
          .setTicker("这是一个音频播放器")
          // 设置标题
          .setContentTitle("ZMediaPlayer")
          // 设置内容
          .setContentText("内容")
          // 设置通知时间,默认为系统发出通知的时间,通常不用设置
          .setWhen(System.currentTimeMillis())
          // 设置是否显示时间
          .setShowWhen(true)
          // 设置大图标-展开时一些手机上大图标会替换掉小图标
          .setLargeIcon(largeIcon)
          // 点击通知后自动清除
          .setAutoCancel(false)
          // 设置点击通知效果
          .setContentIntent(contentPendingIntent)
          // 设置删除时候出发的动作
          .setDeleteIntent(delPendingIntent)
          // 自定义视图
          .setContent(RemoteViews views)
          // 设置额外信息,一般显示在右下角
          .setContentInfo("额外信息")
          // 向通知添加声音、闪灯和振动效果的最简单、最一致的方式是使用当前的用户默认设置,使用defaults属性,可以组合 
          .setDefaults(Notification.DEFAULT_VIBRATE);

Notification notification = builder.build();
// 获取NotificationManager实例
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// 发送通知,并设置id
notificationManager.notify(id, notification);

修改Notification:

// 通过id进行更新Notification
notification = builder.setContentTitle("ZMediaPlayer111")
          // 设置内容
          .setContentText("内容111")
          .build();
notificationManager.notify(id, notification);

取消Notification:

// 通过id进行取消Notification
if (notificationManager != null)
    notificationManager.cancel(id);
收受远程事件

在appDelegate中的didFinishLaunchingWithOptions方法中加上:

[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

来收纳远程序调节制事件

接下来在viewController中,实现代理:

- remoteControlReceivedWithEvent:(UIEvent *)event { if(event.type==UIEventTypeRemoteControl){ switch (event.subtype) { case UIEventSubtypeRemoteControlPlay: [self.audioPlayer play]; break; case UIEventSubtypeRemoteControlPause: [self.audioPlayer pause]; break; case UIEventSubtypeRemoteControlStop: [self.audioPlayer stop]; break; case UIEventSubtypeRemoteControlTogglePlayPause: if (self.audioPlayer.isPlaying) { [self.audioPlayer pause]; }else{ [self.audioPlayer play]; } break; case UIEventSubtypeRemoteControlNextTrack: NSLog(@"Next..."); break; case UIEventSubtypeRemoteControlPreviousTrack: NSLog(@"Previous..."); break; case UIEventSubtypeRemoteControlBeginSeekingForward: NSLog(@"Begin seek forward..."); break; case UIEventSubtypeRemoteControlEndSeekingForward: NSLog(@"End seek forward..."); break; case UIEventSubtypeRemoteControlBeginSeekingBackward: NSLog(@"Begin seek backward..."); break; case UIEventSubtypeRemoteControlEndSeekingBackward: NSLog(@"End seek backward..."); break; default: break; } }}

ViewController类落成如下:

//// ViewController.m// prac//// Created by Realank on 16/3/23.// Copyright © 2016年 realank. All rights reserved.//#import "ViewController.h"#import <AVFoundation/AVFoundation.h>@interface ViewController () <AVAudioPlayerDelegate>@property (nonatomic, strong) AVAudioPlayer *audioPlayer;@end@implementation ViewController- viewDidLoad { [super viewDidLoad];}- touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { if ([self.audioPlayer isPlaying]) { [self.audioPlayer stop]; AVAudioSession *audioSession=[AVAudioSession sharedInstance]; [audioSession setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil]; }else{ [self musicPlayback]; } }- (AVAudioPlayer *)audioPlayer { if (!_audioPlayer) { NSString *urlStr=[[NSBundle mainBundle]pathForResource:@"liang.mp3" ofType:nil]; NSURL *url=[NSURL fileURLWithPath:urlStr]; NSError *error=nil; //初始化播放器,注意这里的Url参数只能时文件路径,不支持HTTP Url _audioPlayer=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error]; //设置播放器属性 _audioPlayer.numberOfLoops=0;//设置为0不循环 _audioPlayer.delegate=self; [_audioPlayer prepareToPlay];//加载音频文件到缓存 if{ NSLog(@"初始化播放器过程发生错误,错误信息:%@",error.localizedDescription); return nil; } AVAudioSession *audioSession=[AVAudioSession sharedInstance]; [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil]; [audioSession setActive:YES error:nil]; //添加通知,拔出耳机后暂停播放 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(routeChange:) name:AVAudioSessionRouteChangeNotification object:nil]; } return _audioPlayer;}- musicPlayback { if (!self.audioPlayer.isPlaying) { [self.audioPlayer play]; } }-audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:flag{ NSLog(@"音乐播放完成...");}/** * 一旦输出改变则执行此方法 * * @param notification 输出改变通知对象 */-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"]) { [self.audioPlayer pause]; } }}-dealloc{ [[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionRouteChangeNotification object:nil];}- remoteControlReceivedWithEvent:(UIEvent *)event { if(event.type==UIEventTypeRemoteControl){ switch (event.subtype) { case UIEventSubtypeRemoteControlPlay: [self.audioPlayer play]; break; case UIEventSubtypeRemoteControlPause: [self.audioPlayer pause]; break; case UIEventSubtypeRemoteControlStop: [self.audioPlayer stop]; break; case UIEventSubtypeRemoteControlTogglePlayPause: if (self.audioPlayer.isPlaying) { [self.audioPlayer pause]; }else{ [self.audioPlayer play]; } break; case UIEventSubtypeRemoteControlNextTrack: NSLog(@"Next..."); break; case UIEventSubtypeRemoteControlPreviousTrack: NSLog(@"Previous..."); break; case UIEventSubtypeRemoteControlBeginSeekingForward: NSLog(@"Begin seek forward..."); break; case UIEventSubtypeRemoteControlEndSeekingForward: NSLog(@"End seek forward..."); break; case UIEventSubtypeRemoteControlBeginSeekingBackward: NSLog(@"Begin seek backward..."); break; case UIEventSubtypeRemoteControlEndSeekingBackward: NSLog(@"End seek backward..."); break; default: break; } }}@end

本文由必发88唯一官网发布于88bifa必发唯一官网,转载请注明出处:前台服务播放音乐,拔耳机控制

关键词: 书客创作[ib... Android笔记 音视频 后台 耳机

上一篇:Ajax乱码问题整理,jsp中文显示乱码解决方案

下一篇:没有了