Runtime Permissions, Files, and ACTION_SEND

The CommonsBlog


Runtime Permissions, Files, and ACTION_SEND

There has been pressure over the past couple of years for developers to move to content:// Uri values instead of file:// Uri values, particularly for things like ACTION_SEND. Android 6.0’s runtime permission system increases that pressure a bit further.

READ_EXTERNAL_STORAGE is a dangerous permission on Android 6.0, and therefore is subject to the runtime permission system if yourtargetSdkVersion is 23 or higher. This does not directly affect the sending app in an ACTION_SEND scenario, as that app could be writing togetExternalFilesDir() or getExternalCacheDir(), neither of which require any permissions as of Android 4.4. However, those locations are app-specific, and so while the sender’s locations are accessible by other apps handling ACTION_SEND, the recipient needs to haveREAD_EXTERNAL_STORAGE. Some developers will be trying to move away from having such a permission, as they have to prompt users for it.

Worse, there is a corner case that will trip up many implementers of ACTION_SEND. Suppose the following occurs:

  • The user installs the recipient app, but does not run it, or does not do anything when running it that would trigger requestPermissions() forREAD_EXTERNAL_STORAGE

  • The user then uses some other app’s ACTION_SEND capability to try to send some content to the recipient app, in the form of a file:// Uripointing to a file on external storage

  • The recipient app is buggy, by not handling runtime permissions properly in its ACTION_SEND-handling Activity, believing (incorrectly) that the permission must already have been granted by this point

Stack Overflow user Daniele B ran into this, where Gmail and Hangouts were recipient apps with the bug. If Google can’t get this right, many other developers won’t get it right either.

If you are implementing an ACTION_SEND-handling Activity, and you plan on supporting file:// Uri values, you need to include the appropriate runtime permission checks in that Activity.

However, if you are the sender of ACTION_SEND Intents, this is a fine reason to move off of file:// Uri values and use content:// Uri values instead. This eliminates the whole READ_EXTERNAL_STORAGE requirement in the first place.

FileProvider provides a canned ContentProvider implementation for serving up files. However:

  • The documentation is wrong, claiming that <external-path> points to getExternalFilesDir(), when it really points toEnvironment.getExternalStorageDirectory(). Since I filed the issue two years ago, and it is still outstanding, it is unlikely that Google will ever fix the documentation.

  • Many recipients of ACTION_SEND will incorrectly assume that Uri is a file and attempt to get a local filesystem path from MediaStore. Such developers are misguided, as there is no requirement that the Uri be from MediaStore, let alone have a filesystem path that the recipient can access (e.g., the file is on removable storage on Android 4.4+). However, you as the sender have to put up with misguided developers. Some apps will behave better if you subclass FileProvider and put a null DATA column in the results returned from query()MyLegacyCompatCursorWrapper can help with this, as seen in this sample app covered in this really nifty book.

We are likely to stumble over these sorts of cases from time to time over the next year, as we collectively apply the runtime permissions system to our apps and see where things go haywire. When interacting with other apps, the fewer dangerous permissions you can require them to have, the better off you will be in general.

— Oct 07, 2015  

Copyright © 2015 CommonsWare, LLC — All Rights Reserved

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,你需要导入React Native中的NativeModules和PermissionsAndroid: ```javascript import { NativeModules, PermissionsAndroid } from 'react-native'; const { MyNativeModule } = NativeModules; ``` 然后,你需要在你的组件中调用MyNativeModule中的方法来请求文件访问权限: ```javascript async requestFileAccessPermission() { try { const granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.MANAGE_ALL_FILES_ACCESS_PERMISSION, { 'title': '文件访问权限', 'message': '请允许我们访问您的文件以便完成操作' } ) if (granted === PermissionsAndroid.RESULTS.GRANTED) { // 权限已授予,可以开始使用原生模块了 MyNativeModule.useMyNativeModule(); } else { // 权限被拒绝,需要告知用户 console.warn("权限被拒绝"); } } catch (err) { console.warn(err) } } ``` 最后,你需要在MyNativeModule.java中实现useMyNativeModule()方法,使用MANAGE_ALL_FILES_ACCESS_PERMISSION权限来操作文件: ```java @ReactMethod public void useMyNativeModule() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // Android 11及以上版本需要使用MANAGE_EXTERNAL_STORAGE权限 if (Environment.isExternalStorageManager()) { // 已获取文件访问权限,可以执行相关操作 // ... } else { // 未获取文件访问权限,需要引导用户去设置中开启 Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION); intent.setData(Uri.parse("package:" + getReactApplicationContext().getPackageName())); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getReactApplicationContext().startActivity(intent); } } else { // Android 10及以下版本可以直接使用MANAGE_ALL_FILES_ACCESS_PERMISSION权限 // ... } } ``` 需要注意的是,Android 11及以上版本需要使用MANAGE_EXTERNAL_STORAGE权限来访问外部存储器,而MANAGE_ALL_FILES_ACCESS_PERMISSION只能用于访问应用内部存储器。如果你想要访问外部存储器,需要引导用户去设置中开启该权限。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值