安卓Nougat中点击按钮截图分享遇权限拒绝问题求助
你的问题核心是Android 7.0(API 24)引入的StrictMode安全政策:跨应用传递file://类型的URI会触发权限拒绝——这种方式会直接暴露应用私有文件给其他应用,违反了安卓沙箱机制。你之前申请的WRITE_EXTERNAL_STORAGE权限其实在这里完全没必要,因为你把截图存在了应用的私有缓存目录(getCacheDir()),真正需要调整的是用FileProvider生成安全的content://类型URI来共享文件。
下面是具体的修复步骤:
1. 在AndroidManifest.xml中注册FileProvider
在<application>标签内添加FileProvider的注册信息,注意authorities要使用你的应用包名+.fileprovider格式(避免和其他应用冲突):
<application ...> ... <provider android:name="androidx.core.content.FileProvider" android:authorities="com.beaconites.gratuitycalculator.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> ... </application>
2. 创建文件路径配置文件
在res/xml目录下新建file_paths.xml文件(如果xml目录不存在就手动创建),配置允许共享的缓存目录:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 对应应用的私有缓存目录 --> <cache-path name="shared_cache" path="." /> </paths>
3. 修改分享方法中的URI生成逻辑
更新你的Share_result()方法,把Uri.fromFile(file)替换成FileProvider生成的安全URI,同时添加读取权限标记,确保接收方应用能正常访问文件:
public void Share_result() { String uniqueId = getTodaysDate() + "_" + getCurrentTime() + "_" + Math.random(); Bitmap bitmap; View v = findViewById(R.id.snapview); mAdView.setVisibility(View.INVISIBLE); button.setVisibility(View.INVISIBLE); v.setDrawingCacheEnabled(true); bitmap = v.getDrawingCache(); try { File file = new File(getApplicationContext().getCacheDir(), uniqueId + ".png"); FileOutputStream fOut = new FileOutputStream(file); bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut); fOut.flush(); fOut.close(); file.setReadable(true, false); final Intent intent = new Intent(android.content.Intent.ACTION_SEND); // 替换为FileProvider生成的content类型URI Uri contentUri = FileProvider.getUriForFile( this, "com.beaconites.gratuitycalculator.fileprovider", // 和Manifest中authorities保持一致 file ); intent.putExtra(Intent.EXTRA_STREAM, contentUri); // 添加权限标记,允许接收方读取该URI指向的文件 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.putExtra(Intent.EXTRA_TEXT, "Let me recommend you this application.\n https://play.google.com/store/apps/details?id=com.beaconites.gratuitycalculator "); intent.putExtra(Intent.EXTRA_TITLE, "UAE Gratuity Calculator"); intent.setType("image/*"); startActivity(Intent.createChooser(intent, "choose one")); mAdView.setVisibility(View.VISIBLE); button.setVisibility(View.VISIBLE); } catch (Exception e) { e.printStackTrace(); } v.setDrawingCacheEnabled(false); }
4. 简化权限请求(可选)
因为你现在把文件存在应用私有缓存目录,完全不需要申请WRITE_EXTERNAL_STORAGE权限,所以可以直接删除checkAndRequestPermissions()相关的代码——这样还能减少用户授权的步骤,提升应用体验。
补充说明
在Android 7.0之前,系统允许跨应用传递file:// URI,但这种方式存在安全风险:其他应用可能通过这个URI随意访问甚至修改你的应用私有文件。Nougat之后的StrictMode强制要求用FileProvider来安全共享文件,通过content:// URI精准控制访问权限,只有你明确授权的应用才能读取对应文件。
内容的提问来源于stack exchange,提问作者Tousif Irshad

