Reputation: 1001
I am targeting my Android app for Android 13 (API 33)
The WRITE_EXTERNAL_STORAGE permission seems to be working fine below API 33 i.e. Android 12 and less but the runtime permission popup for WRITE_EXTERNAL_STORAGE won't appear when running the app on Android 13.
My Android app creates one keystore file in app's private storage.
The behaviour changes for Android 13 mention this:
If your app targets Android 13, you must request one or more new permissions instead of the READ_EXTERNAL_STORAGE.
The new permissions are:
I didn't find any information about this in the official documentation. The documentation is focusing on media files only without any word about other file types.
https://developer.android.com/about/versions/13/behavior-changes-13#granular-media-permissions
Upvotes: 97
Views: 156561
Reputation: 320
If you want to write files then you dont need permission use
File directory = getExternalFilesDir("Folder name");
if (!directory.exists()) {
if (!directory.mkdir()) {
Toast.makeText(this, "Can't create directory", Toast.LENGTH_SHORT).show();
return;
}
else Toast.makeText(this, "Directory created", Toast.LENGTH_SHORT).show();
}
Upvotes: 1
Reputation: 93
I Android 13 and above WRITE_EXTERNAL_STORAGE is granted by default and you not have to grant it by code. e.g
if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.TIRAMISU){
saveImage();
}else {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_WRITE_EXTERNAL_STORAGE);
} else {
saveImage();
}
}
Upvotes: 9
Reputation: 47
You don't need to request permission in android 13> You have to control the version and make the actions
Upvotes: 1
Reputation: 399
This is worked for me for react native
// other imports
import DeviceInfo from "react-native-device-info"
// other states
const [apiLevel, setAPILevel] = useState(null);
//update your state variable
useEffect(()=>{
const getDeviceInfo = async()=>{
const apiLevel = DeviceInfo.getSystemVersion();
setAPILevel(apiLevel);
console.log("🚀 ~ file: app.tsx:115 ~ getDeviceInfo ~ apiLevel:",
apiLevel)
}
getDeviceInfo();
},[])
if (Platform.OS === "android" && apiLevel < 13) {
console.log("🚀 ~ file: SingleCategoryScreen.tsx:327 ~
downloadAllLectureVideos ~ Platform.OS:", Platform.OS)
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
)
if (granted !== PermissionsAndroid.RESULTS.GRANTED) {
console.log("Permission denied. Cannot download videos.");
setIsDownloading(false)
return
}
}
Upvotes: 1
Reputation: 937
TO CHECK WRITE_EXTERNAL_STORAGE For Android API 31 and aove
public static boolean isGrantedPermissionWRITE_EXTERNAL_STORAGE(Activity activity) {
int version = Build.VERSION.SDK_INT;
if( version <= 32 ) {
boolean isAllowPermissionApi28 = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED ;
Log.i("general_em","isGrantedPermissionWRITE_EXTERNAL_STORAGE() - isAllowPermissionApi28: " + isAllowPermissionApi28);
return isAllowPermissionApi28;
} else {
boolean isAllowPermissionApi33 = Environment.isExternalStorageManager();
Log.i("general_em","isGrantedPermissionWRITE_EXTERNAL_STORAGE() - isAllowPermissionApi33: " + isAllowPermissionApi33);
return isAllowPermissionApi33;
}
}
Upvotes: 1
Reputation: 63
Use ( READ_MEDIA_IMAGES ) instead of ( WRITE_EXTERNAL_STORAGE ) If you are using sdk 33.
Upvotes: 1
Reputation: 1042
You can find documentation for accessing non-media files at Android official documentation or "How to Save a File in Shared Storage Location in Android 13". From Android 10 onwards, if you want to write a file which is intended to be accessible directly by other apps (such as File manager) or user, then you have to write it onto Shared Storage location. This has to be done in 3 steps:
Step 1: Launch System Picker to choose the destination by the user.
private ActivityResultLauncher<Intent> launcher; // Initialise this object in Activity.onCreate()
private Uri baseDocumentTreeUri;
public void launchBaseDirectoryPicker() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
launcher.launch(intent);
}
Step 2: Receive the chosen destination as Uri returned by System Picker in onActivityResult(). Here, you can optionally persist the permissions and Uri for future use.
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
baseDocumentTreeUri = Objects.requireNonNull(result.getData()).getData();
final int takeFlags = (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// take persistable Uri Permission for future use
context.getContentResolver().takePersistableUriPermission(result.getData().getData(), takeFlags);
SharedPreferences preferences = context.getSharedPreferences("com.example.fileutility", Context.MODE_PRIVATE);
preferences.edit().putString("filestorageuri", result.getData().getData().toString()).apply();
} else {
Log.e("FileUtility", "Some Error Occurred : " + result);
}
}
Step 3: Write content into a file.
public void writeFile(String fileName, String content) {
try {
DocumentFile directory = DocumentFile.fromTreeUri(context, baseDocumentTreeUri);
DocumentFile file = directory.createFile("text/*", fileName);
ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(file.getUri(), "w");
FileOutputStream fos = new FileOutputStream(pfd.getFileDescriptor());
fos.write(content.getBytes());
fos.close();
} catch (IOException e) {
}
}
Upvotes: 4
Reputation: 2425
TLDR: You don't.
From Google's official documentation:
"If your app targets Android 11, both the WRITE_EXTERNAL_STORAGE permission and the WRITE_MEDIA_STORAGE privileged permission no longer provide any additional access."
So in effect, if you were to request WRITE_EXTERNAL_STORAGE on Android 11 or later, you would be requesting nothing. This is the whole point of Android's migration to scoped storage, which effectively prevents apps from reading or writing to the storage directories of other apps UNLESS they are accessing specific file types (e.g. media, using the permissions you mentioned) or are granted special file manager permissions by Google themselves. For more insight into scoped storage, see this well written article, but TLDR security and leftover files from app uninstalls were the big reasons Google did this.
So if you really want to write files, either make sure you're only writing to your app's designated storage directories, in which case you won't need any permissions at all, or if you really need to write to a directory your app doesn't own get that file manager permission from Google (how to get that permission)
Upvotes: 89