AndroidのカメラをUIに表示する【Androidアプリ開発】

AndroidのカメラをUIに表示するソースコードを解説します。UIは、 Composable を使って構成します。

AndroidのカメラをUIに表示する【Androidアプリ開発】
AndroidのカメラをUIに表示する【Androidアプリ開発】

ソースコード

AndroidManifest.xml

AndroidManifest.xml に以下を追加します。
xml
<uses-feature
    android:name="android.hardware.camera"
    android:required="false" />
<uses-permission android:name="android.permission.CAMERA" />

build.gradle.kts (Module :app)

モジュールレベルの build.gradle.ktsdependencies に以下を追加して、依存ライブラリをインストールします。

kts
implementation("androidx.camera:camera-camera2:1.3.1")
implementation("androidx.camera:camera-lifecycle:1.3.1")
implementation("androidx.camera:camera-view:1.3.1")

MainActivity

kotlin
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            RtmpTestTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    // CameraPreview() に hasCameraPermission を渡します
                    CameraPreviewWithPermissionRequest()
                }
            }
        }
    }
}

@Composable
fun CameraPreviewWithPermissionRequest() {
    var hasCameraPermission by remember { mutableStateOf(false) }
    val context = LocalContext.current

    // パーミッションのリクエストの結果を受け取る Launcher
    val permissionLauncher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.RequestPermission(),
        onResult = { isGranted: Boolean ->
            hasCameraPermission = isGranted
        }
    )

    // アプリがフォアグラウンドに来たときにパーミッションの状態をチェック
    LaunchedEffect(key1 = true) {
        if (context.checkSelfPermission(android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            permissionLauncher.launch(android.Manifest.permission.CAMERA)
        } else {
            hasCameraPermission = true
        }
    }

    if (hasCameraPermission) {
        CameraPreview()
    } else {
        Text("カメラのアクセス許可が必要です。")
    }
}

CameraPreview.kt

kotlin
@Composable
fun CameraPreview() {
    val context = LocalContext.current
    val lifecycleOwner = LocalLifecycleOwner.current
    val cameraProviderFuture = remember { ProcessCameraProvider.getInstance(context) }
    val previewView = remember { PreviewView(context) } // CameraXライブラリの一部で、カメラのプレビューを表示するためのビュー
    val modifier = Modifier.fillMaxSize()

    AndroidView(
        modifier = modifier,
        factory = { previewView },
        update = { view ->
            val cameraProvider = cameraProviderFuture.get()
            val preview = Preview.Builder().build().also {
                it.setSurfaceProvider(view.surfaceProvider)
            }

            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
            try {
                cameraProvider.unbindAll()
                cameraProvider.bindToLifecycle(
                    lifecycleOwner, cameraSelector, preview
                )
            } catch(exc: Exception) {
                Log.e("CameraPreview", "Use case binding failed", exc)
            }
        }
    )
}

解説

このコードは、AndroidのJetpack Composeを使用して、カメラのプレビューを表示するためのComposable関数(CameraPreview)を定義しています。Composable関数は、UIを宣言的に記述するためのもので、Jetpack Composeで使用されます。この特定の例では、カメラのプレビューを画面に表示するために、CameraXライブラリと一緒に使用されています。

ここで重要なクラスと関数について解説します:

PreviewView

PreviewViewは、CameraXライブラリの一部で、カメラのプレビューを表示するためのビューです。Androidの従来のビューシステムに属しており、Compose内で使用するためには、AndroidViewというComposable関数を介して統合する必要があります。

AndroidView

AndroidViewは、既存のAndroidビュー(この場合はPreviewView)をComposeに統合するために使用されるComposable関数です。これにより、Composeが中心のアプリケーションでも、まだComposeに移行されていない旧式のビューコンポーネントを使用できるようになります。

コード解説

ローカルコンテキストとライフサイクルオーナーの取得

kotlin
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current

Compose内で、現在のコンテキストとライフサイクルオーナーを取得しています。これらはカメラのセットアップとバインディングに必要です。

CameraProviderの取得とPreviewViewのインスタンス化

kotlin
val cameraProviderFuture = remember { ProcessCameraProvider.getInstance(context) }
val previewView = remember { PreviewView(context) }
rememberを使用して、ProcessCameraProviderのインスタンス(将来的な結果を含む)とPreviewViewのインスタンスを保持します。これにより、これらのオブジェクトは、Composableが再構築されるたびに再インスタンス化されることはありません。

AndroidViewを使ってPreviewViewをComposeに統合

kotlin
AndroidView(
    modifier = modifier,
    factory = { previewView },
    update = { view ->
        // ...
    }
)
AndroidView Composableは、PreviewViewをComposeのUIツリーに統合します。factoryパラメータにはPreviewViewのインスタンスを渡し、updateブロックでは、カメラのセットアップとバインディングのロジックを記述します。

カメラのプレビューをセットアップ

kotlin
val cameraProvider = cameraProviderFuture.get()
val preview = Preview.Builder().build().also {
    it.setSurfaceProvider(view.surfaceProvider)
}
cameraProviderFuture.get()でCameraProviderを取得し、Previewのインスタンスを作成して、surfaceProviderを設定します。

カメラセレクターを設定し、ライフサイクルにバインド

kotlin
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
try {
    cameraProvider.unbindAll()
    cameraProvider.bindToLifecycle(
        lifecycleOwner, cameraSelector, preview
    )
} catch(exc: Exception) {
    Log.e("CameraPreview", "Use case binding failed", exc)
}

デフォルトのバックカメラを使用するようにカメラセレクターを設定し、cameraProviderを使って、カメラのプレビューをライフサイクルオーナーにバインドします。これにより、アプリのライフサイクルと同期してカメラのリソースが管理されます。例外が発生した場合は、エラーログを出力します。

全体として、このコードはComposeを使用してカメラのプレビューを表示する一例ですが、実際のアプリではパーミッションの確認など、さらに多くの処理を行う必要があります。また、rememberが使用されているので、これらのインスタンスはComposableが再構築されても保持されます。

関連記事

最後までご覧いただきありがとうございます!

▼ 記事に関するご質問やお仕事のご相談は以下よりお願いいたします。
お問い合わせフォーム