19.Android相关

1.常用adb命令

adb root 用户权限
adb remount 写权限
adb disable-verity写权限失败时执行,然后reboot
adb shell终端控制设备,命令行终端
adb shell input keyevent 4 返回
ps list package 查看所有应用 + | grep XXX
adb reboot bootloader fastboot 进入fastboot模式
fastboot reboot 退出fastboot
adb push 本机pwd 机器pwd
adb pull 远程拉取到本地
adb install -r *.apk 安装apk
adb wait-for-device 等设备的device启动
adb device查看连接的设备
adb shell dmesg 抓kernel的log
adb logcat抓串口log
adb reboot edl进入烧机模式


2.常用repo命令

repo status 查看整个worktree状态
repo branches 查看本地worktree上工作分支情况
repo abandon <分支名字> {<git库名>--all} 删除
git push orign + 路径 向gerrit提交修改
repo sync .同步当前路径的代码

3.git提交冲突:

  • git log 查看最新commit id
  • git reset --hard e33c*****653df3(最新commit id)
  • 同步代码repo sync .
  • cherry pick自己提交的有冲突的代码
  • git status 查看提示有冲突的文件,进行修改
  • git add .提交解决冲突后的代码
  • git cherry-pick --continue 取消拣选操作,提交解决冲突后的代码 或 git commit -a
  • git push ***
