이미지 파일 내부 캐시저장소에 임시저장

나고수·2022년 8월 28일
0

1일1공부

목록 보기
61/68
post-custom-banner

하고 싶은 것 : 사진을 편집한 후 편집한 사진을 디바이스에 저장하지 않고 편집된 사진을 서버에만 저장 하고 싶음.
방법 : 이미지 파일을 내부 캐시 저장소에 임시 저장한다.

 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 이란?

FileProvider는 file:///Uri 대신 파일에 대해 content://Uri를 만들어 앱과 연결된 파일의 보안 공유를 용이하게 하는 ContentProvider의 특수 하위 클래스입니다.

콘텐츠 URI를 사용하면 임시 액세스 권한을 사용하여 읽기 및 쓰기 액세스 권한을 부여할 수 있습니다. 콘텐츠 URI를 포함하는 인텐트를 생성할 때 콘텐츠 URI를 클라이언트 앱에 보내기 위해 Intent.setFlags()를 호출하여 권한을 추가할 수도 있습니다. 이러한 권한은 수신 활동에 대한 스택이 활성 상태인 동안 클라이언트 앱에서 사용할 수 있습니다. 서비스로 가는 인텐트의 경우 서비스가 실행되는 동안 권한을 사용할 수 있습니다.

이에 비해 file:///Uri에 대한 액세스를 제어하려면 기본 파일의 파일 시스템 권한을 수정해야 합니다. 제공한 권한은 모든 앱에서 사용할 수 있으며 변경할 때까지 유효합니다. 이 수준의 액세스는 근본적으로 안전하지 않습니다.

콘텐츠 URI가 제공하는 향상된 수준의 파일 액세스 보안은 FileProvider를 Android 보안 인프라의 핵심 부분으로 만듭니다.

이 FileProvider 개요에는 다음 항목이 포함됩니다.

파일 제공자 정의
사용 가능한 파일 지정
파일에 대한 콘텐츠 URI 생성
URI에 임시 권한 부여
다른 앱에 콘텐츠 URI 제공

  • manifest에서 내부/외부저장소 권한을 얻었어야했던 과거와 달리 fileProvider을 활용하면 이런 권한을 얻을 필요가 없습니다.
  • content://uri 로 시작하는 uri가 생기는데, 이 uri를 통해 외부 앱에 파일 접근에 관한 임시 권한을 줄 수도 있습니다.
  • 지금은 '파일에 대한 콘텐츠 URI 생성'을 활용해 파일에서 uri를 얻어왔습니다.
  • FileProvider.getUriForFile 파라미터
  • 사용방법
  1. file providier path - directory 매칭
//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>
  1. manifest에 지정
 <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>
  1. 파일에서 uri 얻기
 FileProvider.getUriForFile(context, "com.gosoo.example.fileprovider", tempFile)
profile
되고싶다
post-custom-banner

0개의 댓글