Jetpack Composeでカメラアプリを作ろう！

## 今回のアプリ
アプリにカメラの許可を与える
![スクリーンショット 2023-12-16 20.39.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953312/ca883391-5f50-df8d-f0da-fca8320e9b8f.png)
カメラ機能
![スクリーンショット 2023-12-16 20.38.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953312/1c9ac09c-6b53-db83-6c56-faf52a7ee58c.png)

# はじめに
今、開発中のアプリでカメラ機能を実装した！！！！！
でも、JetpackComposeでカメラ機能を使う情報が少ないい！！！
そこで、あらゆるサイトを調べてまくって実装までこぎつけました。
今回は、その内容をまとめてみました。

＃ 開発環境
Android Studio Flamingo | 2022.2.1 Patch 2
MacBook Air M2

## 1 プロジェクトを作成する
![スクリーンショット 2023-12-16 20.49.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953312/e31673b9-1871-843e-9436-6960d412bd2f.png)
EmptyActivityを選びます
![スクリーンショット 2023-12-16 20.49.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953312/bfd73b41-573b-d8ff-a542-c499aa9b7565.png)
プロジェクト名を「myCamera」
MinimumSDK「API29:Android 10.0(Q)」

## 2 必要な権限をリクエストします
![スクリーンショット 2023-12-16 20.57.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953312/ee09e80a-127a-b1b0-4ce1-ace2a9bf9458.png)
AndroidManifest.xml を開き、application タグの前に次の行を追加します。
コード
```
<uses-feature android:name="android.hardware.camera.any" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"android:maxSdkVersion="28" />
```
## 3 CameraX の依存関係を追加する
```
def camerax_version = "1.2.1"
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
implementation "androidx.camera:camera-video:${camerax_version}"
implementation "androidx.camera:camera-view:${camerax_version}"
implementation "androidx.camera:camera-extensions:${camerax_version}"
```
このコードをbuild.gradle(Module:app)に追加します。


## 4 AccompanistのPermissionsライブラリを追加する
JetpackComposeでパーミッションを取得するために、必要なライブラリを追加します。
```
implementation "com.google.accompanist:accompanist-permissions:0.28.0"
```
このコードをbuild.gradle(Module:app)に追加します。
ここまでで、下準備は終わりです。

## 5　アプリ作成開始
### MainActivity
```
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyCameraTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    MainCamera()
                }
            }
        }
    }
}

```
ここは、アプリの中心で一番最初に実行されます。後述するMainCameraを実行させます。

## MainCamera
```
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun MainCamera() {
    val permissionState: PermissionState = rememberPermissionState(permission = Manifest.permission.CAMERA)

    if(permissionState.status.isGranted){
        CametaStert()
    }else{
        NoPermission(onRequestPermission = permissionState::launchPermissionRequest)
    }
}
```
この関数では、アプリにカメラの使用許可が降りているのかを判断して、
許可があればCametaStert（カメラを起動させる関数）、許可がなければNoPermission(許可をリクエストする関数)を実行する。
重要なポイントは、
```
val permissionState: PermissionState = rememberPermissionState(permission = Manifest.permission.CAMERA)
```
ここで、カメラのパーミッションの状況を取得しています。

## NoPermission
```
@Composable
fun NoPermission(onRequestPermission:() -> Unit){
    Column(modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center)
    {
        Button(onClick =  onRequestPermission ) {
            Text(text = "カメラの許可を与えてください")
        }
    }
}
```
ここでは、ユーザーに確認を取り、カメラ許可のリクエストを送ります。

## CametaStert
```
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CametaStert(){
    val context = LocalContext.current
    val lifecycleOwner = LocalLifecycleOwner.current
    val imageCapture =  remember {
        ImageCapture.Builder()
            .setFlashMode(ImageCapture.FLASH_MODE_AUTO) // フラッシュモードを設定
            .setTargetAspectRatio(AspectRatio.RATIO_4_3) // ターゲットのアスペクト比を設定
            .build()
    }
    val previewView = PreviewView(context).apply {
        layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
        scaleType = PreviewView.ScaleType.FILL_CENTER
    }
    val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
    DisposableEffect(Unit) {
        val cameraProvider = cameraProviderFuture.get()
        Log.d("cameraProvider",cameraProvider.toString())
        val preview = androidx.camera.core.Preview.Builder().build()

        val cameraSelector = CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build()

        preview.setSurfaceProvider(previewView.surfaceProvider)
        cameraProvider.bindToLifecycle(
            lifecycleOwner,
            cameraSelector,
            preview,
            imageCapture
        )
        onDispose {
            cameraProvider.unbindAll()
        }
    }
    Scaffold(floatingActionButton = {
        FloatingActionButton(onClick = { }) {
            Icon(imageVector = Icons.Default.Add, contentDescription = "Clothesadd")
        }
    }) {paddingValues: PaddingValues ->
     AndroidView(factory = {previewView},
         modifier = Modifier.padding(paddingValues))
    }
}
```
この関数では、カメラのプレビューを実装しています。

## 終わり
今回は、単純にプレビューを表示させるアプリを作りました。
次は、このアプリに写真を取って保存する機能を追加します。