ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 안드로이드 기본 앱 연동하기 - 카메라 앱
    Android 2024. 9. 19. 15:53

     

    카메라 앱을 연동하여 사진을 촬영하고 그 결과를 돌려받는 방법은 2가지가 있다.

    1. 사진 데이터 가져오기

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

     

    암시적 인텐트로 카메라 앱의 사진 촬영 액티비티를 실행한다.

    val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    requestCameraThumbnailLauncher.launch(intent)

     

    액션 문자열을 MediaStore.ACTION_IMAGE_CAPTURE 로 지정하여 인텐트를 시스템에 전달하면 카메라 앱이 실행된다. 카메라 앱에서 넘어온 사진 데이터는 ActivityResultCallback 으로 가져오면 된다.

    val requestCameraThumbnailLauncher = registerForActivityResult(
    	ActivityResultContracts.StartActivityForResult())
    {
    	val bitmap = it.data.extras.get("data") as Bitmap
    }

     

    bitmap 변수에는 넘어온 카메라 데이터가 담겨져있다.


    2. 사진 파일 공유하기

     

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

     

    ① 앱에서 사진을 저장할 파일을 만든다. 

    ② 사진 파일 정보를 포함한 인텐트를 시스템에 전달해 카메라 앱을 실행한다.

    ③ 카메라 앱으로 사진을 촬영하여 사진을 공유된 파일에 저장한다.

    ④ 카메라 앱을 종료하면서 성공 또는 실패를 반환한다.

    ⑤ 카메라 앱이 저장한 사진 파일을 앱에서 이용한다.

     

    먼저 내 앱(카메라앱X)에서 외장 메모리에 파일을 만들어야 한다. 두가지 방법이 있다.

    getExternalStoragePublicDirectory() 

    모든 앱에서 이용할 수 있는 파일을 만든다. 해당 함수를 이용해 외장 메모리에 파일을 만들려면 퍼미션을 설정해야 한다.

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

    getExternalFilesDir()

    이 앱에서만 이용할 수 있는 파일을 만든다. getExternalStoragePublicDirectory() 와 마찬가지로 퍼미션을 설정해야했지만 API 레벨 19 이후부터 해당 작업을 하지 않아도 된다. (단, API 19 하위에서 동작할려면 퍼미션을 설정해줘야 한다.)

     

    API 24 부터는 "file://" 프로토콜로 구성된 URI 를 외부에 노출하지 못하도록 하는 엄격 모드가 적용됐다.

    따라서 앱끼리 파일을 공유하려면 "content://" 프로토콜을 이용하고 이 URI 에 임시로 접근할 수 있는 권한을 부여해야 한다. 이때는 FileProvider 클래스를 이용한다. FileProvider 클래스는 content:// 프로토콜로 구성된 URI 를 생성해준다.

     

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

     

    // 파일 프로바이더용 XML 파일
    <paths>
    	<external-path name="myfiles" path="Android/data/com.example.패키지명/files/Pictures"/>
    </paths>

     

    이곳에 지정한 경로는 getExternalFilesDir() 함수로 파일을 만들었을 때 파일이 저장되는 위치이다.

    해당 파일 프로바이더용 XML 파일을 메니페스트에 등록해야한다.

    // manifest 에 file provider xml 등록
    <provider
    	android:name="androidx.core.content.FileProvider"
        android:authorities="com.example.패키지명.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
    	<meta-data
        	android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths"/>
    </provider>

     

    resource 속성에 아까 만든 XML 파일을 지정한다.

     

    이제 코드에서 파일을 만들어야 한다.

    val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
    val storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
    val file = File.createTempFile(
    	"JPEG_${timeStamp}_",
        ".jpg",
        storageDir
    )
    filePath = file.absolutePath

     

    Environment.DIRECTORY_PICTURES 로 지정하여 아까 파일 프로바이더용 XML 파일을 만들때 path로 지정한 Android/data/com.example.패키지명/files/Pictures 에 저장된다.  

    createTempFile 에 해당 매개변수를 지정한 이유는 파일명이 중복되지 않게 하여 날짜와 시각을 이용했다.

    filePath 는 나중에 파일 내용을 읽을 때 사용하려고 파일 경로를 저장했다.

     

    인텐트를 만들어 카메라 앱을 실행해보자.

    val requestCameraFileLauncher = registerForActivityResult(
    	ActivityResultContracts.StartActivityForResult())
    {
    	val option = BitmapFactory.Options()
        option.inSampleSize = 4 // OOM Error 방지
        val bitmap = BitmapFactory.decodeFile(filePath, option)
        bitmap.let {
        	// View 에 출력
            binding.cameraImage.setImageBitmap(it)
        }
    }
    
    val photoUri = FileProvider.getUriForFile(
    	this,
        "com.example.패키지명.fileprovider", file
    )
    val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) // 암시적 인텐트
    intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri)
    requestCameraFileLauncher.launch(intent)

     

    이렇게 하면 카메라 앱을 내 앱에 연동하여 카메라 정보를 가져올 수 있다.

Designed by Tistory.