当前位置: 首页 > 工具软件 > wire-android > 使用案例 >

Android开发中集成protobuf协议

水渊
2023-12-01

protobuff是Google开源的一个二进制协议,被广泛应用与各大项目中。类似的还有腾讯MIG的JCE,原理上都是通过序号设置成员变量位置,然后实现序列化。但是在集成protobuff到Android中时,由于通过protobuf脚本生成的JAVA文件,含有大量的方法,稍微多生成几个类,就会造成方法方法数超64k。通过在gradle中设置:

android {
     .......
    defaultConfig {
       .......
        multiDexEnabled true 
    }
    .......

可以解决通过生成多个dex文件解决编译问题。但是会造成包变大 and 各种莫名其妙的低版本兼容问题,因此要求是严格控制方法数在64K以内。

所以,在Android集成protobuff时候,不能使用google官方的集成方法,改为使用“Square wire”项目。

项目主页:

https://github.com/square/wire

集成方法:

1、gradle中加入项目组件。

compile 'com.squareup.wire:wire-runtime:2.0.3'
2、加入混淆代码:
-keep class com.squareup.wire.** { *; }
-keep class com.yourcompany.yourgeneratedcode.** { *; }

3、下载 wire-compiler-VERSION-jar-with-dependencies.jar

wire-compiler-VERSION-jar-with-dependencies.jar是一个编译好的jar包,作用是根据proto语法,生成对应的java文件。

需要注意的是,原项目中并没有给出这个jar包的下载地址,想要下载它,需要去http://search.maven.org/中搜索“com.squareup.wire”。结果链接如下:

        http://search.maven.org/#search|ga|1|g%3A%22com.squareup.wire%22

注意下载的jar包版本哦。必须跟gradle中编译的版本保持一致,否则可能会出现编译错误or一些bug。


4、编写proto文件

syntax = "proto2";

package squareup.dinosaurs;

option java_package = "com.squareup.dinosaurs";

import "squareup/geology/period.proto";

message Dinosaur {
  // Common name of this dinosaur, like "Stegosaurus".
  optional string name = 1;

  // URLs with images of this dinosaur.
  repeated string picture_urls = 2;

  optional squareup.geology.Period period = 5;
}
具体proto语法,请自行搜索。


5、根据proto文件生成java文件。

使用cmd or shell 执行以下命令:
java -jar -Dfile.encoding=UTF-8 wire-compiler-2.0.1-jar-with-dependencies.jar --proto_path=. --java_out=. *.proto
需要注意的点:
-Dfile.encoding=UTF-8 : 指明生成的java文件编码是utf8,不指明的话,会使用系统编码。在win7系统默认gbk,会出现中文乱码。
--proto_path:proto文件路径,“.”是当前目录。
--java_out : java文件的生成目录。
*.proto:针对所有proto文件生成java文件。


6、使用
java文件已经生成,看代码可以发现,方法数相比protobuf确实减少了很多,同时每个类都会被拆分成单个文件。使用过程中会遇到一些类型转换,例如Message->bytestring or Message->byte 等。仔细看api基本都能满足需要,只有一个Message->bytestring 的转换需要自己实现,详情如下:
    public static ByteString pbToByteString(Message body) {
        try {
            Class<? extends Message> aClass = body.getClass();
            Field adapter = aClass.getField("ADAPTER");
            ProtoAdapter o = (ProtoAdapter) adapter.get(body);
            return ByteString.of(o.encode(body));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

        }
        return null;
    }



 类似资料: