하고 싶은 것 : 사진을 편집한 후 편집한 사진을 디바이스에 저장하지 않고 편집된 사진을 서버에만 저장 하고 싶음.
방법 : 이미지 파일을 내부 캐시 저장소에 임시 저장한다.
private const val tempFileName = "myTempFile.jpeg"
//비트맵을 임시 파일로 저장하는 함수
suspend fun Bitmap.createTempFile(context: Context, index: Int) {
//파일 IO는 메모리가 많이 필요한 작업 이기 때문에 메인쓰레드에서 작업하면 안된다.
//코루틴의 dispatcher을 이용해 IO 코루틴에서 작업하도록 하자
withContext(Dispatchers.IO) {
//파일이 존재하는지 체크하고, 파일이 존재하면 삭제한다.
val imagePath = File(context.cacheDir.absolutePath)
val file = File(imagePath, $tempFileName")
if (file.exists()) {
file.delete()
}
try {
val storage: File = context.cacheDir //내부 저장소 내 캐시디렉토리
val tempFile = File(storage, $tempFileName") //파일 만들기
try {
//////////////////////////////////////////////////////
//찾아보니 임시 파일은 createTempFile을 이용해서 만드는 것이 더 좋은 것 같다.
//prefix - 파일명. 그 뒤에 임의의 숫자가 더 붙는다. ex) prerix : test -> test1234578
//suffix - 확장자. ".jpg" , ".txt" 등을 넣어주면 된다 null을 넣을시 디폴트로 ".tmp"가 된다.
//directory - 경로. 파일이 생성될 위치이다.
// val tempImage = java.io.File.createTempFile("tempFile",".jpg",context.cacheDir)
// tempImage.deleteOnExit() // jvm이 종료될 때 자동 삭제된다.
// deleteOnExit()을 사용하면 위의 파일이 존재하는지 체크하고 삭제하는 부분을 안해도 될 듯 하다.
// val stream = FileOutputStream(tempImage)
// this@createTempFile.compress(Bitmap.CompressFormat.JPEG, 100, stream)
/////////////////////////////////////////////////////////
tempFile.createNewFile()
val stream = FileOutputStream(tempFile)
this@createTempFile.compress(Bitmap.CompressFormat.JPEG, 100, stream)
//file -> bitmap
//중간 숫자가 퀄리티 인데, 높은 수록 화질은 좋아지지만 그만큼 용량도 커진다.
stream.close()
} catch (e: IOException) {
e.printStackTrace()
}
} catch (e: IOException) {
e.printStackTrace()
}
}
}
//임시저장된 파일의 uri 를 알아내는 함수
fun getTempFileUri(context: Context, index: Int): Uri? {
val imagePath = File(context.cacheDir.absolutePath)
val tempFile = try {
File(imagePath, $tempFileName") //임시저장된 파일 가져오기
} catch (e: IOException) {
return null
}
//파일에서 uri 가져오기
return FileProvider.getUriForFile(context, "com.gosoo.example.fileprovider", tempFile)
}
FileProvider는 file:///Uri 대신 파일에 대해 content://Uri를 만들어 앱과 연결된 파일의 보안 공유를 용이하게 하는 ContentProvider의 특수 하위 클래스입니다.
ㅤ
콘텐츠 URI를 사용하면 임시 액세스 권한을 사용하여 읽기 및 쓰기 액세스 권한을 부여할 수 있습니다. 콘텐츠 URI를 포함하는 인텐트를 생성할 때 콘텐츠 URI를 클라이언트 앱에 보내기 위해 Intent.setFlags()를 호출하여 권한을 추가할 수도 있습니다. 이러한 권한은 수신 활동에 대한 스택이 활성 상태인 동안 클라이언트 앱에서 사용할 수 있습니다. 서비스로 가는 인텐트의 경우 서비스가 실행되는 동안 권한을 사용할 수 있습니다.
ㅤ
이에 비해 file:///Uri에 대한 액세스를 제어하려면 기본 파일의 파일 시스템 권한을 수정해야 합니다. 제공한 권한은 모든 앱에서 사용할 수 있으며 변경할 때까지 유효합니다. 이 수준의 액세스는 근본적으로 안전하지 않습니다.
ㅤ
콘텐츠 URI가 제공하는 향상된 수준의 파일 액세스 보안은 FileProvider를 Android 보안 인프라의 핵심 부분으로 만듭니다.
ㅤ
이 FileProvider 개요에는 다음 항목이 포함됩니다.
ㅤ
파일 제공자 정의
사용 가능한 파일 지정
파일에 대한 콘텐츠 URI 생성
URI에 임시 권한 부여
다른 앱에 콘텐츠 URI 제공
//res > xml > file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="cache" path="./" /> //내부 캐시 저장소의 주소를 등록
</paths>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.gosoo.example.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
FileProvider.getUriForFile(context, "com.gosoo.example.fileprovider", tempFile)