尽管有权限,但写入外部存储的权限被拒绝
Permission denied on writing to external storage despite permission
我有一个 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 它似乎已经损坏了一些东西。
如果您 运行 您的应用处于 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;
}
}
Android N 引入了一种新的权限模型,它只在应用真正需要时才请求权限,而不是像以前那样在安装过程中请求权限。
使用以下代码请求权限
注意 - 还要在 Manifest 文件中添加所需的权限
如果您不向 Main Activity 请求权限,请将引用传递给 context/activity
以下示例显示了请求写入外部存储权限的示例,可以同时请求多个权限(google 不推荐)。
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
}
}
这是我在类似情况下所做的:
第 1 步:向清单文件添加权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
第 2 步:创建权限检查函数
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
}
更新:参见以获得更好的解决方案
编辑:对于那些没有时间寻找解决方案的人来说,这只是一种解决方法。 *
如果您收到 permission denied 错误,即使已授予权限并且您已经实施了权限检查,
确保你没有瞄准 api 29 级:
将targetSdkVersion和compilesdkversion从29更改为28 或任何其他较低级别。
如果您以 SDK 29 为目标,但在成功请求 WRITE_EXTERNAL_STORAGE 权限后仍然出现 "permission denied" 错误,您应该添加
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
与“确保你没有瞄准 api 级别 29...”的答案相关,我找到了这个。
https://developer.android.com/reference/android/os/Environment#getExternalStorageDirectory
。。。。。。。。。
“getExternalStoragePublicDirectory”
此方法已在 API 级别 29 中弃用。
为了提高用户隐私,直接访问 shared/external 存储设备已被弃用。当应用面向 Build.VERSION_CODES.Q 时,应用无法再直接访问从此方法返回的路径。通过迁移到 Context#getExternalFilesDir(String)、MediaStore 或 Intent#ACTION_OPEN_DOCUMENT.
等替代方案,应用可以继续访问存储在 shared/external 存储中的内容
。。。。。。。。。
所以,在这种情况下,您必须用其他方法替换“getExternalStoragePublicDirectory”。
在最新版本的 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"'
//并从您的 activity 创建方法来请求 运行 权限
在需要的任何地方从 activity 调用此函数。
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;
}
我有一个 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 它似乎已经损坏了一些东西。
如果您 运行 您的应用处于 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;
}
}
Android N 引入了一种新的权限模型,它只在应用真正需要时才请求权限,而不是像以前那样在安装过程中请求权限。
使用以下代码请求权限
注意 - 还要在 Manifest 文件中添加所需的权限
如果您不向 Main Activity 请求权限,请将引用传递给 context/activity
以下示例显示了请求写入外部存储权限的示例,可以同时请求多个权限(google 不推荐)。
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
}
}
这是我在类似情况下所做的:
第 1 步:向清单文件添加权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
第 2 步:创建权限检查函数
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
}
更新:参见
编辑:对于那些没有时间寻找解决方案的人来说,这只是一种解决方法。 *
如果您收到 permission denied 错误,即使已授予权限并且您已经实施了权限检查,
确保你没有瞄准 api 29 级:
将targetSdkVersion和compilesdkversion从29更改为28 或任何其他较低级别。
如果您以 SDK 29 为目标,但在成功请求 WRITE_EXTERNAL_STORAGE 权限后仍然出现 "permission denied" 错误,您应该添加
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
与“确保你没有瞄准 api 级别 29...”的答案相关,我找到了这个。
https://developer.android.com/reference/android/os/Environment#getExternalStorageDirectory
。。。。。。。。。
“getExternalStoragePublicDirectory”
此方法已在 API 级别 29 中弃用。
为了提高用户隐私,直接访问 shared/external 存储设备已被弃用。当应用面向 Build.VERSION_CODES.Q 时,应用无法再直接访问从此方法返回的路径。通过迁移到 Context#getExternalFilesDir(String)、MediaStore 或 Intent#ACTION_OPEN_DOCUMENT.
等替代方案,应用可以继续访问存储在 shared/external 存储中的内容。。。。。。。。。
所以,在这种情况下,您必须用其他方法替换“getExternalStoragePublicDirectory”。
在最新版本的 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"'
//并从您的 activity 创建方法来请求 运行 权限 在需要的任何地方从 activity 调用此函数。
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;
}