LoginSignup
10
8

More than 5 years have passed since last update.

Android用カメラライブラリのCameraKitを使ってみた

Last updated at Posted at 2018-12-18

はじめに

AndroidのcameraApiって分かりづらい、とっつきにくいと思う方は多いのではないでしょうか?
CameraとCamera2があったり、SurfaceViewが必要だったり・・・
普通に実装しようとしても僕のようなへっぽこエンジニアには正直つらいです
ある日見つけたCameraKitというライブラリが良い感じだったので紹介します

いいところ

  • viewに配置したCameraKitView中心に実装できる

実装サンプル

  • 撮影して、保存するところまでやってみます

注:beta3.9の情報のため、仕様は変更になっている可能性があります

gradle

implementation 'com.camerakit:camerakit:1.0.0-beta3.9'
implementation 'com.camerakit:jpegkit:0.1.0'

権限取得


@RuntimePermissions
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        if (savedInstanceState == null) {
            saveWithPermissionCheck()
        }
    }

    @NeedsPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA)
    fun save() {
        supportFragmentManager.beginTransaction().add(R.id.container, CameraFragment()).commit()
    }

    @OnPermissionDenied(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA)
    fun showDeniedForWriteExternalStorage() {
        // 権限を許可されなかったとき
        when {
            PermissionUtils.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) -> {
                Toast.makeText(this, "カメラを使用する権限を取得できませんでした", Toast.LENGTH_SHORT).show()
            }
            PermissionUtils.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) -> {
                Toast.makeText(this, "撮影データを保存する権限を取得できませんでした", Toast.LENGTH_SHORT).show()
            }
        }
    }

    @OnShowRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA)
    fun showRationaleForWriteExternalStorage(request: PermissionRequest) {
        // 再度権限を要求した
        MaterialDialog(this)
            .message(text = "このアプリのご利用には、カメラの使用とデータ保存のための権限を取得する必要があります")
            .show {
                positiveButton(text = "許可") { dialog ->
                    request.proceed()
                }
                negativeButton(text = "今はしない")
            }
    }

    @OnNeverAskAgain(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA)
    fun showNeverAskForWriteExternalStorage() {
        // 今後表示しないを選択した
        MaterialDialog(this)
            .title(text = "カメラを利用できません")
            .message(text = "カメラを使用するためには、設定画面 > 許可からご自身で権限を許可して頂く必要があります。")
            .show {
                positiveButton(text = "設定画面へ") {
                    val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                    intent.data = Uri.fromParts("package", packageName, null)
                    startActivity(intent)
                }
                negativeButton(text = "今はしない")
            }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        onRequestPermissionsResult(requestCode, grantResults)
    }
}
  • activity_main
<RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

    <FrameLayout
            android:id="@+id/container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
    />

</RelativeLayout>

CameraViewの設定

  • 権限を取得できたら、CameraViewを保持するFragmentを生成します

class CameraFragment : Fragment() {
    private val df = SimpleDateFormat("yyyyMMdd-HHmmss", Locale.getDefault())
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_camera, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        captureButton.setOnClickListener {
            cameraView.captureImage { _, bytes ->
                val currentTimeMillis = System.currentTimeMillis()
                val datetime = df.format(Date(currentTimeMillis))
                val savedPhoto = File(Environment.getExternalStorageDirectory(), "$datetime-$currentTimeMillis.jpg")
                try {
                    val outputStream = FileOutputStream(savedPhoto.path)
                    outputStream.write(bytes)
                    outputStream.close()
                } catch (e: java.io.IOException) {
                    e.printStackTrace()
                }
            }
        }
    }

    override fun onStart() {
        super.onStart()
        cameraView.onStart()
    }

    override fun onResume() {
        super.onResume()
        cameraView.onResume()
    }

    override fun onPause() {
        cameraView.onPause()
        super.onPause()
    }

    override fun onStop() {
        cameraView.onStop()
        super.onStop()
    }
}
  • fragment_camera.xml
<RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
>

    <com.camerakit.CameraKitView
            android:id="@+id/cameraView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:keepScreenOn="true"
            app:camera_flash="off"
            app:camera_focus="auto"
            app:camera_imageJpegQuality="100"
    />

    <Button
            android:text="撮影ボタン"
            android:id="@+id/captureButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
    />
</RelativeLayout>

簡単に解説

  • CameraKitViewを配置しておけばカメラの準備ができていて、プレビューはそこに表示され、任意のタイミングでそのイメージを取得できる
    • 直感的!!!
  • カメラの権限のみであればpermissionDispacherを使わずに実装できるのですが、storageに関してうまくできなかったのでActivity側で事前に取得してしまう設計にしています
  • 他にもいろいろプロパティがあり、ぱっと見で理解できそうなドキュメントになっているので困ったらこちらにどうぞ
  • 知見ある方の情報お待ちしています m_ _m

関連リンク

10
8
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
8