Reputation: 1045
I have an Android 7.0 test device and my APK targets = "targetSdkVersion 22", with:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
with:
final File f = new
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + "DressUpBaby" + photonumber + ".png");
f.createNewFile();
and at this point I get the warning:
W/System.err: java.io.IOException: Permission denied
How to get it to save the file? This was working when I created this on Eclipse, but now that I have updated and moved to Android Studio it seems to have broken something.
Upvotes: 20
Views: 50410
Reputation: 383
This article really helped me.
1. Request MANAGE_EXTERNAL_STORAGE permission :
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ourcodeworld.plugins.capacitornativefilepicker"
xmlns:tools="http://schemas.android.com/tools"
>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage"/>
</manifest>
2. Request External Storage Permissions
After declaring the permissions, you need to request the regular READ_EXTERNAL_STORAGE
and WRITE_EXTERNAL_STORAGE
permissions. Note that we don't include the MANAGE_EXTERNAL_STORAGE
, because if you request it, when verifying if you have access or not, the mentioned permission will always return denied, even though the user has already granted access:
ActivityCompat.requestPermissions(
this,
new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.MANAGE_EXTERNAL_STORAGE
},
1
);
3. Checking permission of MANAGE_EXTERNAL_STORAGE
Now, instead of the regular permissions request to handle the mentioned permission, you need instead to verify whether the access to the external storage is allowed. In case it isn't, you need to launch a new activity showing the system's dialog where the user should manually allow the access to the external storage to your app like this:
import android.os.Environment;
import android.content.Intent;
import android.provider.Settings;
import android.net.Uri;
// If you have access to the external storage, do whatever you need
if (Environment.isExternalStorageManager()){
// If you don't have access, launch a new activity to show the user the system's dialog
// to allow access to the external storage
}else{
Intent intent = new Intent();
intent.setAction(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
Uri uri = Uri.fromParts("package", this.getPackageName(), null);
intent.setData(uri);
startActivity(intent);
}
So when the user installs the app and try to access the file picker, if the access to all files isn't granted yet, the following system intent will be launched:
The user will have to explicitly allow access to all files if you want to read files from any source in the device and that should be enough.
Upvotes: 2
Reputation: 1420
in latest version of android making request permission bit different for example, if you want access storage permission first you need request access permission from Manifest.xml
like:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
and most important don't forget to allow this from application tag of Manifets.xml,
`android:requestLegacyExternalStorage="true"'
//and created method from your activity to request run to permission call this function from activity anywhere required.
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;
}
Upvotes: 1
Reputation: 1131
UPDATE: See Volker Voecking's answer for a better solution
EDIT: This is simply a workaround for those who don't have time to look for a solution. *
If you get permission denied error even when the permissions are granted and you already implemented permission checks,
Change targetSdkVersion and compilesdkversion from 29 to 28 or any other lower level.
Upvotes: 20
Reputation:
Related to the answer "make sure you're not targetting api level 29...", I found this.
https://developer.android.com/reference/android/os/Environment#getExternalStorageDirectory
。。。。。。。。。。
"getExternalStoragePublicDirectory"
This method was deprecated in API level 29.
To improve user privacy, direct access to shared/external storage devices is deprecated. When an app targets Build.VERSION_CODES.Q, the path returned from this method is no longer directly accessible to apps. Apps can continue to access content stored on shared/external storage by migrating to alternatives such as Context#getExternalFilesDir(String), MediaStore, or Intent#ACTION_OPEN_DOCUMENT.
。。。。。。。。。。
so, in that case you have to replace "getExternalStoragePublicDirectory" with those other methods.
Upvotes: 1
Reputation: 5583
If you target SDK 29 and you still get a "permission denied" error after successfully requesting the WRITE_EXTERNAL_STORAGE permission you should add
android:requestLegacyExternalStorage="true"
to the application definition in AndroidManifest.xml.
<manifest ... >
<!-- This attribute is "false" by default on apps targeting
Android 10 or higher. -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
see https://developer.android.com/training/data-storage/compatibility
Upvotes: 18
Reputation: 1490
Here is what I did in a similar situation:
<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();
}
}
@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
}
Upvotes: 1
Reputation: 71
Android N introduces a new model of permissions which only asks for permissions when the app really needs it rather than during installation like it previously did.
Use the following code to ask for permissions
Note - Also add the required permissions in the Manifest file
If you aren't asking permissions from Main Activity pass the reference to the context/activity
The following example shows example for asking permissions to Write to external storage, multiple permisisons can be requiested at the same time (Not recommended by 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
}
}
Upvotes: 7
Reputation: 1122
If you're running your app on API level 23 or greater you have to request permission at runtime.
Request permission:
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
requestPermissions(permissions, WRITE_REQUEST_CODE);
Then handle the result:
@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;
}
}
For more information visit Requesting Permissions at Run Time - Android Doc
Upvotes: 12