您的位置:首页 > 移动开发 > Android开发

Android开发中集成protobuf协议

2016-01-18 12:29 731 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: