【AndroidAPP】权限被拒绝:[android.permission.READ_EXTERNAL_STORAGE],USB设备访问权限系统报错

一、问题原因

在这里插入图片描述

1.安卓安全性变更

Android 12+ 的安全性变更,Google 引入了更严格的 PendingIntent 安全管理,强制要求开发者明确指定 PendingIntent 的可变性(Mutable)或不可变性(Immutable)。
但是,在从 Android 14+ (API 34) 开始,FLAG_MUTABLE 和隐式 Intent 的组合会被禁止。因此,在使用静态的广播请求的时候,FLAG_MUTABLE多余,且违反安全规则。

2.关键点

关键在于安卓 14+ 版本的安全策略变化,导致无法再继续使用 FLAG_MUTABLE。
在这里插入图片描述

二、解决办法

1.代码示例

先给出代码示例,供大家参考,然后解释关键点在哪。

MainActivity.kt(Kotlin class)代码示例:

package com.example.serialportdebugappimport android.app.PendingIntent
import android.content.Intent
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbManager
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivityclass MainActivity : AppCompatActivity() {private lateinit var statusTextView: TextViewprivate lateinit var logTextView: TextViewprivate lateinit var checkPortButton: Buttonprivate lateinit var usbManager: UsbManageroverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 初始化视图statusTextView = findViewById(R.id.statusTextView)logTextView = findViewById(R.id.logTextView)checkPortButton = findViewById(R.id.checkPortButton)// 获取 USB 管理器usbManager = getSystemService(USB_SERVICE) as UsbManager// 按钮点击事件checkPortButton.setOnClickListener {detectUsbDevices()}}/*** 检测 USB 设备*/private fun detectUsbDevices() {val deviceList = usbManager.deviceListif (deviceList.isEmpty()) {logTextView.append("No USB devices found\n")return}for ((_, device) in deviceList) {logTextView.append("Detected device: ${device.deviceName}\n")requestPermission(device)}}/*** 请求 USB 权限*/private fun requestPermission(device: UsbDevice) {val intent = PendingIntent.getBroadcast(this, 0, Intent("com.android.example.USB_PERMISSION"),PendingIntent.FLAG_IMMUTABLE)usbManager.requestPermission(device, intent)}
}

UsbBroadcastReceiver.kt(Kotlin class)代码示例:

package com.example.serialportdebugappimport android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbManager
import android.util.Logclass UsbBroadcastReceiver : BroadcastReceiver() {override fun onReceive(context: Context, intent: Intent) {val action = intent.actionif (action == "com.android.example.USB_PERMISSION") {synchronized(this) {val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {device?.let {Log.d("UsbBroadcastReceiver", "Permission granted for device: ${device.deviceName}")}} else {Log.d("UsbBroadcastReceiver", "Permission denied for device: ${device?.deviceName}")}}}}
}

AndroidManifest.xml 代码示例(总配置文件)

<manifest xmlns:android="http://schemas.android.com/apk/res/android"><uses-feature android:name="android.hardware.usb.host" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.SerialPortDebugApp"><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><!-- 广播接收器,处理 USB 权限 --><receiver android:name=".UsbBroadcastReceiver" android:exported="false"><intent-filter><action android:name="com.android.example.USB_PERMISSION" /></intent-filter></receiver></application>
</manifest>

build.gradle.kts(:app) 相关依赖代码示例

plugins {alias(libs.plugins.android.application)alias(libs.plugins.kotlin.android)alias(libs.plugins.kotlin.compose)
}android {namespace = "com.example.serialportdebugapp"compileSdk = 35defaultConfig {applicationId = "com.example.serialportdebugapp"minSdk = 26targetSdk = 35versionCode = 1versionName = "1.0"testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"}buildTypes {release {isMinifyEnabled = falseproguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"),"proguard-rules.pro")}}compileOptions {sourceCompatibility = JavaVersion.VERSION_11targetCompatibility = JavaVersion.VERSION_11}kotlinOptions {jvmTarget = "11"}buildFeatures {compose = true}
}dependencies {implementation(libs.androidx.core.ktx)implementation(libs.androidx.lifecycle.runtime.ktx)implementation(libs.androidx.activity.compose)implementation(platform(libs.androidx.compose.bom))implementation(libs.androidx.ui)implementation(libs.androidx.ui.graphics)implementation(libs.androidx.ui.tooling.preview)implementation(libs.androidx.material3)implementation(libs.androidx.appcompat)testImplementation(libs.junit)androidTestImplementation(libs.androidx.junit)androidTestImplementation(libs.androidx.espresso.core)androidTestImplementation(platform(libs.androidx.compose.bom))androidTestImplementation(libs.androidx.ui.test.junit4)debugImplementation(libs.androidx.ui.tooling)debugImplementation(libs.androidx.ui.test.manifest)implementation(libs.purejavacomm)
}

libs.versions.toml 代码示例:

