오늘은 안드로이드 Cache 디렉토리를 이용해,
xml로 구성된 화면을,
이미지 파일로 생성해 공유하는 방법을 보겠습니다.
구체적인 구현방법을 알아보기 전에,
이미지 공유를 위해서,
안드로이드 저장공간 중,
왜 Cache 디렉토리를 이용해야 하는지부터,
알아보겠습니다.
1. 안드로이드 Cache를 사용하는 이유
저장소에 대한 권한은 계속 바뀌어 왔습니다.
프라이버시를 강화한 것이라고 하지만,
안드로이드 버전별 코드 파편화가 심해지는 현상 때문에,
구현하는 개발자 입장에서 테스트해야할 기기도 많아졌고,
동적권한 관련해서 코드도 복잡해 졌습니다.
그래서 저는 항상 권한으로부터 자유로운 공간들을 사용할 수 없는지부터 판단합니다.
이러한 공간에서 해결할 수 없는 저장공간에 대해서만,
복잡하게 파편화된 코드를 사용하는 것 이지요.
이렇게 권한으로부터 자유로운 공간들로는,
Cache 디렉토리와 앱내에서 사용하는 Raw 그리고 Asset 디렉토리가 있는데요.
이 중 Cache디렉토리는 다음과 같은 장점이 있습니다.
- 권한 Free: 권한이 필요하지 않습니다.
- 시스템 관리: 시스템이 자동으로 관리하여 오래된 파일을 삭제합니다.
- 안드로이드 시스템이 오래된 파일 자동으로 삭제
- 용량 관리: 앱 자체 용량을 증가시키지 않습니다.
따라서, 앱에 영구히 유지할 필요가 없는 임시 파일을 생성할 경우 답은 정해져 있습니다.
권한 관련 코드가 필요없고,
앱의 용량도 걱정할 필요가 없는,
Cache 디렉토리를 사용하는 것 입니다.
2. implementation
Cache디렉토리를 사용할 때,
가장 먼저 할 것은 라이브러리를 implement하는 것 인데요.
이미지를 저장할 때 사용할 함수가 포함된,
AndroidKTX라이브러리를 미리 implement해 주어야 합니다.
이 라이브러리는 신규로 생성한 프로젝트에 대부분 포함되어 있을 것이므로,
존재하는지 확인만 해 주면 됩니다.
build.gradle에 implement 되어있는지 먼저 확인해 줍니다.
implementation 'androidx.core:core-ktx:1.13.1'
또한 이 글의 예제 코드에서,
FrameLayout에 접근하기 위해서,
ViewBinding을 사용하고 있는데요.
이에 대해서는 아래 글을 참조해 주세요.
3. xml을 이미지로 저장하기
이제 xml을 이미지로 저장해서 공유하는 코드를 보도록 하겠습니다.
구현할 때는 아래와 같은 과정을 거칩니다.
- xml을 Bitmap으로 변환
- xml을 Bitmap이미지로 변환하기 위해서, drawToBitmap() 함수 사용
- cache디렉토리에 images라는 디렉토리 생성
- Bitmap을 testScreenShot.png라는 파일에 FileOutputStream을 이용해 저장
- 저장한 파일의 uri는 FileProvider의 getUriForFile()함수를 사용
- Intent를 이용해서 외부에 공유하기
위에서 사용된, drawToBitmap()함수는,
View를 Bitmap으로 변환하게 해 줍니다.
Intent로 공유하기 위해서, 파일로 저장하는데요.
이 때, FileOutputStream()을 사용해 주었습니다.
참고로, 이 코드가 구현된 곳이 Fragment라서,
context가 필요한 곳에서, requireContext()함수를 사용하였습니다.
Activity라면 이 함수가 필요하지 않겠지요.
private fun shareScreenshot() {
lifecycleScope.launch {
try {
val bitmap = mBinding.frameWrapper.drawToBitmap()
// IO 스레드에서 파일저장 처리
val contentUri = withContext(Dispatchers.IO) {
val cachePath = File(requireContext().cacheDir, "images")
cachePath.mkdirs()
val file = File(cachePath, "testScreenShot.png")
FileOutputStream(file).use { fos ->
bitmap.compress(Bitmap.CompressFormat.PNG, 85, fos)
}
FileProvider.getUriForFile(
requireContext(),
"${requireContext().packageName}.fileprovider",
file
)
}
// 공유 인텐트 생성 및 실행
val sAux = "\n공유합니다.\n\n${ExtLinkConstants.LINK}\n\n"
val shareIntent = Intent().apply {
action = Intent.ACTION_SEND
type = "image/png"
putExtra(Intent.EXTRA_TEXT, sAux)
putExtra(Intent.EXTRA_STREAM, contentUri)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
Intent.createChooser(shareIntent, "공유합니다.").also { intent ->
startActivity(intent)
}
} catch (e: Exception) {
Toast.makeText(
requireContext(),
"공유 중 문제가 발생했습니다.",
Toast.LENGTH_SHORT
).show()
}
}
}
3. 파일경로에 대한 xml 정의
안드로이드에서 앱의 내부 파일을 다른 앱과 공유할 때는,
FileProvider를 제공해 주어야 하는데요.
이것이 있어야, 외부앱에서 접근이 가능해지기 때문입니다.
FileProvider 선언은 아래에서 할 텐데요.
선언하기 전에, 파일의 경로에 대해서 정의해주는 xml파일을 생성해야 합니다.
먼저 아래와 같은 이름의 file_paths파일을 xml폴더안에 생성합니다.
- res/xml/file_paths.xml
아래와 같이 xml을 작성할 수 있는데요.
xml은 아래와 같은 요소들로 구성되어 있습니다.
- <cache-path>: 앱의 내부 캐시 디렉토리(context.getCacheDir())를 가리킵니다
- name="shared_images": 이 경로에 대한 식별자를 정의
- 이 이름은 FileProvider가 생성하는 콘텐츠 URI의 일부로 사용됨
- path="images/": 캐시 디렉토리 내의 "images" 하위 폴더를 공유 대상으로 지정합니다
<?xml version="1.0" encoding="utf-8"?>
<paths>
<cache-path
name="shared_images"
path="images/"/>
</paths>
4. Manifest
이제 AndroidManifest.xml에서 FileProvider를 정의할 차례입니다.
아래와 같이 <provider>태그 안에 정의를 해 주는데요.
resource에 위에서 작성한 xml의 파일명을 정확히 적어줍니다.
<application
...
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
이렇게 구현하면,
Cache디렉토리에 파일을 생성해,
외부에 공유할 수 있게 됩니다.
'Android 개발 > File IO, FilesDir, Storage,' 카테고리의 다른 글
안드로이드 앱 내부 파일 확장자 체크 후 삭제하기 # delete filesDir (0) | 2023.04.14 |
---|---|
Uri 에서 Bitmap 파일 생성하는 방법 # getBitmap ImageDecoder (0) | 2022.11.17 |
Mp3파일 외부 저장소에서 가져와 재생하기 #안드로이드 (0) | 2019.09.07 |
Android 에서 File 저장하기 Part1. Internal Storage 편 (0) | 2017.01.08 |
댓글