외부에서_접근할_수_없는_앱_내부_공간에_사진_저장하기 - boostcampwm-2024/and04-Nature-Album GitHub Wiki

💡외부에서 접근할 수 없는 앱 내부 공간에 사진 저장하기

Intent Camera를 사용하여 진행

(카메라 권한 필요)

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

image

Intent에 EXTRA_OUTPUT 으로 uri를 제공하면 해당 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
        }
    }

image

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
        }
    }

추가 사항

  • 내부 파일의 메타데이터(위치 정보)를 얻기 위해서는 파일 권한 필요
⚠️ **GitHub.com Fallback** ⚠️