尽管获得许可,但写入外部存储的权限被拒绝
Posted
技术标签:
【中文标题】尽管获得许可,但写入外部存储的权限被拒绝【英文标题】:Permission denied on writing to external storage despite permission 【发布时间】:2017-11-11 08:37:12 【问题描述】:我有一个 android 7.0 测试设备,我的 APK 目标 = "targetSdkVersion 22",其中:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
与:
final File f = new
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + "DressUpBaby" + photonumber + ".png");
f.createNewFile();
此时我收到警告:
W/System.err: java.io.IOException: Permission denied
如何得到它来保存文件?当我在 Eclipse 上创建它时,这是可行的,但现在我已经更新并移至 Android Studio,它似乎已经破坏了一些东西。
【问题讨论】:
我给你一个提示:Claim a Permission 和 Have a Permission 是两个不同的东西。 您是否在运行时请求了权限:developer.android.com/training/permissions/requesting.html Android marshmallow request permission?的可能重复 Android 7.0 (API level 24) ,所以 targetSdkVersion 22 apk 在这个设备上不能工作!不是吗!? 对于低于 23 的目标 SDK 则无需请求权限.. 【参考方案1】:更新:请参阅Volker Voecking's answer 以获得更好的解决方案
编辑:对于那些没有时间寻找解决方案的人来说,这只是一种解决方法。 *
如果即使授予了权限并且您已经实施了权限检查,您仍然收到 permission denied 错误,
确保您没有针对 api 级别 29:
将 targetSdkVersion 和 compilesdkversion 从 29 更改为 28 或任何其他更低级别。
【讨论】:
非常感谢,我无法在任何地方找到解决我的问题的方法,但它确实有效。 如何在 API 级别 29 的 Android 上解决此问题? 加入问题,我想保留targetApi 29,但似乎无法写入外部存储 谢谢,为学校分配作业意味着我没有时间连续几天纠结为什么我无法阅读文件,这对我来说已经足够了,但我会避免这种情况一个“真实的”情况。 你真的拯救了我的一天!【参考方案2】:如果您以 SDK 29 为目标,并且在成功请求 WRITE_EXTERNAL_STORAGE 权限后仍然收到“权限被拒绝”错误,则应添加
android:requestLegacyExternalStorage="true"
AndroidManifest.xml 中的应用程序定义。
<manifest ... >
<!-- This attribute is "false" by default on apps targeting
Android 10 or higher. -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
见https://developer.android.com/training/data-storage/compatibility
【讨论】:
这解决了问题。非常感谢!【参考方案3】:如果您在 API 级别 23 或更高级别上运行应用,则必须在运行时请求权限。
请求权限:
String[] permissions = Manifest.permission.WRITE_EXTERNAL_STORAGE;
requestPermissions(permissions, WRITE_REQUEST_CODE);
然后处理结果:
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)
switch (requestCode)
case WRITE_REQUEST_CODE:
if(grantResults[0] == PackageManager.PERMISSION_GRANTED)
//Granted.
else
//Denied.
break;
欲了解更多信息,请访问Requesting Permissions at Run Time - Android Doc
【讨论】:
【参考方案4】:Android N 引入了一种新的权限模型,它只在应用真正需要权限时才请求权限,而不是像以前那样在安装过程中请求权限。
使用以下代码请求权限
注意 - 还要在 Manifest 文件中添加所需的权限
如果您不向 Main Activity 请求权限,请传递对上下文/活动的引用
以下示例显示了请求写入外部存储权限的示例,可以同时请求多个权限(谷歌不推荐)。
public class MainActivity extends AppCompatActivity
/**
* Variables for requiesting permissions, API 25+
*/
private int requestCode;
private int grantResults[];
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) if(ContextCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED )
//if you dont have required permissions ask for it (only required for API 23+)
ActivityCompat.requestPermissions(this, new String[]Manifest.permission.WRITE_EXTERNAL_STORAGE,requestCode);
onRequestPermissionsResult(requestCode,new String[]Manifest.permission.WRITE_EXTERNAL_STORAGE,grantResults);
@Override // android recommended class to handle permissions
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults)
switch (requestCode)
case 1:
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED)
Log.d("permission","granted");
else
// permission denied, boo! Disable the
// functionality that depends on this permission.uujm
Toast.makeText(MainActivity.this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();
//app cannot function without this permission for now so close it...
onDestroy();
return;
// other 'case' line to check fosr other
// permissions this app might request
【讨论】:
Android M 引入了新的权限模型,而不是Android N【参考方案5】:这是我在类似情况下所做的:
第 1 步:向清单文件添加权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
第二步:创建权限检查函数
void checkForPermissions()
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED)
// Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE))
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
// This part I didn't implement,because for my case it isn't needed
Log.i(TAG,"Unexpected flow");
else
// No explanation needed; request the permission
ActivityCompat.requestPermissions(this,
new String[]Manifest.permission.WRITE_EXTERNAL_STORAGE,
MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE);
// MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE is an
// app-defined int constant. The callback method gets the
// result of the request.
else
// Permission is already granted, call the function that does what you need
onFileWritePermissionGranted();
第 3 步:实现 onRequestPermissionsResult
@Override
public void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] grantResults)
switch (requestCode)
case MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE:
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED)
// permission was granted, yay!
// call the function that does what you need
onFileWritePermissionGranted();
else
Log.e(TAG, "Write permissions has to be granted tp ATMS, otherwise it cannot operate properly.\n Exiting the program...\n");
return;
// other 'case' lines to check for other
// permissions this app might request.
第四步:使用权限:)
void onFileWritePermissionGranted()
// Write to some file
【讨论】:
【参考方案6】:与答案“确保您没有针对 api 级别 29...”相关,我找到了这个。
https://developer.android.com/reference/android/os/Environment#getExternalStorageDirectory
。。。。。。。。。。
"getExternalStoragePublicDirectory"
此方法在 API 级别 29 中已弃用。
为了改善用户隐私,不推荐直接访问共享/外部存储设备。当应用程序以 Build.VERSION_CODES.Q 为目标时,从此方法返回的路径不再可供应用程序直接访问。通过迁移到 Context#getExternalFilesDir(String)、MediaStore 或 Intent#ACTION_OPEN_DOCUMENT 等替代方案,应用可以继续访问存储在共享/外部存储上的内容。
。。。。。。。。。。
因此,在这种情况下,您必须将“getExternalStoragePublicDirectory”替换为其他方法。
【讨论】:
【参考方案7】:在最新版本的android中,请求权限有点不同,例如, 如果您想先访问存储权限 您需要从 Manifest.xml 请求访问权限
喜欢:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
最重要的是不要忘记从 Manifets.xml 的应用程序标签中允许这样做,
`android:requestLegacyExternalStorage="true"'
//并从您的活动创建方法来请求运行权限 在任何需要的地方调用这个函数。
private boolean requestPermission()
boolean request=true;
String[] permissions=Manifest.permission.CAMERA,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION;
if (permissions.length!=0)
ActivityCompat.requestPermissions(this,permissions,102);
request= true;
else
toastMsg("Permissions Denied");
println("Permissions not allowed by User...");
request=false;
return request;
【讨论】:
以上是关于尽管获得许可,但写入外部存储的权限被拒绝的主要内容,如果未能解决你的问题,请参考以下文章