我无法在物理SD卡上写文件。我想问用户是否允许 写入整个SD卡。用户授予权限。现在我想在SD卡上的特定目录中创建文件(目录已经存在)。当我尝试打开输出流时,我得到异常:
Java.Lang.SecurityException:Permission Denial:编写com.android.externalstorage.ExternalStorageProvider uri content://com.android.externalstorage.documents/tree/0FFF170E%3AMyDir/MyFile.MyExt from pid = 3563,uid = 10082需要android.permission.MANAGE_DOCUMENTS或grantUriPermission()
以下是活动的代码:
using System.Linq;
using System.Threading.Tasks;
using Android.App;
using Android.Content;
using Android.Net;
using Android.OS;
using Android.OS.Storage;
namespace MyApp
{
[Activity(Label = "MyApp", MainLauncher = true)]
public class MainActivity : Activity
{
private const int AccessRequest = 101;
private TaskCompletionSource<string> AccessIntentTaskCompletionSource { get; set; }
protected override async void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
string uriWithPermission = await AccessIntentAsync();
if (!string.IsNullOrEmpty(uriWithPermission))
{
string targetUri = uriWithPermission + "MyDir/MyFile.MyExt"; // MyDir exists on SD card
// Example of targetUri:
// content://com.android.externalstorage.documents/tree/0FFF-170E%3AMyDir/MyFile.MyExt
WriteFileToUri(targetUri);
}
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == AccessRequest)
{
string path = null;
if (resultCode == Result.Ok)
{
path = data.DataString;
Android.Net.Uri uriPath = data.Data;
ContentResolver.TakePersistableUriPermission(uriPath, ActivityFlags.GrantReadUriPermission | ActivityFlags.GrantWriteUriPermission);
}
this.AccessIntentTaskCompletionSource?.SetResult(path);
}
}
private async Task<string> AccessIntentAsync()
{
this.AccessIntentTaskCompletionSource = new TaskCompletionSource<string>();
StorageManager sm = GetSystemService(StorageService) as StorageManager;
if (sm != null)
{
StorageVolume volume = sm.StorageVolumes.FirstOrDefault(sv => !sv.IsPrimary); // Assume only one non-primary storage volume.
if (volume != null)
{
Intent intent = volume.CreateAccessIntent(null); // request access to the entire volume
StartActivityForResult(intent, AccessRequest);
return await this.AccessIntentTaskCompletionSource.Task;
}
}
return null;
}
private void WriteFileToUri(string targetUri)
{
Android.Net.Uri outputUri = Uri.Parse(targetUri);
byte[] source = System.Text.Encoding.UTF8.GetBytes("MyFileContent");
using (System.IO.Stream outputStream = this.ContentResolver.OpenOutputStream(outputUri)) // throws Exception
{
outputStream.Write(source, 0, source.Length);
outputStream.Close();
}
}
}
}
这是清单:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="MyApp.MyApp" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="25" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:allowBackup="true" android:label="@string/app_name"></application>
</manifest>
我在模拟器和真实设备上测试过它。两者均采用Android 7.1。
SD卡安装在&#34;用于传输照片和媒体&#34;模式。
修改 请求权限android.permission.WRITE_EXTERNAL_STORAGE在运行时不起作用。仅当我想写入 PRIMARY 外部存储时才有效。
答案 0 :(得分:0)
您必须提供运行时权限
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
Log.v(TAG,"Permission is granted");
//File write logic here
return true;
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE)
}
答案 1 :(得分:0)
string targetUri = uriWithPermission + "MyDir/MyFile.MyExt"; // MyDir exists
即使存在MyDir
,您的代码也无法正常工作,因为它不是正确的uri文件。
此外,如果用户选择了MyDir目录并且您的coude看起来像
string targetUri = uriWithPermission + "/MyFile.MyExt";
使用输出流创建文件的代码仍无效。
相反,您应该使用DocumentFile
来获取所选目录的实例。之后,您可以使用DocumentFile.createFile()
创建子目录或文件。
您不需要清单和运行时的常用权限。
答案 2 :(得分:0)
检查以下代码,它将帮助您理解文件保存在内存中。
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_CAPTURE_IMAGE_REQUEST_CODE && resultCode == RESULT_OK) {
// Show the thumbnail on ImageView
previewMedia();
} else if (requestCode == REQUEST_GALLERY_PHOTO && resultCode == RESULT_OK) {
// Show the thumbnail on ImageView
try {
imageUri = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getActivity().getContentResolver().query(imageUri,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
mCurrentPhotoPath = cursor.getString(columnIndex);
cursor.close();
bitmap = BitmapFactory.decodeFile(compressImage(mCurrentPhotoPath));
preview_imageview.setImageBitmap(bitmap);
} catch (Exception e) {
e.getMessage();
}
// ScanFile so it will be appeared on Gallery
MediaScannerConnection.scanFile(getActivity(),
new String[]{imageUri.getPath()}, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
}
});
}
}