android9 对sdcard,usb无写入权限,可以通过Do
2021-03-26 本文已影响0人
中v中
manifest无需配置权限
代码如下:
activity:
package io.wuzz.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.provider.DocumentsContract;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.RadioGroup;
import android.widget.Switch;
import android.widget.Toast;
import java.io.File;
public class MainActivity extends AppCompatActivity {
Vm myViewModel1;
Button but1, but2;
Switch aSwitch;
String ROOT = getUSBDiskPath();
String PATH = ROOT + "/testfolder";
Context context;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
but1 = findViewById(R.id.button);
but2 = findViewById(R.id.button2);
aSwitch = findViewById(R.id.switch1);
context = this;
myViewModel1 = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(Vm.class);
but1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
File f = new File(ROOT + "/testabcdef");
boolean b = DocumentsUtils.mkdirs(context,f);
Log.d("====1",b+""); // truue
File f1 = new File(ROOT+"/testxyz");
boolean b1 = f1.mkdirs();
Log.d("====2",b1+""); // false
}
});
but2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onStart() {
super.onStart();
// 加载权限,并建立PATH目录
if (DocumentsUtils.checkWritableRootPath(this, PATH)) {
showOpenDocumentTree();
}
}
private void showOpenDocumentTree() {
Intent intent = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
StorageManager sm = getSystemService(StorageManager.class);
StorageVolume volume = sm.getStorageVolume(new File(ROOT));
if (volume != null) {
intent = volume.createAccessIntent(null);
}
}
if (intent == null) {
intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
}
startActivityForResult(intent, DocumentsUtils.OPEN_DOCUMENT_TREE_CODE_USB);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case DocumentsUtils.OPEN_DOCUMENT_TREE_CODE_USB:
if (data != null && data.getData() != null) {
Uri uri = data.getData();
DocumentsUtils.saveTreeUri(this, ROOT, uri);
}
break;
default:
break;
}
}
public static String getUSBDiskPath(){
String path = null;
File f = new File("/storage");
File[] files = f.listFiles();
for(File file : files){
if(file.getAbsolutePath().contains("Udisk")){
path = file.getAbsolutePath();
break;
}
}
return path;
}
}
DocumentUtils代码:
package io.wuzz.myapplication;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.preference.PreferenceManager;
import android.provider.DocumentsContract;
import android.util.Log;
import androidx.documentfile.provider.DocumentFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
public class DocumentsUtils {
private static final String TAG = "app";
public static final int OPEN_DOCUMENT_TREE_CODE_SDCARD = 8000;
public static final int OPEN_DOCUMENT_TREE_CODE_USB = 8001;
private static List<String> sExtSdCardPaths = new ArrayList<>();
private DocumentsUtils() {
}
public static void cleanCache() {
sExtSdCardPaths.clear();
}
/**
* Get a list of external SD card paths. (Kitkat or higher.)
*
* @return A list of external SD card paths.
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
private static String[] getExtSdCardPaths(Context context) {
if (sExtSdCardPaths.size() > 0) {
return sExtSdCardPaths.toArray(new String[0]);
}
for (File file : context.getExternalFilesDirs("external")) {
if (file != null && !file.equals(context.getExternalFilesDir("external"))) {
int index = file.getAbsolutePath().lastIndexOf("/Android/data");
if (index < 0) {
Log.w(TAG, "Unexpected external file dir: " + file.getAbsolutePath());
} else {
String path = file.getAbsolutePath().substring(0, index);
try {
path = new File(path).getCanonicalPath();
} catch (IOException e) {
// Keep non-canonical path.
}
sExtSdCardPaths.add(path);
}
}
}
if (sExtSdCardPaths.isEmpty()) sExtSdCardPaths.add("/storage/sdcard1");
return sExtSdCardPaths.toArray(new String[0]);
}
/**
* Determine the main folder of the external SD card containing the given file.
*
* @param file the file.
* @return The main folder of the external SD card containing this file, if the file is on an SD
* card. Otherwise,
* null is returned.
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
private static String getExtSdCardFolder(final File file, Context context) {
String[] extSdPaths = getExtSdCardPaths(context);
try {
for (int i = 0; i < extSdPaths.length; i++) {
if (file.getCanonicalPath().startsWith(extSdPaths[i])) {
return extSdPaths[i];
}
}
} catch (IOException e) {
return null;
}
return null;
}
/**
* Determine if a file is on external sd card. (Kitkat or higher.)
*
* @param file The file.
* @return true if on external sd card.
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
public static boolean isOnExtSdCard(final File file, Context c) {
return getExtSdCardFolder(file, c) != null;
}
/**
* Get a DocumentFile corresponding to the given file (for writing on ExtSdCard on Android 5).
* If the file is not
* existing, it is created.
*
* @param file The file.
* @param isDirectory flag indicating if the file should be a directory.
* @return The DocumentFile
*/
public static DocumentFile getDocumentFile(final File file, final boolean isDirectory,
Context context) {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
return DocumentFile.fromFile(file);
}
String baseFolder = getExtSdCardFolder(file, context);
boolean originalDirectory = false;
if (baseFolder == null) {
return null;
}
String relativePath = null;
try {
String fullPath = file.getCanonicalPath();
if (!baseFolder.equals(fullPath)) {
relativePath = fullPath.substring(baseFolder.length() + 1);
} else {
originalDirectory = true;
}
} catch (IOException e) {
return null;
} catch (Exception f) {
originalDirectory = true;
//continue
}
String as = PreferenceManager.getDefaultSharedPreferences(context).getString(baseFolder,
null);
Uri treeUri = null;
if (as != null) treeUri = Uri.parse(as);
if (treeUri == null) {
return null;
}
// start with root of SD card and then parse through document tree.
DocumentFile document = DocumentFile.fromTreeUri(context, treeUri);
if (originalDirectory) return document;
String[] parts = relativePath.split("/");
for (int i = 0; i < parts.length; i++) {
DocumentFile nextDocument = document.findFile(parts[i]);
if (nextDocument == null) {
if ((i < parts.length - 1) || isDirectory) {
nextDocument = document.createDirectory(parts[i]);
} else {
nextDocument = document.createFile("image", parts[i]);
}
}
document = nextDocument;
}
return document;
}
public static boolean mkdirs(Context context, File dir) {
boolean res = dir.mkdirs();
if (!res) {
if (isOnExtSdCard(dir, context)) {
DocumentFile documentFile = getDocumentFile(dir, true, context);
res = documentFile != null && documentFile.canWrite();
}
}
return res;
}
public static boolean delete(Context context, File file) {
boolean ret = file.delete();
if (!ret && isOnExtSdCard(file, context)) {
DocumentFile f = getDocumentFile(file, false, context);
if (f != null) {
ret = f.delete();
}
}
return ret;
}
public static boolean canWrite(File file) {
boolean res = file.exists() && file.canWrite();
if (!res && !file.exists()) {
try {
if (!file.isDirectory()) {
res = file.createNewFile() && file.delete();
} else {
res = file.mkdirs() && file.delete();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return res;
}
public static boolean canWrite(Context context, File file) {
boolean res = canWrite(file);
if (!res && isOnExtSdCard(file, context)) {
DocumentFile documentFile = getDocumentFile(file, true, context);
res = documentFile != null && documentFile.canWrite();
}
return res;
}
public static boolean renameTo(Context context, File src, File dest) {
boolean res = src.renameTo(dest);
if (!res && isOnExtSdCard(dest, context)) {
DocumentFile srcDoc;
if (isOnExtSdCard(src, context)) {
srcDoc = getDocumentFile(src, false, context);
} else {
srcDoc = DocumentFile.fromFile(src);
}
DocumentFile destDoc = getDocumentFile(dest.getParentFile(), true, context);
if (srcDoc != null && destDoc != null) {
try {
if (src.getParent().equals(dest.getParent())) {
res = srcDoc.renameTo(dest.getName());
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
res = DocumentsContract.moveDocument(context.getContentResolver(),
srcDoc.getUri(),
srcDoc.getParentFile().getUri(),
destDoc.getUri()) != null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
return res;
}
public static InputStream getInputStream(Context context, File destFile) {
InputStream in = null;
try {
if (!canWrite(destFile) && isOnExtSdCard(destFile, context)) {
DocumentFile file = getDocumentFile(destFile, false, context);
if (file != null && file.canWrite()) {
in = context.getContentResolver().openInputStream(file.getUri());
}
} else {
in = new FileInputStream(destFile);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return in;
}
public static OutputStream getOutputStream(Context context, File destFile) {
OutputStream out = null;
try {
if (!canWrite(destFile) && isOnExtSdCard(destFile, context)) {
DocumentFile file = getDocumentFile(destFile, false, context);
if (file != null && file.canWrite()) {
out = context.getContentResolver().openOutputStream(file.getUri());
}
} else {
out = new FileOutputStream(destFile);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return out;
}
public static boolean saveTreeUri(Context context, String rootPath, Uri uri) {
DocumentFile file = DocumentFile.fromTreeUri(context, uri);
if (file != null && file.canWrite()) {
SharedPreferences perf = PreferenceManager.getDefaultSharedPreferences(context);
perf.edit().putString(rootPath, uri.toString()).apply();
return true;
} else {
Log.e(TAG, "no write permission: " + rootPath);
}
return false;
}
public static boolean checkWritableRootPath(Context context, String rootPath) {
File root = new File(rootPath);
if (!root.canWrite()) {
if (isOnExtSdCard(root, context)) {
DocumentFile documentFile = getDocumentFile(root, true, context);
return documentFile == null || !documentFile.canWrite();
} else {
SharedPreferences perf = PreferenceManager.getDefaultSharedPreferences(context);
String documentUri = perf.getString(rootPath, "");
if (documentUri == null || documentUri.isEmpty()) {
return true;
} else {
DocumentFile file = DocumentFile.fromTreeUri(context, Uri.parse(documentUri));
return !(file != null && file.canWrite());
}
}
}
return false;
}
}