Protobuf C++ 与 Android Java

Posted

技术标签:

【中文标题】Protobuf C++ 与 Android Java【英文标题】:Protobuf C++ vs Android Java 【发布时间】:2018-12-04 05:25:15 【问题描述】:

我正在开发一个 android 项目,在该项目中我们使用 Google 的 Protobuf 库进行序列化/反序列化。过去,我曾使用 C++ 开发 Protobuf。假设我有一个带有一个 protobuf 对象的 .proto 文件:

message LoginAck 
  enum LoginResult 
    OK = 1;
    NO_AUTH = 2;
    ERROR = 3;
  
  optional LoginResult result = 1;

在 C++ 中生成代码时,为此对象生成的类派生自 google::protobuf::Message,如下所示: 类登录:公共 ::google::protobuf::Message ...

而如果我尝试使用 Android 生成相同的代码,则这些类是派生自/扩展自 公共静态最终类登录扩展 com.google.protobuf.GeneratedMessageLite

com.google.protobuf.GeneratedMessageLite<
          Login, Login.Builder> implements
      // @@protoc_insertion_point(message_implements:Login)
      LoginOrBuilder 
...

问题在于,对于 MessageLite 类型,我无法使用只能通过 Message 类访问的描述符。我的 Gradle 构建文件如下所示:

dependencies 
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation 'com.google.protobuf:protobuf-java:3.4.0'
    implementation 'com.koushikdutta.async:androidasync:2.1.6'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'


protobuf 
    generatedFilesBaseDir = "$projectDir/src/generated"
    protoc 
        // You still need protoc like in the non-Android case
        artifact = 'com.google.protobuf:protoc:3.4.0'
    
    plugins 
        javalite 
            // The codegen for lite comes as a separate artifact
            artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'
        
    
    generateProtoTasks 
        all().each  task ->
            task.builtins 
                // In most cases, you don't need the full Java output
                // if you use the lite output.
                remove java
            
            task.plugins 
                javalite 
            
            task.generateDescriptorSet = true
            task.descriptorSetOptions.includeSourceInfo = true
            task.descriptorSetOptions.includeImports = true
        
    

我想生成带有从 Message 而不是 MessageLite 扩展的类的 java 文件。如何做到这一点?

【问题讨论】:

【参考方案1】:

在做了更多的研究和大量的尝试后,我终于找到了解决方案。我必须进行的更改位于 Protobuf 块中的 build.gradle 文件中,如下所示:

protobuf 
    generatedFilesBaseDir = "$projectDir/src/generated"
    protoc 
        // You still need protoc like in the non-Android case
        artifact = 'com.google.protobuf:protoc:3.4.0'
    
    generateProtoTasks 
        all().each  task ->
            task.builtins 
                // In most cases you don't need the full Java output
                // if you use the lite output.
                java 
            
            task.generateDescriptorSet = true
            task.descriptorSetOptions.includeSourceInfo = true
            task.descriptorSetOptions.includeImports = true
        
    

这里的区别是我必须从块中删除 javalite 插件并保留 java 生成的代码。但是,为了使新脚本正常工作,我必须删除项目中现有的“生成”文件夹。现在,我得到了 Messages.java 文件,其中包含扩展 Message 类的对象,而不是 MessageLite 类,后者具有许多功能,例如可供使用的描述符。 遗憾的是,这一事实在网上的任何地方都没有记录。因此,如果将来有人遇到这种情况,请对您的 build.gradle 文件进行上述更改。 谢谢

【讨论】:

以上是关于Protobuf C++ 与 Android Java的主要内容,如果未能解决你的问题,请参考以下文章

google protobuf可以用于android中C和Java服务之间的通信吗?

问题解决:C++与Python之间使用protobuf无法解析

无法使用 Google 的 protobuf 构建测试 C++ 应用程序

ProtoBuf系列protobuf的介绍与安装

未检查/强制执行 Protobuf C++ 必填字段

为啥 protobuf 不适合大型数据结构?