android 使用MediaPlayer实现音乐播放--权限请求
在Android应用中,获取本地音乐文件的权限是实现音乐扫描功能的关键步骤之一。随着Android版本的不断更新,从Android 6.0(API级别23)开始,应用需要动态请求权限,而到了android 13以上需要的权限又做了进一步改变。
1. 需要添加存储权限到AndroidManifest.xml中,android 6.0到android 12只需要存储权限,android 13开始对权限做了更细致的处理,而不是READ_EXTERNAL_STORAGE,拆分成下面三个权限。如果同时请求 READ_MEDIA_IMAGES 权限和 READ_MEDIA_VIDEO 权限,系统只会显示一个系统权限对话框。如果您的应用之前已获得 READ_EXTERNAL_STORAGE 权限,则在升级时,系统会自动授予任何请求的 READ_MEDIA_* 权限。如果您的应用只需要访问图片、照片和视频,优先使用照片选择器,而不是声明 READ_MEDIA_IMAGES 和 READ_MEDIA_VIDEO 权限。如果是只要音频文件同理只需要READ_MEDIA_VIDEO 权限即可。

一般我们获取音频文件,只需要添加下面权限即可
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"tools:ignore="ScopedStorage" android:maxSdkVersion="32"/><uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
2.动态请求权限
检查是否有获取音频文件权限
fun checkPermission(context: Context): Boolean {return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {ContextCompat.checkSelfPermission(context,Manifest.permission.READ_MEDIA_AUDIO) == PackageManager.PERMISSION_GRANTED} else {ContextCompat.checkSelfPermission(context,Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED}}
请求权限
fun requestPermission(activity: Activity, requestCode: Int) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {ActivityCompat.requestPermissions(activity,arrayOf(Manifest.permission.READ_MEDIA_AUDIO,Manifest.permission.POST_NOTIFICATIONS), requestCode)} else {ActivityCompat.requestPermissions(activity,arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),requestCode)}}
一般我们写成一个数组里面一起去请求
private static final String[] permissionsArray = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.RECORD_AUDIO};private static final String[] permissionsArray13 = new String[]{Manifest.permission.READ_MEDIA_AUDIO,Manifest.permission.RECORD_AUDIO,Manifest.permission.POST_NOTIFICATIONS};private void checkRequiredPermission(final Activity activity) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {for (String permission : permissionsArray13) {if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {permissionsList.add(permission);}}} else {for (String permission : permissionsArray) {if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {permissionsList.add(permission);}}}if (permissionsList != null && permissionsList.size() > 0) {ActivityCompat.requestPermissions(activity, permissionsList.toArray(new String[permissionsList.size()]), REQUEST_PERMISSION);} else {//去初始化}}
去请求权限可以用一个对话框去处理会显得更友好
final PermissionDialog permissionDialog = new PermissionDialog(this, R.color.library_dialog_bg, getString(R.string.permission_title));permissionDialog.setPermissionDialogListener(new PermissionDialog.IPermissionDialogListener() {@Overridepublic void cancelClick() {finish();permissionDialog.cancel();}@Overridepublic void okClick() {boolean isBannedPermission = MusicPermissionUtils.INSTANCE.isBannedPermission(MusicLibraryActivity.this);if (!isBannedPermission) {Utils.goToSettingIntent(MusicLibraryActivity.this);} else {MusicPermissionUtils.INSTANCE.requestPermission(MusicLibraryActivity.this, REQUEST_PERMISSION);}permissionDialog.cancel();}});permissionDialog.show();
处理权限请求结果,如果全部权限都已同意可以去做初始化,一般我们做权限请求最好每个功能点需要用到的权限一个个去请求会更友好。
@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {switch (requestCode) {case REQUEST_PERMISSION:boolean isAllRequest = false;for (int i = 0; i < permissions.length; i++) {if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {isAllRequest = true;} else {//去请求权限showPermissionDialog();return;}}if (isAllRequest) {//初始化或者继续操作}break;default:super.onRequestPermissionsResult(requestCode, permissions, grantResults);}}
用户如果不同意权限可以跳转到设置找到应用去同意添加权限,用户有可能会拒绝权限请求,最好在界面添加可以继续请求的按钮或者直接跳转到设置里面让用户找到应用去添加需要的权限
public static void goToSettingIntent(Context context) {Intent localIntent = new Intent();localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);if (Build.VERSION.SDK_INT >= 9) {localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");localIntent.setData(Uri.fromParts("package", context.getPackageName(), null));} else if (Build.VERSION.SDK_INT <= 8) {localIntent.setAction(Intent.ACTION_VIEW);localIntent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails");localIntent.putExtra("com.android.settings.ApplicationPkgName", context.getPackageName());}context.startActivity(localIntent);}
音乐权限请求工具代码
object MusicPermissionUtils {fun hasMusicPermission(context: Context): Boolean {val permission = checkPermission(context)if (permission == PackageManager.PERMISSION_GRANTED) {return true}return false}fun isBannedPermission(activity: Activity): Boolean {val isBannedPermission: Boolean =if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {ActivityCompat.shouldShowRequestPermissionRationale(activity,Manifest.permission.READ_MEDIA_AUDIO)} else {ActivityCompat.shouldShowRequestPermissionRationale(activity,Manifest.permission.READ_EXTERNAL_STORAGE)}return isBannedPermission}fun requestPermission(activity: Activity, requestCode: Int) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {ActivityCompat.requestPermissions(activity,arrayOf(Manifest.permission.READ_MEDIA_AUDIO,Manifest.permission.POST_NOTIFICATIONS), requestCode)} else {ActivityCompat.requestPermissions(activity,arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),requestCode)}}fun checkReadPermission(context: Context): Boolean {return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {ContextCompat.checkSelfPermission(context,Manifest.permission.READ_MEDIA_AUDIO) == PackageManager.PERMISSION_GRANTED} else {ContextCompat.checkSelfPermission(context,Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED}}fun checkPermission(context: Context): Int {val checkWriteStoragePermission: Int =if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {ContextCompat.checkSelfPermission(context, Manifest.permission.READ_MEDIA_AUDIO)} else {ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE)}return checkWriteStoragePermission}}
相关文章:
android 使用MediaPlayer实现音乐播放--权限请求
在Android应用中,获取本地音乐文件的权限是实现音乐扫描功能的关键步骤之一。随着Android版本的不断更新,从Android 6.0(API级别23)开始,应用需要动态请求权限,而到了android 13以上需要的权限又做了进一步…...
Web开发:ORM框架之使用Freesql的DbFrist封装常见功能
一、调用 public class Program {static string connectionstring "连接字符串(数据库名)";static void Main(string[] args){//1.连接数据库var freesql new FreeSqlBuilder().UseConnectionString(DataType.SqlServer, connectionstring…...
【多线程-第一天-多线程的执行原理-多线程的优缺点-主线程 Objective-C语言】
一、多线程的执行原理 1.单任务操作系统:同一时间只能执行一个任务 多任务操作系统:同一时间可以执行多个任务 比如,我可以一边听着酷狗,一边聊着QQ, 在单任务的操作系统里边,只有进程,没有线程, 单任务操作系统,CPU必须执行完一个任务,才能执行第二个任务, 多任…...
SQL基础语法介绍-基于MySQL
文章目录 一、SQL分类二、SQL语法1.数据库字段类型1.1.数值类型1.2 字符类型1.3 日期类型 2.字段约束2.1约束介绍2.2 非空约束(not null)2.3 唯一约束(unique)2.4 主键约束(primary key)2.5 自增长主键2.6 …...
一分钟学习数据安全——数据安全风险的系统化应对思路
数据是组织的重要资产,未经授权的数据访问可能导致数据泄露、数据篡改、隐私侵犯和合规风险等问题。企业可以通过数据访问控制来提高信息系统在数据全生命周期管理中的安全性。企业可以引入IAM系统,来控制身份来管理权限。通过对用户访问权限的管理和合适…...
端口port常识
端口(Port)用于区分不同的服务或进程。在网络通信中,每个运行在计算机上的进程都会通过一个端口来与其他计算机上的进程进行通信。以下是一些关于端口和使用常识的信息: 端口号范围: 0-1023:这些被称为“知…...
【Oracle实战】文章导读
【Oracle基础】 【实战】Oracle基础之单机安装-01 Windows 2016 Oracle 11gR2【实战】Oracle基础之单机安装-02 Windows 2016 Oracle 12cR2【实战】Oracle基础之单机安装-03 CentOS 7.9 Oracle 11gR2【实战】Oracle基础之单机安装&#x…...
“人工智能+高职”:VR虚拟仿真实训室的发展前景
在当今科技日新月异的时代,人工智能(AI)与虚拟现实(VR)技术的融合正逐步改变着各行各业,教育领域也不例外。特别是在高等职业教育(简称“高职”)体系中,VR虚拟仿真实训室…...
c语言学习27宏定义条件编译
1类型重定义 typedef typedef关键字 属性:关键字 功能:将数据类型重新定义别名 (数据类型 别名) 格式:typedef数据类型名 别名; 例子:typedef unsigned char u8; 位置…...
理论结合实践:用Umami构建网站分析系统
个人博客地址(欢迎大家访问):理论结合实践:用Umami构建网站分析系统 1. 引言 网站统计分析是一种通过收集、处理和分析网站数据来评估网站性能、用户行为和流量来源的综合方法。通过分析用户访问模式、页面浏览量、访问时长、用户…...
Unreal从入门到精通之如何绘制用于VR的3DUI交互的手柄射线
文章目录 前言实现方式MenuLaser实现步骤1.Laser和Cursor2.移植函数3.启动逻辑4.检测射线和UI的碰撞5.激活手柄射线6.更新手柄射线位置7.隐藏手柄射线8.添加手柄的Trigger监听完整节点如下:效果图前言 之前我写过一篇文章《Unreal5从入门到精通之如何在VR中使用3DUI》,其中讲…...
移动充储机器人“小奥”的多场景应用(上)
在当前现代化城市交通体系中,移动充储机器人“小奥”发挥着至关重要的作用。该机器人不仅是一个简单的设备,而是一个集成了高科技的移动充电站,为新能源汽车提供了一种前所未有的便捷充电解决方案。该机器人配备了先进的电池管理系统…...
已解决wordpress提示正在执行例行维护,请一分钟后回来
今天打开网站时提示“正在执行例行维护,请一分钟后回来”,一分钟后还这样,刷新也没用,这究竟是怎么回事了? 问题原因 这是WordPress在更新,wordpress在升级程序、主题、插件时,都会先切换到维护模式&…...
DDR3脚位解析,class分类
SDQ{0-31}:数据信号,为输入/输出双向信号。 SA{0-15}:地址信号为输入信号。 SDQS{0-3}P/N:数据选通信号,数据可以通过DQS的上升沿与下降沿传输。在读模式时,DQS由存储器发给CPU,DQS与数据边沿对齐。在写模…...
【深度学习|目标跟踪】DeepSort 详解
DeepSort详解 1、Sort回顾2、DeepSort的状态向量3、DeepSort的外观特征4、DeepSort的track状态5、DeepSort的代价矩阵以及门控矩阵6、DeepSort的级联匹配 1、Sort回顾 查看这篇博客 2、DeepSort的状态向量 Sort中的卡尔曼滤波使用的目标的状态向量是一个7维的向量,…...
快速图像识别:落叶植物叶片分类
1.背景意义 研究背景与意义 随着全球生态环境的变化,植物的多样性及其在生态系统中的重要性日益受到关注。植物叶片的分类不仅是植物学研究的基础,也是生态监测、农业管理和生物多样性保护的重要环节。传统的植物分类方法依赖于人工观察和专家知识&…...
MTK Android12 user版本MtkLogger
目录 1.修改device/mediatek/system/common/device.mk 2.修改device/mediatek/system/common/mtklog/mtklog-config-bsp-eng.prop,修改为false是为了开机的时候不要自动启动 3.修改device/mediatek/vendor/common/device.mk 4.修改vendor/mediatek/proprietary/…...
Python数据结构day2
一、链表 1.1目的 解决顺序表存储数据有上限,并且插入和删除操作效率低的问题 1.2概念 链表:链式存储的线性表,使用随机物理内存存储逻辑上连续的数据 链表的组成:由一个个结点组成 结点:由数据域和链接域组成&a…...
后台通用tag面包屑
思路:要实现点击左侧菜单栏,页面跳转且显示面包屑(本文用的是TSVue3) 功能点: 最多显示5个标签超过5个时,自动移除最早的标签至少保留1个标签支持标签关闭功能 首先在store.ts 处理路由(点击过的路由,当前…...
oracle数据恢复—通过拼接数据库碎片的方式恢复Oracle数据的案例
Oracle数据库故障: 存储掉盘超过上限,lun无法识别。管理员重组存储的位图信息并导出lun,发现linux操作系统上部署的oracle数据库中有上百个数据文件的大小变为0kb。数据库的大小缩水了80%以上。 取出&并分析oracle数据库的控制文件。重组…...
机器学习模型评估中的构念效度:超越基准测试分数的科学推断
1. 项目概述与核心问题在机器学习的日常研究和工程实践中,我们每天都在和各种各样的基准测试(Benchmark)打交道。无论是为了比较新提出的ResNet变体在ImageNet上的Top-1准确率,还是评估一个大型语言模型在MMLU上的常识推理能力&am…...
Rydberg原子量子门实现原理与优化技术
1. Rydberg原子平台中的量子门实现基础1.1 Rydberg原子特性与量子计算优势Rydberg原子是指外层电子被激发到高主量子数能级的原子态,这类原子具有三个关键特性使其成为量子计算的理想平台:强偶极-偶极相互作用:当两个原子同时处于Rydberg态时…...
WPF虚拟桌宠组件:可嵌入、高性能、工程化UI生命体
1. 这不是“桌面宠物”,而是一个可嵌入的WPF UI组件化生命体你可能在Windows XP时代见过那只晃着尾巴、偶尔打哈欠的3D小猫,也可能在Win10系统托盘里点开过一个会眨眼的像素狐狸——但那些是独立进程、是系统级小工具、是“看一眼就关掉”的轻量娱乐。而…...
科华UPS电源全品类汇总:选型与场景适配指南
科华UPS电源作为国内智慧电能领域的主流产品,覆盖家用、办公、机房、工业等全场景,产品系列丰富、规格齐全,但多数用户在选型时,常因分不清系列差异、功率适配、架构类型而踩坑。本文系统汇总科华UPS电源的核心分类、主流系列、核…...
浏览器指纹识别机制深度剖析与反识别技术实现
一、浏览器指纹技术基础认知1.1 浏览器指纹的核心定义在数字化时代,每一台接入互联网的设备都会留下独特的数字标识,浏览器指纹便是其中最关键的识别凭证之一。浏览器指纹是网站通过 JavaScript 脚本、HTTP 请求头、硬件接口调用等多种技术手段ÿ…...
【数据结构与算法】数据结构基础——栈和队列
目录栈和队列1. 栈1.1 栈的概念1.2 栈的实现方式分析1.3 栈的实现1.3.1 栈的初始化与销毁1.3.2 入栈与出栈1.3.3 栈的判空与有效元素个数1.3.4 栈顶元素1.4 栈的扩展1.4.1 两栈共享空间2. 队列2.1 队列的概念2.2 队列的实现方式分析2.3 队列的实现2.3.1 队列的初始化与销毁2.3.…...
基于IRS2092的200W D类功放设计:从PWM原理到保护电路实战
1. 项目概述与核心思路折腾音响功放,从经典的AB类玩到D类,感觉就像是从燃油车换到了电动车,动力响应和效率完全是两个维度。这次要聊的这块“200W Class-D Audio Power Amplifier [150115]”单板功放,就是一个非常典型的D类功放设…...
03 - 变量与数据类型
03 - 变量与数据类型 变量是编程里最基础的概念,相当于你往电脑里存东西的"容器"。这章我们把变量的命名规则、Python 的几种基本数据类型都过一遍。 变量是什么 说白了,变量就是一个有名字的盒子。你往里面放个东西,以后想用这个…...
掌握Umi-OCR:5分钟上手开源免费离线文字识别工具
掌握Umi-OCR:5分钟上手开源免费离线文字识别工具 【免费下载链接】Umi-OCR OCR software, free and offline. 开源、免费的离线OCR软件。支持截屏/批量导入图片,PDF文档识别,排除水印/页眉页脚,扫描/生成二维码。内置多国语言库。…...
Claude服务治理架构升级(生产环境零停机迁移实录)
更多请点击: https://codechina.net 第一章:Claude服务治理架构升级(生产环境零停机迁移实录) 为应对日益增长的推理请求量与多租户策略精细化需求,我们对Claude服务治理层实施了从单体API网关向云原生服务网格的平滑…...
