【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.rhkb.cn/news/498600.html

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

相关文章

打印进度条

文章目录 1.Python语言实现(1)黑白色(2)彩色&#xff1a;蓝色 2.C语言实现(1)黑白颜色(2)彩色版&#xff1a;红绿色 1.Python语言实现 (1)黑白色 import sys import timedef progress_bar(percentage, width50):"""打印进度条:param percentage: 当前进度百分比…

ubuntu 使用samba与windows共享文件[注意权限配置]

在Ubuntu上使用Samba服务与Windows系统共享文件&#xff0c;需要正确配置Samba服务以及相应的权限。以下是详细的步骤&#xff1a; 安装Samba 首先&#xff0c;确保你的Ubuntu系统上安装了Samba服务。 sudo apt update sudo apt install samba配置Samba 安装完成后&#xff0c…

数据结构(哈希表)

背景 在对数据的日常处理中&#xff0c;查找是一项基本操作。通常&#xff0c;查找算法都是基于对比的&#xff0c;比如在一条链表中有n个节点&#xff0c;要找到其中的某个节点&#xff0c;最基本的思路就是从头到尾依次遍历每个节点&#xff0c;依次对比每个节点是否是想要的…

【每日学点鸿蒙知识】模拟器开启网络、长时任务、兼容性测试支持、丢帧定位、SO中访问rawfile等

1、模拟器如何开启网络&#xff1f; 模拟器使用的是电脑本身的网络&#xff0c;不通过代理即可访问网络。 2、创建子window后&#xff0c;锁屏很短时间内&#xff0c;应用会被杀死&#xff1f; 没开长时任务&#xff0c;锁屏和退后台保活要开长时任务。 应用退至后台后&…

如何解决Eigen和CUDA版本不匹配引起的错误math_functions.hpp: No such file or directory

Apollo9针对RTX40的docker环境里的Eigen库版本是3.3.4&#xff0c;CUDA是11.8: 编译我们自己封装模型的某些component代码时没问题&#xff0c;编译一个封装occ模型的component代码时始终报错: In file included from /usr/include/eigen3/Eigen/Geometry:11:0, …

Mac连接云服务器工具推荐

文章目录 前言步骤1. 下载2. 安装3. 常用插件安装4. 连接ssh测试5. 连接sftp测试注意&#xff1a;ssh和sftp的区别注意&#xff1a;不同文件传输的区别解决SSL自动退出 前言 Royal TSX是什么&#xff1a; Royal TSX 是一款跨平台的远程桌面和连接管理工具&#xff0c;专为 mac…

python修改ppt中的文字部分及插入图片

批量修改ppt中的某个模块&#xff0c;或者批量制作奖状等场景会用到&#xff1b; import os import pandas as pd from pptx import Presentation from pptx.util import Inchesfilepath/Users/kangyongqing/Documents/kangyq/202303/分析模版/批量制作/file1时段预警_副本.pp…

从0到机器视觉工程师(一):机器视觉工业相机总结

目录 相机的作用 工业相机 工业相机的优点 工业相机的种类 工业相机知名品牌 光源与打光 打光方式 亮暗场照明 亮暗场照明的应用 亮暗场照明的区别 前向光漫射照明 背光照明 背光照明的原理 背光照明的应用 同轴光照明 同轴光照明的应用 总结 相机的作用 相机…

gesp(C++一级)(7)洛谷:B3863:[GESP202309 一级] 小明的幸运数

gesp(C一级)&#xff08;7&#xff09;洛谷&#xff1a;B3863&#xff1a;[GESP202309 一级] 小明的幸运数 题目描述 所有个位数为 k k k 的正整数&#xff0c;以及所有 k k k 的倍数&#xff0c;都被小明称为“ k k k 幸运数”。小明想知道正整数 L L L 和 R R R 之间&a…

风力涡轮机缺陷检测数据集,86.6%准确识别率,11921张图片,支持yolo,PASICAL VOC XML,COCO JSON格式的标注

