Kotlin でも MediaPipe の MultiHandTracking を動かしたい


Kotlin で MediaPipe の MultiHandTracking を利用しているサンプルが無さそうだったので作ってみました。
プログラムは GitHub に上げてあるので、よかったら参考にしてください。

こんな感じで動きます。

作ったと言いながら

元々はこちらの Java のコードを Kotlin に移植したものになります。Kotlin をある程度知っている人なら特に苦労することなく移植できると思います。(自分は素人に毛が生えたようなものなので小一時間ほどは浪費しました・・・)

移植する上での注意

Java のバージョン指定の追加

そのまま移植すると、こんな感じのエラー(java.lang.NoSuchMethodError: No static method)が出ます。

    java.lang.NoSuchMethodError: No static method metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; in class Ljava/lang/invoke/LambdaMetafactory; or its super classes (declaration of 'java.lang.invoke.LambdaMetafactory' appears in /apex/com.android.runtime/javalib/core-oj.jar)
        at com.google.mediapipe.components.CameraXPreviewHelper.startCamera(CameraXPreviewHelper.java:52)
        at com.example.mediapipehandtracking.MainActivity.startCamera(MainActivity.kt:165)
        at com.example.mediapipehandtracking.MainActivity.onResume(MainActivity.kt:102)
        at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1465)
        at android.app.Activity.performResume(Activity.java:8203)
        at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4757)
        at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4810)
        at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:190)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:105)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2373)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:213)
        at android.app.ActivityThread.main(ActivityThread.java:8147)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1101)

aar を取り込んで入れてるのでそのせいだと思われますが、Java のバージョンを指定することでエラーを回避できます。

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = "1.8"
    }

gradle.build, AndroidManifest.xml

この辺はしっかり必要なものを設定していないと、ビルドは通るものの、実行時にエラーになったりします。
自分は protobuf のモジュールを違うものを使っていて、ログに問題が出ていると出力されていたものの、
Error ではなく Infoだったので、気付くのに時間掛かりました。

gradle.build の修正

implementation 'com.google.protobuf:protobuf-java:3.11.4'

implementation 'com.google.protobuf:protobuf-lite:3.0.1'

にする必要があります。

コードはこちら

参考