<think>我们正在处理一个关于Android 15系统上MediaProvider插入文件失败以及文件打开权限的问题。根据用户提供的引用内容,似乎涉及到目录访问权限的问题,其中尝试访问某些路径时出现了FAILED(失败)的情况,而有些则SUCCESS(成功)。具体来说: - `/storage/emulated/0`:FAILED - `/storage/emulated/0/Download`:FAILED -> 然后SUCCESS(可能是两次尝试?) - `/storage/emulated/0/Android/data/com.android.apitester/files/Documents`:SUCCESS -> SUCCESS 用户特别提到了`MediaProvider`的`insertFileIfNecessary`方法失败和`FileNotFoundException`权限问题。 在Android 15(API级别35)中,Google继续加强了存储权限管理,特别是分区存储(Scoped Storage)的严格执行。从Android 11(API级别30)开始,应用默认被限制在分区存储中,只能访问特定的外部存储目录(如应用的私有目录和媒体集合)。在Android 15中,这一限制可能更加严格。 ### 问题分析 1. **`MediaProvider.insertFileIfNecessary`失败**:这个方法通常用于向媒体库插入文件记录。失败可能是由于以下原因: - 应用没有正确的存储权限(例如,没有`READ_EXTERNAL_STORAGE`或`WRITE_EXTERNAL_STORAGE`权限,但在Android 10及以上,这些权限对于媒体文件的读写作用有限,更多依赖媒体存储API)。 - 在Android 10及以上,应用需要使用`MediaStore` API来创建和访问公共目录的文件,而不是直接使用文件路径。 2. **`FileNotFoundException`权限问题**:当应用试图通过文件路径直接访问文件时,可能会因为分区存储的限制而失败。特别是,如果应用没有权限访问该文件所在的目录,或者该文件不在应用可以访问的范围内(如应用私有目录、媒体集合中的文件、或通过Storage Access Framework获取的文件)。 ### 解决方案 #### 1. 使用MediaStore API 对于媒体文件(图片、视频、音频、下载文件等),应使用`MediaStore` API进行插入、查询和修改。 - **插入文件到媒体库**: 使用`ContentResolver.insert`方法,指定要插入的媒体类型(例如`MediaStore.Images.Media.EXTERNAL_CONTENT_URI`)和媒体信息(通过`ContentValues`)。然后通过`ContentResolver.openOutputStream`获取输出流来写入文件。 示例代码: ```java ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DISPLAY_NAME, "my_image.jpg"); values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/MyApp"); ContentResolver resolver = context.getContentResolver(); Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); if (uri != null) { try (OutputStream outputStream = resolver.openOutputStream(uri)) { // 将图像数据写入outputStream } catch (IOException e) { e.printStackTrace(); // 处理异常 } } ``` 这样,文件会被创建在指定的相对路径下,并且媒体库会更新。 #### 2. 处理非媒体文件 对于非媒体文件(如下载的PDF、文本文件等),如果它们不在应用私有目录中,则可能需要使用Storage Access Framework(SAF)来让用户选择保存位置。或者,如果应用需要访问特定的目录(如Downloads目录),则需要注意: - 在Android 10及以上,应用可以无需权限访问下载集合(`MediaStore.Downloads`)中的文件,但仅限于应用自己创建的文件。对于其他文件,需要用户通过SAF选择。 - 对于下载文件,可以使用`MediaStore.Downloads`集合(API级别29及以上): ```java ContentValues values = new ContentValues(); values.put(MediaStore.Downloads.DISPLAY_NAME, "document.pdf"); values.put(MediaStore.Downloads.MIME_TYPE, "application/pdf"); values.put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS + "/MyApp"); Uri uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values); // 然后使用ContentResolver.openOutputStream写入 ``` #### 3. 权限声明 确保在AndroidManifest.xml中声明必要的权限: ```xml <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ``` 注意:在Android 10(API级别29)及以上,当应用以Android 10及以上为目标平台时,`WRITE_EXTERNAL_STORAGE`权限在访问媒体文件时不再有效,必须使用`MediaStore` API。但是,对于访问下载集合中的文件(API 29+)或访问应用私有目录,不需要这些权限。 #### 4. 处理Android 15的进一步限制 在Android 15中,可能需要额外的步骤: - **检查是否有权限**:使用`Environment.isExternalStorageManager()`检查是否获得了管理所有文件的权限(MANAGE_EXTERNAL_STORAGE)。但注意,Google Play对使用此权限的应用有严格限制,通常不建议使用,除非是文件管理器类应用。 - **使用SAF**:对于需要访问其他应用创建的文件,使用`Intent.ACTION_OPEN_DOCUMENT`或`Intent.ACTION_CREATE_DOCUMENT`来让用户选择文件或目录。 #### 5. 处理FileNotFoundException 如果遇到`FileNotFoundException`,可能是因为: - 文件路径不可访问(由于分区存储)。 - 文件不存在。 - 路径指向一个目录而不是文件。 解决方案:避免直接使用文件路径,转而使用`ContentResolver`打开文件描述符或流。 ### 示例:插入一个图片文件并避免权限问题 ```java private void saveImageToGallery(Context context, Bitmap bitmap, String fileName) { ContentResolver resolver = context.getContentResolver(); ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName); values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES); Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); if (uri == null) { // 插入失败,可能是权限问题或存储不可用 return; } try (OutputStream os = resolver.openOutputStream(uri)) { if (os != null) { bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os); Toast.makeText(context, "图片保存成功", Toast.LENGTH_SHORT).show(); } } catch (IOException e) { e.printStackTrace(); // 删除失败的记录 resolver.delete(uri, null, null); Toast.makeText(context, "图片保存失败", Toast.LENGTH_SHORT).show(); } } ``` ### 总结 在Android 15上,由于分区存储的严格执行,应用应当: - 使用`MediaStore` API来创建和访问媒体文件和下载集合中的文件。 - 避免直接使用文件路径访问公共目录。 - 对于非媒体文件或需要访问其他目录的情况,使用Storage Access Framework(SAF)让用户选择。 - 确保在AndroidManifest.xml中声明了必要的权限,并动态请求(如果需要)。 如果问题仍然存在,请检查是否在AndroidManifest.xml中正确声明了权限,并且应用的目标SDK版本设置正确。 ### 相关问题 1.Android 15中,如何请求管理所有文件的权限(MANAGE_EXTERNAL_STORAGE)? 2. 如何使用Storage Access Framework(SAF)让用户选择保存文件的位置? 3.Android 15中,如何查询媒体库中的文件? 4. 处理`MediaStore`插入失败的错误码有哪些? [^1]: 提供的引用内容显示了目录访问权限测试结果,其中部分目录访问失败(FAILED),部分成功(SUCCESS)。这可能暗示了在Android 15上,应用对某些公共目录的访问受到了限制,需要采用新的API进行文件操作。 </think>### Android 15 解决 MediaProvider 文件插入和权限问题指南 在 Android 15 中,Google 进一步加强了存储权限管理(特别是 Scoped Storage 限制),这可能导致 `MediaProvider.insertFileIfNecessary()` 失败和文件访问异常。以下是系统性的解决方案: #### 1. 检查运行时权限(关键步骤) ```kotlin // 在 Activity/Fragment 中请求必要权限 val permissions = arrayOf( Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO, Manifest.permission.READ_MEDIA_AUDIO ) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { requestPermissions(permissions, REQUEST_CODE) } ``` - ✅ **Android 15 变更**:废弃了传统的 `READ_EXTERNAL_STORAGE`,改用细粒度的媒体类型权限 - 📌 注意:文件操作前必须动态请求权限,即使已在 Manifest 声明[^1] #### 2. 修复 MediaStore 插入失败 (`insertFileIfNecessary`) ```kotlin // 使用 MediaStore API 插入文件 fun saveImage(context: Context, bitmap: Bitmap) { val values = ContentValues().apply { put(MediaStore.Images.Media.DISPLAY_NAME, "photo_${System.currentTimeMillis()}.jpg") put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/MyApp") } val resolver = context.contentResolver val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values) uri?.let { resolver.openOutputStream(it)?.use { stream -> bitmap.compress(Bitmap.CompressFormat.JPEG, 95, stream) } } ?: throw FileNotFoundException("MediaProvider insert failed") } ``` - ✅ 必须指定 `RELATIVE_PATH`(Android 10+ 强制要求) - ✅ 使用 `ContentResolver.openOutputStream` 而非直接文件路径 #### 3. 解决 FileNotFoundException **场景**:访问 `/storage/emulated/0/Download` 等共享目录 ```kotlin // 正确访问共享文件的方式 val uri = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) val projection = arrayOf(MediaStore.Downloads._ID, MediaStore.Downloads.DISPLAY_NAME) val selection = "${MediaStore.Downloads.DISPLAY_NAME} = ?" val args = arrayOf("target_file.pdf") context.contentResolver.query(uri, projection, selection, args, null)?.use { cursor -> if (cursor.moveToFirst()) { val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Downloads._ID)) val fileUri = ContentUris.withAppendedId(uri, id) // 通过 URI 访问文件 context.contentResolver.openFileDescriptor(fileUri, "r")?.use { pfd -> // 文件操作... } } } ``` #### 4. 特殊目录处理(Android/data) ```kotlin // 访问应用专属目录不需要权限 val appSpecificDir = context.getExternalFilesDir(null) val file = File(appSpecificDir, "data.txt") // 直接使用 File API 操作(无需 MediaStore) file.writeText("Private data") ``` #### 5. AndroidManifest.xml 关键配置 ```xml <!-- 适配 Android 13+ 的媒体权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <!-- 管理所有文件权限(谨慎使用,Play Store 审核严格) --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> ``` #### 6. 调试建议 1. 检查 `adb logcat` 错误日志: ``` E/MediaProvider: Insert failed for /storage/emulated/0/DCIM/Camera/IMG.jpg E/AndroidRuntime: java.io.FileNotFoundException: open failed: EACCES (Permission denied) ``` 2. 验证 URI 权限: ```kotlin context.contentResolver.persistedUriPermissions.forEach { Log.d("URI_PERM", "Uri: ${it.uri} 持久化: ${it.isPersisted}") } ``` ### 常见问题根源 1. **权限模型变更**:Android 15 要求使用媒体类型权限替代传统存储权限 2. **路径访问限制**:直接访问 `/storage/emulated/0/` 已被完全禁止 3. **MediaProvider 策略更新**:对非媒体文件的插入操作更严格 4. **SELinux 策略加强**:系统应用权限限制更严格 > ⚠️ **关键提示**:Google Play 要求所有新应用从 2023 年 8 月起必须适配 Android 13(API 33+)。对于文件操作,优先使用 MediaStore API 而非 File API[^1]。 ### 相关问题 1. 如何处理 Android 15 中的 `MANAGE_EXTERNAL_STORAGE` 权限请求流程? 2. 跨应用文件共享时如何保证 URI 权限持久化? 3. 如何为特定文件类型(如 PDF)申请精细化的媒体权限? 4. 在后台 Service 中操作 MediaStore 需要注意哪些限制? 5. Scoped Storage 下如何实现文件管理器类应用的核心功能? [^1]: 根据 Android 15 存储权限模型变更和 MediaProvider 更新策略分析
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值