Android 카메라 앱 연동하기

timothy jeong·2021년 11월 17일
0

Android with Kotlin

목록 보기
48/69

카메라 앱을 실행해 사진을 촬영하고 사진 데이터를 가져오는 방법을 알아보자. 카메라 앱을 연동하여 사진을 촬영하고 그 결과를 돌려받는 방법은 2가지가 있다.

  • 사진 데이터를 가져오는 방법
  • 사진 파일을 공유하는 방법

사진 데이터를 가져오는 방법은 카메라 앱으로 사진을 촬영한 후 파일로 저장하지 않고 데이터만 넘겨주는 방식이다. 이 방식은 사진을 파일로 저장하지 않으므로 쉽게 구현할 수 있지만 넘어오는 사진 데이터의 크기가 작다는 단점이 있다.

사진 파일을 공유하는 방법은 카메라 앱에서 촬영한 사진을 파일에 저장한 후 성공인지 실패인지 넘겨주는 방식이다. 이 방식을 이용하면 휴대폰의 카메라 성능만큼 큰 크기의 사진을 촬영하고 앱에서 이용할 수 있지만, 카메라 앱이 파일 정보를 공유하는 것이므로 몇가지 준비작업이 필요하다.

사진 데이터를 가져오는 방법

인텐트로 카메라 앱의 사진 촬영 액티비티를 실행한다. 그리고 사진을 촬영하고 확인 버튼을 누르면 카메라 앱을 실행한 액티비티로 넘어온다.

private lateinit var resultLauncher : ActivityResultLauncher<Intent>

...
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        resultLauncher = registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()) {
            if (it.resultCode == RESULT_OK) {
                Log.d("INFO", "RESULT_OK")
                val bitmap = it.data?.extras?.get("data") as Bitmap
                binding.galleryResult.setImageBitmap(bitmap)
            }
        }
        
resultLauncher.launch(intent)

사진 파일을 공유하는 방법

다음의 절차를 따른다

  • 앱에서 사진을 저장할 파일을 만든다.
  • 사진 파일 정보를 포함한 인텐트를 전달해 카메라 앱을 실행한다.
  • 카메라 앱으로 사진을 촬영하여 공유된 파일에 저장한다.
  • 카메라 앱을 종료하면서 성공 또는 실패를 반환한다.
  • 카메라 앱이 저장한 사진 파일을 앱에서 이용한다.

먼저 앱에서 외장 메모리에 파일을 만들어 줘야 한다. 파일을 만들 때 getExternalStoreagePublicDirectory() 또는 getExternalFileDir() 함수를 이용할 수도 있다. 전자는 모든 앱에서 이용할 수 있는 파일을 만들고, 후자는 이 앱에서만 이용할 수 있는 파일을 만든다.

getExternalStoreagePublicDirectory() 는 퍼미션을 설정해야하고, getExternalFileDir() 는 API 19 이하까지 고려한다면 퍼미션을 설정해야한다.

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

그리고 API 24 부터는 file:// 프로토콜로 구성된 URI 를 외부에 노출하지 못하도록 하는 엄격 모드가 적용되었다. 따라서 앱끼리 파일을 공유하려면 content:// 프로토콜을 이용하고 이 URI에 임시로 접근할 수 있는 권한을 부여해야 한다. 이때 FileProvider 클래스를 이용한다. FileProvider 클래스는 androidx 라이브러리에서 제공하며 XML 설정을 기반으로 해서 content:// 프로토콜로 구성된 URI 를 생성해 준다.

결국 FileProvider 를 이용하려면 공유할 파일의 URI값을 만들어야 한다. 그러려면 프로젝트의 res/xml 디렉터리에 파일 프로바이더용 XML 파일을 만들어줘야 한다.

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="myfile"
    path="Android/data/{앱 패키지명}/files/Pictures"/>
</paths>

파일 프로바이더용 XML 파일은 path 속성에 지정한 경로의 파일 권한을 설정한다. 이곳에 지정한 경로는 getExternalFilesDir() 함수로 파일을 만들 때 저장되는 위치이다. 이렇게 작성한 파일 프로바이더용 XML 파일을 메니페스트에 등록해야한다.

        <provider
            android:authorities="com.example.providerusingapp"
            android:name="androidx.core.content.FileProvider"
            android:exported="true"
            android:grantUriPermissions="true"/>
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_path"/>

이제 카메라 앱과 연동을 해보자.

class MainActivity : AppCompatActivity() {
    private lateinit var binding : ActivityMainBinding
    lateinit var filePath: String
    private lateinit var resultLauncher : ActivityResultLauncher<Intent>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        resultLauncher = registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()) {
            if (it.resultCode == RESULT_OK) {
                Log.d("INFO", "RESULT_OK")
                val option = BitmapFactory.Options()
                option.inSampleSize = 10
                val bitmap = BitmapFactory.decodeFile(filePath, option)
                bitmap.let{
                    binding.galleryResult.setImageBitmap(bitmap)
                }
            }
        }

        val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
        val storageDir: File? = getExternalFilesDir(Environment.DIRECTORY_PICTURES)

        val file = File.createTempFile(
            "JPEG_${timeStamp}_",
            ".jpg",
            storageDir
        )

        filePath = file.absolutePath

        val photoURI: Uri = FileProvider.getUriForFile(
            this,
            "com.example.providerusingapp",
            file)

        val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
        resultLauncher.launch(intent)

    }
profile
개발자

0개의 댓글