package com.sw.dualscreen.utils import android.content.ContentUris import android.content.Context import android.net.Uri import android.os.Build import android.provider.MediaStore import androidx.annotation.RequiresApi import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MultipartBody import okhttp3.RequestBody.Companion.asRequestBody import timber.log.Timber import java.io.File object FileUtils { /** * 从Uri获取File * example: file:///data/user/0/com.sw.inbound/cache/IMG_17515262353556856678814444882273.jpg */ private fun getFileFromUri(context: Context, uri: Uri): File? { Timber.d("getFileFromUri uri = ${uri.scheme}") return when (uri.scheme) { "file" -> File(uri.path ?: return null) "content" -> { try { val inputStream = context.contentResolver.openInputStream(uri) ?: return null val cacheDir = context.cacheDir val file = File.createTempFile( "upload_${System.currentTimeMillis()}", ".jpg", cacheDir ) file.outputStream().use { output -> inputStream.copyTo(output) } file } catch (e: Exception) { Timber.e(e) null } } else -> null } } /** * 通过uri生成http请求体 */ fun genRequestPart(context: Context, imageUri: Uri): MultipartBody.Part? { Timber.d("genRequestPart imageUri = $imageUri") // 1. 从Uri获取文件 val file = getFileFromUri(context, imageUri) if (file == null) { Timber.e("getFileFromUri file is null") return null } // 2. 创建请求体 val requestFile = file .asRequestBody("application/octet-stream".toMediaTypeOrNull()) val imagePart = MultipartBody.Part.createFormData( "file", file.name, requestFile ) return imagePart } /** * 通过Uri删除文件 * @param context 上下文 * @param uri 文件Uri * @return Boolean 是否删除成功 */ fun deleteFileWithUri(context: Context, uri: Uri): Boolean { Timber.d("deleteFileWithUri uri = ${uri.scheme}") return when { // 1. 处理 content:// 类型的Uri (MediaStore) uri.scheme.equals("content", ignoreCase = true) -> { deleteContentUriFile(context, uri) } // 2. 处理 file:// 类型的Uri uri.scheme.equals("file", ignoreCase = true) -> { deleteFileUriFile(uri) } // 3. 其他情况尝试直接解析路径 else -> { deleteFileFromPath(uri.path ?: return false) } } } // 删除Content Uri文件 private fun deleteContentUriFile(context: Context, uri: Uri): Boolean { Timber.d("deleteContentUriFile uri = ${uri.scheme}") return try { context.contentResolver.delete(uri, null, null) > 0 } catch (e: SecurityException) { // Android 10+需要特殊处理 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { deleteMediaStoreFile(context, uri) } else { false } } catch (e: Exception) { Timber.e(e) false } } // Android 10+删除MediaStore文件 @RequiresApi(Build.VERSION_CODES.Q) private fun deleteMediaStoreFile(context: Context, uri: Uri): Boolean { Timber.d("deleteMediaStoreFile uri = ${uri.scheme}") val contentResolver = context.contentResolver val projection = arrayOf(MediaStore.MediaColumns._ID) return try { contentResolver.query(uri, projection, null, null, null)?.use { cursor -> if (cursor.moveToFirst()) { val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID)) val contentUri = ContentUris.withAppendedId(uri, id) contentResolver.delete(contentUri, null, null) > 0 } else { false } } ?: false } catch (e: Exception) { Timber.e(e) false } } // 删除File Uri文件 private fun deleteFileUriFile(uri: Uri): Boolean { Timber.d("deleteFileUriFile uri = $uri") return try { File(uri.path ?: return false).delete() } catch (e: Exception) { Timber.e(e) false } } // 直接通过路径删除文件 private fun deleteFileFromPath(path: String): Boolean { Timber.d("deleteFileFromPath path = $path") return try { File(path).delete() } catch (e: Exception) { Timber.e(e) false } } }