前言
最近公司项目里需要获取本地音乐,开始傻傻的以为苹果不能获取本地音乐,后面查了下发现其实是可以的,也就是获取媒体资料库的音乐。好了废话不多说,我们直接进入主题。
获取权限
从 iOS 10
之后,关于权限的提示都需要在infp.plist
文件里写入对应的提示语,不然程序会crash
,在infp.plist
文件写入以下代码即可。
<key>NSAppleMusicUsageDescription</key>
<string>App需要您的同意,才能访问媒体资料库</string>
我想当初刚开始做适配iOS 10
的同志们估计是哭着踩着这些坑一步步走过来的,别告诉我就我一个人是这样的。
然后我们需要通过代码里去获取用户关于访问媒体资料库的权限,如果用户拒绝了此权限,我们需要提示用户打开此权限。
第一步:导入头文件
#import <MediaPlayer/MediaPlayer.h>
第二步:获取用户关于媒体资料库的权限
// MARK:- 判断是否有权限
- (void)requestAuthorizationForMediaLibrary {
__weak typeof(self) weakSelf = self;
// 请求媒体资料库权限
MPMediaLibraryAuthorizationStatus authStatus = [MPMediaLibrary authorizationStatus];
if (authStatus != MPMediaLibraryAuthorizationStatusAuthorized) {
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
NSString *appName = [infoDictionary objectForKey:@"CFBundleDisplayName"];
if (appName == nil) {
appName = @"APP";
}
NSString *message = [NSString stringWithFormat:@"允许%@访问你的媒体资料库?", appName];
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"警告" message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[weakSelf dismissViewControllerAnimated:YES completion:nil];
}];
UIAlertAction *setAction = [UIAlertAction actionWithTitle:@"设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
if ([[UIApplication sharedApplication] canOpenURL:url])
{
[[UIApplication sharedApplication] openURL:url];
[weakSelf dismissViewControllerAnimated:YES completion:nil];
}
}];
[alertController addAction:okAction];
[alertController addAction:setAction];
[self presentViewController:alertController animated:YES completion:nil];
}
}
获取媒体资料库里的音乐数据
上面我们讲了如何获取用户的媒体资料库权限,在用户同意APP
访问媒体资料库之后,我们开始从媒体资料库里获取我们想要的本地音乐数据。
- 第一步:获取
iTunes
中的音乐
// MARK:- 获取 iTunes 中的音乐
- (void)getItunesMusic {
// 创建媒体选择队列
MPMediaQuery *query = [[MPMediaQuery alloc] init];
// 创建读取条件
MPMediaPropertyPredicate *albumNamePredicate = [MPMediaPropertyPredicate predicateWithValue:[NSNumber numberWithInt:MPMediaTypeMusic] forProperty:MPMediaItemPropertyMediaType];
// 给队列添加读取条件
[query addFilterPredicate:albumNamePredicate];
// 从队列中获取条件的数组集合
NSArray *itemsFromGenericQuery = [query items];
// 遍历解析数据
for (MPMediaItem *music in itemsFromGenericQuery) {
[self resolverMediaItem:music];
}
}
通过创建选择队列,添加读取条件之后,我们获得了符合读取条件的数组NSArray *itemsFromGenericQuery = [query items]
。但是此时itemsFromGenericQuery
里面装的是一个个MPMediaItem
,我们还需要对MPMediaItem
处理,变成方便我们处理的Dictionary
或者Model
。
- 第二步:对
MPMediaItem
进行处理
- (void)resolverMediaItem:(MPMediaItem *)music {
// 歌名
NSString *name = [music valueForProperty:MPMediaItemPropertyTitle];
// 歌曲路径
NSURL *fileURL = [music valueForProperty:MPMediaItemPropertyAssetURL];
// 歌手名字
NSString *singer = [music valueForProperty:MPMediaItemPropertyArtist];
if(singer == nil)
{
singer = @"未知歌手";
}
// 歌曲时长(单位:秒)
NSTimeInterval duration = [[music valueForProperty:MPMediaItemPropertyPlaybackDuration] doubleValue];
NSString *time = @"";
if((int)duration % 60 < 10) {
time = [NSString stringWithFormat:@"%d:0%d",(int)duration / 60,(int)duration % 60];
}else {
time = [NSString stringWithFormat:@"%d:%d",(int)duration / 60,(int)duration % 60];
}
// 歌曲插图(没有就返回 nil)
MPMediaItemArtwork *artwork = [music valueForProperty:MPMediaItemPropertyArtwork];
UIImage *image;
if (artwork) {
image = [artwork imageWithSize:CGSizeMake(72, 72)];
}else {
image = [UIImage imageNamed:@"duanshipin"];
}
[_songArr addObject:@{@"name": name,
@"fileURL": fileURL,
@"singer": singer,
@"time": time,
@"image": image,
}];
}
注意
- 歌曲路径
这里返回的歌曲路径直接是NSURL
类型的,不是NSString
类型。 - 歌曲时长
这里查询出来的音乐的时长是以秒为单位的,也就是说如果一首歌的时长为3分钟,那这里查询出来的duration
的值为180s,所以我们需要对这个值进行转换,转换成mm:ss
的形式. - 歌曲封面
这里需要注意的是,如果歌曲没有封面,MPMediaItemArtwork
为nil
,所以你需要对这个nil
单独处理下,最好是放一张默认图片。
写在最后
放一张运行Demo
的图片,如果需要 Demo
的话,我会传到Github
上,然后贴出链接的。