如何使用 Retrofit2 上传应用程序不拥有且只有 Uri 具有读取权限的文件

问题描述 投票:0回答:1

现在,当我从我的应用程序中选择要上传的文件时,例如照片

private val imageFileFromGalleryPickResult =
    registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { imageUri ->
        imageUri?.let { }
    }

然后我将它保存到应用程序个人存储(缓存目录),如果您需要修改它(更改分辨率或在发送到服务器之前修复方向),这很有用

suspend fun savePublicFileToAppCacheDir(context: Context, fileUri: Uri): File {
    val appCacheDir = ContextCompat.getExternalCacheDirs(context)
        .filterNotNull()
        .first()
        .also { it.mkdirs() }
    val file = File(appCacheDir, "temp_file.jpg")
    context.contentResolver.openInputStream(uri)!!.use { input ->
        FileOutputStream(file).use { output ->
            output.write(input.readBytes())
        }
    }
    return file
}

在那之后我可以很容易地用

Retrofit2
发送这个文件因为应用程序拥有它:

fun buildMultipartBodyPart(file: File, paramName: String): MultipartBody.Part {
    val requestFile = file.asRequestBody("image/jpeg".toMediaTypeOrNull())
    return MultipartBody.Part.createFormData(paramName, file.name, requestFile)
}

@Multipart
@POST("user/profile/photo")
suspend fun sendProfilePhoto(
    @Part photoFile: MultipartBody.Part,
)

但是我没有先复制到应用程序目录的文件呢,尤其是大文件(50mb+)?

所以我只有

Uri
。那么我怎样才能用 Retrofit 发送文件呢?以某种方式发送
InputStream

更新

我想我只能用

fun ByteArray.toRequestBody()
input.readBytes()

但是,大文件呢? :)

android retrofit2 android-file android-contentresolver
1个回答
0
投票

现在我是这样实现的:

fun Uri.getFileName(
    context: Context,
    contentResolver: ContentResolver = context.contentResolver
): String? {
    val projection = arrayOf(MediaStore.MediaColumns.DISPLAY_NAME)
    contentResolver.query(this, projection, null, null, null)?.use {
        if (it.moveToFirst()) {
            return it.getString(0)
        }
    }
    return null
}

fun Uri.toMultipartBodyPart(
    context: Context,
    paramName: String
): MultipartBody.Part {
    val uri = this
    val contentResolver = context.contentResolver
    val fileName = uri.getFileName(context, contentResolver)
    val mimeType = contentResolver.getType(uri)
    val bytes = contentResolver.openInputStream(uri)!!.use { input ->
        input.readBytes() // not good for RAM
    }
    val requestedBody = bytes.toRequestBody(mimeType?.toMediaTypeOrNull())
    return MultipartBody.Part.createFormData(paramName, fileName, requestedBody)
}

如果有更好的方法,很高兴在这里看到其他带有示例的答案

© www.soinside.com 2019 - 2024. All rights reserved.