风力涡轮机缺陷检测数据集&#xff0c;86.6&#xff05;准确识别率&#xff0c;11921张图片&#xff0c;支持yolo&#xff0c;PASICAL VOC XML&#xff0c;COCO JSON格式的标注 数据集下载 yolov11&#xff1a; https://download.csdn.net/download/pbymw8iwm/90206849 yolov…

力扣-数据结构-8【算法学习day.79】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;建议灵神的题单和代码随想录&#xff09;和记录自己的学习过程&#xff0c;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关…

FreeRTOS的内存管理(选择heap4.c文件的理由)

目录 1. 了解FreeRTOS内存管理 2. 了解内存碎片 3.了解各个heap.c的内存分配方法 1.heap1.c 2.heap2.c 3.heap3.c 4.heap4.c 5.heap5.c 总结&#xff1a; 内存管理是一个系统基本组成部分&#xff0c;FreeRTOS 中大量使用到了内存管理&#xff0c;比如创建任务、信号量…

WPF中的Microsoft XAML Behaviors包功能详解

什么是XAML Behaviors(行为) XAML Behaviors 提供了一种简单易用的方法&#xff0c;能以最少的代码为 Windows UWP/WPF 应用程序添加常用和可重复使用的交互性。 但是Microsoft XAML Behaviors包除了提供常用的XAML Behaviors之外&#xff0c;还提供了一些Trigger&#xff08…

一文学习SpringBoot

一、SpringBoot介绍 (一)SpringBoot简介 Spring Boot 是由 Pivotal 团队提供的一个用于简化 Spring 应用初始搭建以及开发过程的框架。它基于 Spring 框架&#xff0c;旨在通过减少配置和简化开发流程来加速应用的开发和部署。Spring Boot 提供了嵌入式的 Tomcat、Jetty 或 Un…

本地小主机安装HomeAssistant开源智能家居平台打造个人AI管家

文章目录 前言1. 添加镜像源2. 部署HomeAssistant3. HA系统初始化配置4. HA系统添加智能设备4.1 添加已发现的设备4.2 添加HACS插件安装设备 5. 安装cpolar内网穿透5.1 配置HA公网地址 6. 配置固定公网地址 前言 大家好&#xff01;今天我要向大家展示如何将一台迷你的香橙派Z…

streamlit、shiny、gradio、fastapi四个web APP平台体验

streamlit、shiny、gradio、fastapi四个web APP平台体验 经常被问的问题就是&#xff1a;web APP平台哪个好&#xff1f;该用哪个&#xff1f;刚开始只有用streamlit和shiny&#xff0c;最近体验了一下gradio和fastapi&#xff0c;今天根据自己的体会尝试着回答一下。 使用R语…

Presto-简单了解-230403

presto是什么了解一下&#xff1a; 秒级查询引擎&#xff08;不做存储&#xff09;&#xff0c;GB-PB级不依赖于yarn&#xff0c;有自己的资源管理和执行计划支持多种数据源&#xff1a;hive、redis、kafka presto架构 presto优缺点 presto优点 内存到内存的传输&#xff0…

VScode 格式化代码空格记录

点击 -> “文件” -> “首选项" -> “设置” -> 按下图操作&#xff1a; 怎么格式化代码空格&#xff0c;先看下&#xff1a; 保存代码后&#xff0c;这代码自动格式化发&#xff0c;如下图&#xff1a; 你可以试试看就即可

HTML5 开关(Toggle Switch)详细讲解

HTML5 开关&#xff08;Toggle Switch&#xff09;详细讲解 1. 任务概述 开关&#xff08;Toggle Switch&#xff09;是一种用于表示二元状态&#xff08;如开/关&#xff09;的用户界面控件。用户可以通过点击开关来切换状态&#xff0c;常见于设置选项、开关功能等场景。 2…

Python中PDF转Word的技术

Python PDF转Word技术概述 在日常办公和数据处理中&#xff0c;经常需要将PDF文档转换为Word文档&#xff0c;以便进行编辑、修改或格式调整。Python作为一种强大的编程语言&#xff0c;提供了多种库和工具来实现这一功能。以下是对Python中PDF转Word技术的详细介绍。 一、技…