[versions]
agp = "8.7.2"
kotlin = "2.0.0"
coreKtx = "1.15.0"
junit = "4.13.2"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
lifecycleRuntimeKtx = "2.8.7"
activityCompose = "1.8.0"
composeBom = "2024.04.01"
appcompat = "1.7.0"[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
purejavacomm = { group = "com.github.purejavacomm", name = "purejavacomm", version = "1.0.2.RELEASE" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }

activity_main.xml 代码示例 (APP界面,UI,用于测试USB串口调试APP的界面UI设计)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="16dp"><TextViewandroid:id="@+id/statusTextView"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="USB Status: Not connected"android:textSize="18sp" /><TextViewandroid:id="@+id/logTextView"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Log output:\n"android:padding="8dp"android:scrollbars="vertical" /><Buttonandroid:id="@+id/checkPortButton"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Check USB Devices" />
</LinearLayout>

2.关键点

关键点在于,MainActivity.kt 中的 这段代码:

    /*** 请求 USB 权限*/private fun requestPermission(device: UsbDevice) {val intent = PendingIntent.getBroadcast(this, 0, Intent("com.android.example.USB_PERMISSION"),PendingIntent.FLAG_IMMUTABLE)usbManager.requestPermission(device, intent)}

能够看到,在使用 PendingIntent 的时候,我们告知了“FLAG_IMMUTABLE”,这是关键,回到文章最开始的时候我们说到过的:
这是 Android 14+ 的特性,我们只能使用 FLAG_IMMUTABLE,也就是不可变的 PendingIntent。

只要这个写对了,权限被拒绝:[android.permission.READ_EXTERNAL_STORAGE] 的 BUG基本就会被解决。

3.关于 Intent 和 PendingIntent:

Intent 是 Android 中的一种消息对象,用于描述应用程序要执行的操作。
作用是用来启动 活动(Activity)、服务(Service) 或 广播(Broadcast)。
可以携带数据,以便被启动的组件可以接收到并使用这些数据。

分为显示和隐式:

在这里插入图片描述

常见的 Intent 的用途:

在这里插入图片描述
PendingIntent 是一种特殊类型的 Intent,可以在 未来 的某个时间由系统或其他应用触发。
它充当一个 “授权”,允许其他应用或系统在您的应用上下文中执行操作。

通常用于将操作 “延迟执行”,而不是立即执行。
适用于一些 异步场景,例如:通知(Notification)的点击事件。定时任务。广播接收器。

说白了,它就好像嵌入式和VUE中的 “监听”,是用来等待消息的,而不是主动出击。
而且,重要的是:Intent 是瞬发的,使用后就销毁。
但是 PendingIntent 是持续的,会一直存在到 被触发、被取消 为止。

Intent 和 PendingIntent 的对比

在这里插入图片描述

PendingIntent 的 3 种类型

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/65873.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C之(14)gcov覆盖率

C之(14)gcov覆盖率 Author: Once Day Date: 2024年12月30日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: C语言_Once-Day的博客-CSDN博客 前些天…

简易屏幕共享工具-基于WebSocket

前面写了两个简单的屏幕共享工具&#xff0c;不过那只是为了验证通过截屏的方式是否可行&#xff0c;因为通常手动截屏的频率很低&#xff0c;而对于视频来说它的帧率要求就很高了&#xff0c;至少要一秒30帧率左右。所以&#xff0c;经过实际的截屏工具验证&#xff0c;我了解…

Paperlib(论文管理工具)

Paperlib 是一个简单好用的论文管理工具。软件接入各学科数据库用于匹配论文元数据&#xff0c;逐步为每一个学科&#xff08;例如计算机科学&#xff0c;物理学等&#xff09;定制化数据库组合提高检索精度。尤其是精准的会议论文元数据检索能力。还可以管理你的论文&#xff…

c# 2024/12/27 周五

6《详解类型、变量与对象》36 详解类型、变量与对象 _1_哔哩哔哩_bilibili

Formality:匹配(match)是如何进行的?

相关阅读Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482 匹配点、对比点和逻辑锥 匹配指的是Formality工具尝试将参考设计中的每个匹配点与实现设计中的相应匹配点进行配对&#xff0c;这里的匹配点包括对比点(Compare Point…

分布式算法(五):初识ZAB协议

文章目录 一、什么是Zookeeper二、ZAB与Zookeeper的关系为什么Zookeeper不直接使用Paxos 三、ZAB简介1.名词解释提案&#xff08;Proposal&#xff09;事务&#xff08;Transaction&#xff09;原子广播&#xff08;Atomic Broadcast&#xff09; 2.集群角色领导者&#xff08;…

Mybatis 01

JDBC回顾 select 语句 "select *from student" 演示&#xff1a; 驱动包 JDBC 的操作流程&#xff1a; 1. 创建数据库连接池 DataSource 2. 通过 DataSource 获取数据库连接 Connection 3. 编写要执⾏带 ? 占位符的 SQL 语句 4. 通过 Connection 及 SQL 创建…

tensorboard的界面参数与图像数据分析讲解

目录 1.基础概念&#xff1a; (a)精确率与召回率&#xff1a; (b)mAP: (c)边界框损失&#xff1a; (d)目标损失&#xff1a; (e)分类损失&#xff1a; (f):学习率&#xff1a; 2.设置部分&#xff08;最右边部分&#xff09;&#xff1a; GENERAL&#xff08;常规设置…

《计算机网络A》单选题-复习题库解析-2

目录 51、下列关于以太网网卡地址特点的说法中&#xff0c;不正确的是&#xff08; &#xff09;。 52、当一个Web Browser向一个使用标准服务器端口的Web Server提出请求时&#xff0c;那么在服务返回的响应包中&#xff0c;所使用的源端口是&#xff08; &#xff0…

Linux总结之CentOS Stream 9安装mysql8.0实操安装成功记录

Linux总结之CentOS Stream 9安装mysql8.0实操安装成功记录 由于网上很多的mysql8.0安装教程都是老版本或者安装过程记录有问题&#xff0c;导致经常安装到一半需要删除重新安装。所以将成功的实操安装过程记录一下&#xff0c;方面后面查阅&#xff0c;大家还有问题的可以在此讨…

高等数学学习笔记 ☞ 无穷小与无穷大

1. 无穷小 1. 定义&#xff1a;若函数当或时的极限为零&#xff0c;那么称函数是当或时的无穷小。 备注&#xff1a; ①&#xff1a;无穷小描述的是自变量的变化过程中&#xff0c;函数值的变化趋势&#xff0c;绝不能认为无穷小是一个很小很小的数。 ②&#xff1a;说无穷小时…

KMP 2024 年总结,Kotlin 崛起的一年

2024 Google I/O 上正式官宣了 KMP&#xff08;Kotlin Multiplatform&#xff09;项目&#xff0c;它是 Google Workspace 团队的一项长期「投资」项目&#xff0c;由 JetBrains 开发维护和开源的项目&#xff0c;简单来说&#xff0c;JetBrains 主导&#xff0c;Google Worksp…

【SpringBoot教程】搭建SpringBoot项目之编写pom.xml

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 &#x1f44f;今天毛毛张分享的内容主要是Maven 中 pom 文件&#x1f195;&#xff0c;涵盖基本概念、标签属性、配置等内容 文章目录 1.前言&#x1f96d;2.项目基本…

【Java 学习】详讲代码块:控制流语句代码块、方法代码块、实例代码块(构造代码块)、静态代码块、同步代码块

&#x1f4ac; 欢迎讨论&#xff1a;如对文章内容有疑问或见解&#xff0c;欢迎在评论区留言&#xff0c;我需要您的帮助&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;如果这篇文章对您有所帮助&#xff0c;请不吝点赞、收藏或分享&#xff0c;谢谢您的支持&#x…

【亚马逊云科技】基于Amazon EKS部署高可用的OceanBase的最佳实践

一、前言 随着企业业务的快速发展和数据量的不断增长&#xff0c;高性能、高可用的数据库解决方案成为了关键需求。OceanBase作为一款分布式关系型数据库&#xff0c;以其高扩展性、高可用性和高性能的特点&#xff0c;逐渐受到企业的广泛关注。然而&#xff0c;在复杂的分布式…

【工具】—— SpringBoot3.x整合swagger

Swagger 是一个规范和完整的框架&#xff0c;用于生成、描述、调用和可视化 RESTful 风格的 Web 服务的接口文档。Swagger简单说就是可以帮助生成接口说明文档&#xff0c;操作比较简单添加注解说明&#xff0c;可以自动生成格式化的文档。 项目环境 jdk17SpringBoot 3.4.0Sp…

从0入门自主空中机器人-2-1【无人机硬件框架】

关于本课程&#xff1a; 本次课程是一套面向对自主空中机器人感兴趣的学生、爱好者、相关从业人员的免费课程&#xff0c;包含了从硬件组装、机载电脑环境设置、代码部署、实机实验等全套详细流程&#xff0c;带你从0开始&#xff0c;组装属于自己的自主无人机&#xff0c;并让…

基于视觉语言模型(VLM)的CogAgent

前言 CogAgent 是由清华大学与智谱AI联合推出的一个多模态大模型&#xff0c;专注于图形用户界面&#xff08;GUI&#xff09;的理解和导航。它代表了在视觉语言模型&#xff08;VLM&#xff09;领域的一项重要进展&#xff0c;特别是在GUI Agent能力方面。相较于传统的基于文…

win10、win11-鼠标右键还原、暂停更新

系统优化 win 10jihuo win 11jihuo鼠标右键还原暂停更新 update 2024.12.28win 10 jihuo winx&#xff0c;打开powershell管理员&#xff0c;输入以下命令,选择1并等待 irm https://get.activated.win | iex参考&#xff1a;https://www.bilibili.com/video/BV1TN411M72J/?sp…

C# 找出给定三角形的所有角度(Find all angles of a given triangle)

给定三角形在二维平面上所有三个顶点的坐标&#xff0c;任务是找到所有三个角度。 示例&#xff1a; 输入&#xff1a;A (0, 0), B (0, 1), C (1, 0) 输出&#xff1a;90, 45, 45 为了解决这个问题&#xff0c;我们使用下面的余弦定律。 c^2 a^2 …