AndroidManifest.xml 파일에 아래 내용을 추가한다.
<uses-permission android:name="android.permission.CAMERA" />
MainActivity에서 Permission 에 대한 상수 추가, 권한을 설정하고 확인하는 메서드를 추가한다.
companion object{
const val PERMISSION = 1
}
private fun setPermissions() {
val permissions = ArrayList<String>()
permissions.add(android.Manifest.permission.CAMERA)
permissions.forEach {
if (ActivityCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,permissions.toTypedArray(), PERMISSION)
}
}
}
위 메서드는 각종 권한들을 ArrayList으로 할당 한 후, 이후 각 권한에 대해 허락되었는지 확인, 허락하지 않았다면 권한을 요청하는 코드이다.
권한이 하나인 경우 ArrayList가 아니여도 상관없지만, 추후에 추가할 수 있으니 동적으로 할당할 수 있게 List의 형태로 저장했다.
이후 onRequestPermissionsResult를 오버라이딩해서 권한거절에 대한 코드를 작성한다. Ctrl + o 로 오버라이딩 할 메서드를 바로 찾아올 수 있다.
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if (requestCode == PERMISSION) {
grantResults.forEach {
if (it != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "권한을 허용하지 않으면 사용할 수 없습니다", Toast.LENGTH_SHORT).show()
finish()
}
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
위의 메서드는 권한 요청한 코드에 대해 권한을 거절한 경우 앱을 종료하는 코드이다. 지금은 마찬가지로 요청한 권한이 하나이므로 grantResults도 하나이다. 따라서 grantResults.forEach 가 아닌 grantResults[0]으로 해도 무방하다.
이 글은 google에서 제공하는 cameraX 라이브러리를 이용해서 미리보기를 구현한다. 따라서 build.gradle에서 아래 라이브러리를 추가한다.
// CameraX core library using the camera2 implementation
def camerax_version = "1.3.0-alpha05"
// The following line is optional, as the core library is included indirectly by camera-camera2
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
// If you want to additionally use the CameraX Lifecycle library
implementation("androidx.camera:camera-lifecycle:${camerax_version}")
// If you want to additionally use the CameraX View class
implementation("androidx.camera:camera-view:${camerax_version}")
첫 두개는 하드웨어 카메라에 접근하기 위해 사용된다.
첫 번째는 카메라의 수명주기를 액티비티에 맞추기 위해서 사용된다.
두 번째는 카메라 뷰를 사용하기 위해서 사용된다.
메인액티비티에서 화면을 보여줄 예정인데, 초기에는 textview로 "Hello world!"가 쓰여져 있다. Res -> layout -> activity_main.xml 파일에서 확인 할 수 있다.
우측 상단에 Design -> Code 로 변경하여 textView를 제거하고, 화면에 보여줄 previewView를 추가한다.
위에 잠시 말했지만, preview로 카메라에서 받아온 후, previewView로 화면에 보여준다. 따라서 보여줄 previewView의 설정을 해준다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
최상단의 ConstraintLayout은 상관없다. Linearlayout이여도 상관없다.
간단히 설명하자면, 앱의 가로 세로를 부모의 크기로 (전체 크기로) 설정한다. 이후 previewView 객체를 메인 액티비티에 불러온다.
MainActivity에 아래 코드를 추가한다.
private lateinit var previewView: PreviewView
이후 onCreate 내부에서 previewView를 가져온다.
previewView = findViewById(R.id.previewView)
private fun setCamera() {
//카메라 제공 객체
val processCameraProvider = ProcessCameraProvider.getInstance(this).get()
//전체 화면
previewView.scaleType = PreviewView.ScaleType.FILL_CENTER
// 전면 카메라
val cameraSelector =
CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
// 16:9 화면으로 받아옴
val preview = Preview.Builder().setTargetAspectRatio(AspectRatio.RATIO_16_9).build()
// preview 에서 받아와서 previewView 에 보여준다.
preview.setSurfaceProvider(previewView.surfaceProvider)
// 카메라의 수명 주기를 메인 액티비티에 귀속
processCameraProvider.bindToLifecycle(this, cameraSelector, preview)
}
조금 더 부가설명을 하자면, 16:9 비율로 화면을 받아온다.
이후 해당 preview의 내용은 previewView에 보여준다.
카메라 객체와 그 외 관련된 객체의 수명주기를 메인 액티비티에 귀속시킨다. 따라서 앱이 종료되는 순간 카메라 객체도 자동으로 종료된다.
CameraSelector.LENS_FACING_BACK 는 핸드폰의 카메라 중 뒷 부분을 선택한다. 앞 부분을 원한다면 CameraSelector.LENS_FACING_FRONT 로 수정하면 된다.
전체 코드는 아래와 같다.
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.camera.core.AspectRatio
import androidx.camera.core.CameraSelector
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.app.ActivityCompat
class MainActivity : AppCompatActivity() {
private lateinit var previewView: PreviewView
companion object{
const val PERMISSION = 1
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
previewView = findViewById(R.id.previewView)
//권한 허용
setPermissions()
//카메라 켜기
setCamera()
}
private fun setCamera() {
//카메라 제공 객체
val processCameraProvider = ProcessCameraProvider.getInstance(this).get()
//전체 화면
previewView.scaleType = PreviewView.ScaleType.FILL_CENTER
// 전면 카메라
val cameraSelector =
CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
// 16:9 화면으로 받아옴
val preview = Preview.Builder().setTargetAspectRatio(AspectRatio.RATIO_16_9).build()
// preview 에서 받아와서 previewView 에 보여준다.
preview.setSurfaceProvider(previewView.surfaceProvider)
// 카메라의 수명 주기를 메인 액티비티에 귀속
processCameraProvider.bindToLifecycle(this, cameraSelector, preview)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if (requestCode == PERMISSION) {
grantResults.forEach {
if (it != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "권한을 허용하지 않으면 사용할 수 없습니다", Toast.LENGTH_SHORT).show()
finish()
}
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
private fun setPermissions() {
val permissions = ArrayList<String>()
permissions.add(android.Manifest.permission.CAMERA)
permissions.forEach {
if (ActivityCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, permissions.toTypedArray(), PERMISSION)
}
}
}
}