Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/230.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 在安卓10上从URI获取真实文件路径,在安卓10中内容URI的后缀为msf:documentid_Android_Xamarin - Fatal编程技术网

Android 在安卓10上从URI获取真实文件路径,在安卓10中内容URI的后缀为msf:documentid

Android 在安卓10上从URI获取真实文件路径,在安卓10中内容URI的后缀为msf:documentid,android,xamarin,Android,Xamarin,我试图从Xamarin Android中的intent chooser获得真正的路径,它在除Android 10之外的所有Android版本中都能正常工作。在安卓10中,内容uri类似于 content://com.android.providers.downloads.documents/document/msf%3A180Android 10默认启用了作用域存储。这意味着您无法直接访问外部存储路径-请看一看 您可以通过在应用程序的AndroidManifest.xml中将设置为true来执行

我试图从Xamarin Android中的intent chooser获得真正的路径,它在除Android 10之外的所有Android版本中都能正常工作。在安卓10中,内容uri类似于


content://com.android.providers.downloads.documents/document/msf%3A180

Android 10默认启用了作用域存储。这意味着您无法直接访问外部存储路径-请看一看

您可以通过在应用程序的AndroidManifest.xml中将设置为
true
来执行建议的操作,但请记住,这只适用于targetSdk 29,不适用于30+

如果您试图访问媒体,则应通过。
否则,请查看。

在获取图像文件的URI之后,当然我们需要通过压缩来编辑此文件,在获得真实的文件路径之后。如果您以SDK 30为目标,这是我使用作用域存储的实现;) 别忘了给我的答案投票

import android.content.ContentValues
import android.content.Context
import android.content.res.AssetFileDescriptor
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ImageDecoder
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import androidx.annotation.RequiresApi
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.FileOutputStream


/**
* Created by Mostafa Anter on 11/5/20.
*/

object PhotoHelper{

@RequiresApi(Build.VERSION_CODES.Q)
        /**
         * mContext: context from activity or fragment,
         * imageSelectedUri: uri that return from any pick picture library it usually return inside on activity response method
         * appFolderName: name of folder that will generate to save compressing images ;)
         * createdImageCompressedName : random name of new compressed image 
         */
fun compressGetImageFilePath(
        mContext: Context,
        imageSelectedUri: Uri,
        appFolderName: String,
        createdImageCompressedName: String = System.currentTimeMillis().toString()
): String {
    //region Getting the photo to process it
    val bitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        ImageDecoder.decodeBitmap(ImageDecoder.createSource(mContext.contentResolver, imageSelectedUri))
    } else {
        mContext.contentResolver.openInputStream(imageSelectedUri)?.use { inputStream ->
            BitmapFactory.decodeStream(inputStream)
        }
    }
    // endregion

    //region save photo to gallery using Scoped storage
    val values = ContentValues().apply {
        put(MediaStore.Images.Media.DISPLAY_NAME, createdImageCompressedName)
        put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
        put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/$appFolderName/")
        put(MediaStore.Images.Media.IS_PENDING, 1)
    }

    val collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
    val imageUri = mContext.contentResolver.insert(collection, values)
    //endregion


    //region save image
    mContext.contentResolver.openOutputStream(imageUri!!).use { out ->
        bitmap!!.compress(Bitmap.CompressFormat.PNG, 100, out)
    }

    values.clear()
    values.put(MediaStore.Images.Media.IS_PENDING, 0)
    mContext.contentResolver.update(imageUri, values, null, null)
    //endregion


    //region get file path of content uri
    val file = File(mContext.cacheDir, "$createdImageCompressedName.png")
    try {
        val assetFileDescriptor: AssetFileDescriptor = mContext.contentResolver.openAssetFileDescriptor(imageUri, "r")!!

        val inputStream = FileInputStream(assetFileDescriptor.fileDescriptor)
        val outputStream = FileOutputStream(file)
        inputStream.copyTo(outputStream)

        inputStream.close()
        outputStream.close()


    } catch (e: FileNotFoundException) {
        e.printStackTrace()
    }
    //endregion



    return file.path

    }
}

如果你想针对新旧设备,只需做if语句检查android版本,如果android Q更大或相等,请使用我的方法,否则请使用你的旧方法。

你可以查询文件名,然后构建路径

  • 查询文件名:

      public static string getFileName(Context context, Android.Net.Uri uri)
      {
          ICursor cursor = null;
          string[] projection = {
              MediaStore.MediaColumns.DisplayName
          };
    
          try
          {
              cursor = context.ContentResolver.Query(uri, projection, null, null,
              null);
              if (cursor != null && cursor.MoveToFirst())
              {
                  int index = cursor.GetColumnIndexOrThrow(MediaStore.MediaColumns.DisplayName);
                  return cursor.GetString(index);
              }
          }
          finally
          {
              if (cursor != null)
                  if (cursor != null)
                  {
                      cursor.Close();
                  }
          }
          return null;
      }
    
构建路径:

string fileName = getFileName(context, uri);
string filePath = Android.OS.Environment.ExternalStorageDirectory + "/Download/" + fileName;

如果您有任何问题,请随时提问。@Nou如果尝试此库,我想知道这一切与发布的问题有什么关系。@blackapps,因为内容uri中的文档id为msf:89,因此我无法获取文件的真实路径。一旦我得到了真正的路径,我必须发送到第三方聊天云,这样他们将获得文件并将其存储在他们的云中。对不起,我在这里的评论当然不是为你。但是在别的地方有一个是给你的。请通过编辑您的帖子作出反应。@blackapps正如我在第一段中解释的,自Android 10以来,您无法访问外部存储路径。我还提供了一个临时解决方案(manifest标志),以及通过MediaStore和相关文档链接实现访问媒体的正确方法。我不明白你发现什么不清楚或不相关。如何访问外部存储不是原始海报的问题。OP只想获取uri的路径。请重读。