2020-12-27T17:27:57.000+09:00

Androidにおけるprotobufのjavaliteについてメモ

直接仕事に関係はないけど、急に情報を集める必要が出てきた為 雑なメモとして。実際に手元で動かしているわけではないので、少なからず誤った記述をしていそう。

AndroidでのProtocol Buffers利用

Androidでは標準ビルドツールとしてGradleを使うので、protobuf-gradle-plugin を導入する。
これはローカルにあるprotocバイナリとのブリッジが主な仕事で、有効にするとGradleプロジェクト内のsourceSetに配置した .proto をJavaクラスとしてコンパイル可能になる。
protocのバイナリをローカルに入れてない場合も考慮して、protobuf.protoc.artifact = 'com.google.protobuf:protoc:3.0.0' などとしてMaven上のprotocを指定すると良い。

Java Lite Runtime

Androidはご存知のとおり一般的なJVMとは異なるRuntimeになっており、これをGoogleのProtobufチームは「制約のある実行環境」と呼んでいるらしい。このような環境を考慮して設計された "Lite" と呼ばれるモードがある。

Liteではprotocによる単なるコンパイルでのJavaクラス吐き出しではなく、

  • Android Runtime等の制約ある環境でも使用可能なJava APIのみの使用
  • 共通ロジックを外部ライブラリへ切り出すことによる省サイズ化

などが行われたものになる。現在この機能は protoc 自体に搭載されているため、Gradleプロジェクトの設定レベルでフラグを立てることで有効化できる。ただし上記のとおり外部のライブラリへ共通ロジックが切り出されている為、その記述は別途必要になる。

// https://github.com/google/protobuf-gradle-plugin#default-outputs

def protobufVersion = '3.8.0'

dependencies {
  implementation "com.google.protobuf:protobuf-javalite:${protobufVersion}"
}

protobuf {
  protoc {
    artifact = "com.google.protobuf:protoc:${protobufVersion}"
  }
  generateProtoTasks {
    all().each { task ->
      task.builtins {
        java {
          option "lite"
        }
      }
    }
  }
}

ポイントは「現在この機能は protoc 自体に搭載されている」「外部のライブラリへ共通ロジックが切り出されている」の2点。protobuf-javalite はあくまでも protoc のLite機能用の内部APIが切り出されたライブラリという位置付けである為、protocの機能アップデート等によって決められたバージョニング規則がそのまま protobuf-javalite にも設定される。両者は一体となって利用される前提である為、常に同じものが設定されなければいけない。
もしこれが異なるバージョンになった場合、protocのLiteモードで出力されたJavaクラスと、それが参照する protobuf-javalite のAPIに齟齬が起きClassNotFound等の例外が発生する可能性がある。


なお、この protobuf-javalite というライブラリは以前 protobuf-lite というartifactだった。

<artifactId>protobuf-lite</artifactId>

https://github.com/protocolbuffers/protobuf/blob/ca21b28287871660057a2b8bada2c044b6b3075d/java/lite/pom.xml#L12

これが2016年頃のリリース以来長いことアップデートされていなかったのだが、2019年6月頃にリリースされた 3.8.x の時に protobuf-javalite へと変更されている。

<artifactId>protobuf-javalite</artifactId>

https://github.com/protocolbuffers/protobuf/blob/815ff7e1fb2d417d5aebcbf5fc46e626b18dc834/java/lite/pom.xml#L12

即ち両者は単なるアップグレードであり、protobuf-lite -> protobuf-javalite という流れで移行されることが理想である。

またこの旧バージョンではprotoc内にliteのモードが同梱されていなかったため、codegenとして com.google.protobuf:protoc-gen-javalite:xxx を指定していた。