외부에서_접근할_수_없는_앱_내부_공간에_사진_저장하기 - boostcampwm-2024/and04-Nature-Album GitHub Wiki
(카메라 권한 필요)
val REQUEST_IMAGE_CAPTURE = 1
private fun dispatchTakePictureIntent() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
try {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
} catch (e: ActivityNotFoundException) {
// display error state to the user
}
}
// onActivityResult를 override해 bundle받기
startActivityForResult
이 deprecated되어 ActivityResultLauncher
사용 필요
class MainActivity : AppCompatActivity() {
private lateinit var takePictureLauncher: ActivityResultLauncher<Intent>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
takePictureLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val imageBitmap = result.data?.extras?.get("data") as Bitmap
// 비트맵으로 작업
}
}
}
private fun dispatchTakePictureIntent() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
try {
takePictureLauncher.launch(takePictureIntent)
} catch (e: ActivityNotFoundException) {
// display error state to the user
}
}
}
위 코드의 get("data")
또한 deprecated, 카메라가 인텐트로 전달하는 data는 크기가 작은(해상도가 낮은)이미지의 비트맵
카메라에서 찍은 사진을 미리보기 할 수 있는 썸네일 이미지 용도로 추측한다.
https://developer.android.com/reference/android/provider/MediaStore#ACTION_IMAGE_CAPTURE
Intent에 EXTRA_OUTPUT
으로 uri를 제공하면 해당 uri에 이미지를 저장
private fun dispatchTakePictureIntent() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
val imageFile = File(filesDir, "${System.currentTimeMillis()}.jpg")
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageFile.toUri())
try {
takePictureLauncher.launch(takePictureIntent)
} catch (e: ActivityNotFoundException) {
// display error state to the user
}
}
https://developer.android.com/reference/android/os/FileUriExposedException
앱 내부 저장소를 외부에 공개해서 발생하는 문제
내부 파일을 외부에서 접근할 수 있도록 FileProvider
사용
https://developer.android.com/reference/androidx/core/content/FileProvider.html
<!-- AndroidManifest.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>
외부 앱에서 접근 가능한 파일 목록 추가 (files 하위의 모든 경로 지정)
<!-- res/xml/file_paths.xml -->
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path
name="internal_files"
path="." />
</paths>
private fun dispatchTakePictureIntent() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
val imageFile = File(filesDir, "${System.currentTimeMillis()}.jpg")
val imageUri = FileProvider.getUriForFile(this, "${packageName}.fileprovider", imageFile)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri)
try {
takePictureLauncher.launch(takePictureIntent)
} catch (e: ActivityNotFoundException) {
// display error state to the user
}
}
- 내부 파일의 메타데이터(위치 정보)를 얻기 위해서는 파일 권한 필요