protobuf 怎么在iOS中实用
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了protobuf 怎么在iOS中实用相关的知识,希望对你有一定的参考价值。
有两种方式,一是直接使用C++版, 引用.h和dylib就可以了, 用在64位的5s上很容易,但是在5以下的32位上编译环不容易弄对。二是用objc版的。可以参考如下操作:
1,下载ProtocolBuffer包,并按照包中根目录下README.txt安装。
make install后,会生成编译器protoc,并拷贝到/usr/local/bin目录下。
2,下载Objective-C compiler for ProtocolBuffer。
目前有两种类型的实现。
一个针对ProtocolBuffer2.2做修改,使最后生成的.proto文件编译器(protoc)支持Objective-C类型的文件输出。
它在这里:http://code.google.com/p/metasyntactic/wiki/ProtocolBuffers
另一个针对ProtocolBuffer2.3推出的plugin模式编写插件,以插件方式支持Objective-C类型的文件输出。
它在这里:https://github.com/booyah/protobuf-objc
我选用第二种方式,这也是Google推荐的方式。
git clone https://github.com/booyah/protobuf-objc.git
默认会在当前运行目录下创建protobuf-objc目录。进入该目录,并执行:
./autogen.sh
./configure
make
make install
最终生成的插件名字为protoc-gen-objc,会被安装到/usr/local/bin/目录下。
3,测试.proto文件编译。
随便写一个test.proto文件,并编译该文件。命令是:
protoc –objc_out=/Output/Directory/ test.proto
protoc会自动在/usr/local/bin/目录下寻找名为”protoc-gen-objc”的插件,并使用该插件编译.proto文件,最终生成两个文件:
test.pb.h
test.pb.m
这个步骤通过后,说明ProtocoBuffer Compiler for Objective-C可以正常工作了。
4,在Xcode4.3.1中使用ProtocolBuffer
将步骤2中protobuf-obj/src/runtime/Classes目录导入到Xcode项目中,导入时,选中”Copy items into destination group‘s folder(if needed)“。
导入位置选择项目根目录。导入完毕后,项目根目录下将会出现Classes目录。将该目录改名为ProtocolBuffers(注意最后的s):
mv Classes ProtocolBuffers
修改项目属性中”Build Setting——>Header Search Pathes”,将项目根目录“.”添加到头文件搜索路径中去。
这样ProtocolBuffer for Objective-C的工作环境就配置好了。
5,使用
将步骤3中编译输出的test.pb.h和test.pb.m添加到项目中,就可以直接使用了。 参考技术A 一、Protobuf的使用
首先来简单介绍一下Protobuf的使用,这里以windows下java开发为例,几个步骤:编写*.proto ->使用google提供的protoc.exe生成*.java->项目中导入protobuf的.jar包进行开发即可。先看这里的*.proto文件:
[plain] view plain copy
package com;
message CMsg
required string msghead = 1;
required string msgbody = 2;
message CMsgHead
required int32 msglen = 1;
required int32 msgtype = 2;
required int32 msgseq = 3;
required int32 termversion = 4;
required int32 msgres = 5;
required string termid = 6;
message CMsgReg
optional int32 area = 1;
optional int32 region = 2;
optional int32 shop = 3;
optional int32 ret = 4;
optional string termid = 5;
使用protoc.exe生成java文件,命令如下:
将生成的Msg.java及protobuf-java-2.3.0.jar导入项目中进行开发,这里写一个服务器端ProtobufServer及客户端ProtobufClient
[java] view plain copy
package com;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import com.Msg.CMsg;
import com.Msg.CMsgHead;
import com.Msg.CMsgReg;
public class ProtoServer implements Runnable
@Override
public void run()
try
System.out.println("beign:");
ServerSocket serverSocket = new ServerSocket(12345);
while (true)
System.out.println("等待接收用户连接:");
// 接受客户端请求
Socket client = serverSocket.accept();
DataOutputStream dataOutputStream;
DataInputStream dataInputStream;
try
InputStream inputstream = client.getInputStream();
dataOutputStream = new DataOutputStream(
client.getOutputStream());
byte len[] = new byte[1024];
int count = inputstream.read(len);
byte[] temp = new byte[count];
for (int i = 0; i < count; i++)
temp[i] = len[i];
CMsg msg = CMsg.parseFrom(temp);
CMsgHead head = CMsgHead.parseFrom(msg.getMsghead()
.getBytes());
System.out.println("==len===" + head.getMsglen());
System.out.println("==res===" + head.getMsgres());
System.out.println("==seq===" + head.getMsgseq());
System.out.println("==type===" + head.getMsgtype());
System.out.println("==Termid===" + head.getTermid());
System.out.println("==Termversion==="
+ head.getTermversion());
CMsgReg body = CMsgReg.parseFrom(msg.getMsgbody()
.getBytes());
System.out.println("==area==" + body.getArea());
System.out.println("==Region==" + body.getRegion());
System.out.println("==shop==" + body.getShop());
sendProtoBufBack(dataOutputStream);
inputstream.close();
catch (Exception ex)
System.out.println(ex.getMessage());
ex.printStackTrace();
finally
client.close();
System.out.println("close");
catch (IOException e)
System.out.println(e.getMessage());
private byte[] getProtoBufBack()
// head
CMsgHead head = CMsgHead.newBuilder().setMsglen(10).setMsgtype(21)
.setMsgseq(32).setTermversion(43).setMsgres(54)
.setTermid("Server:head").build();
// body
CMsgReg body = CMsgReg.newBuilder().setArea(11).setRegion(22)
.setShop(33).setRet(44).setTermid("Server:body").build();
// Msg
CMsg msg = CMsg.newBuilder()
.setMsghead(head.toByteString().toStringUtf8())
.setMsgbody(body.toByteString().toStringUtf8()).build();
return msg.toByteArray();
private void sendProtoBufBack(DataOutputStream dataOutputStream)
byte[] backBytes = getProtoBufBack();
// Integer len2 = backBytes.length;
// byte[] cmdHead2 = BytesUtil.IntToBytes4(len2);
try
// dataOutputStream.write(cmdHead2, 0, cmdHead2.length);
dataOutputStream.write(backBytes, 0, backBytes.length);
dataOutputStream.flush();
catch (IOException e)
e.printStackTrace();
public static void main(String[] args)
Thread desktopServerThread = new Thread(new ProtoServer());
desktopServerThread.start();
[java] view plain copy
package com;
import java.io.InputStream;
import java.net.Socket;
import com.Msg.CMsg;
import com.Msg.CMsgHead;
import com.Msg.CMsgReg;
public class ProtoClient
public static void main(String[] args)
ProtoClient pc=new ProtoClient();
System.out.println("beign:");
pc.runget();
public void runget()
Socket socket = null;
try
//socket = new Socket("localhost", 12345);
socket = new Socket("192.168.85.152", 12345);
// head
CMsgHead head = CMsgHead.newBuilder().setMsglen(5).setMsgtype(1)
.setMsgseq(3).setTermversion(41).setMsgres(5)
.setTermid("Client:head").build();
// body
CMsgReg body = CMsgReg.newBuilder().setArea(11).setRegion(22)
.setShop(33).setRet(44).setTermid("Clent:body").build();
// Msg
CMsg msg = CMsg.newBuilder()
.setMsghead(head.toByteString().toStringUtf8())
.setMsgbody(body.toByteString().toStringUtf8()).build();
// 向服务器发送信息
System.out.println("sendMsg...");
msg.writeTo(socket.getOutputStream());
// 接受服务器的信息
InputStream input = socket.getInputStream();
System.out.println("recvMsg:");
byte[] by = recvMsg(input);
printMsg(CMsg.parseFrom(by));
input.close();
socket.close();
catch (Exception e)
System.out.println(e.toString());
public void printMsg(CMsg g)
try
CMsgHead h = CMsgHead.parseFrom(g.getMsghead().getBytes());
StringBuffer sb = new StringBuffer();
if (h.hasMsglen())
sb.append("==msglen===" + h.getMsglen() + "\n");
if (h.hasMsgres())
sb.append("==msgres===" + h.getMsgres() + "\n");
if (h.hasMsgseq())
sb.append("==msgseq===" + h.getMsgseq() + "\n");
if (h.hasMsgtype())
sb.append("==msgtype===" + h.getMsgtype() + "\n");
if (h.hasTermid())
sb.append("==termid===" + h.getTermid() + "\n");
if (h.hasTermversion())
sb.append("==termversion===" + h.getTermversion() + "\n");
CMsgReg bo = CMsgReg.parseFrom(g.getMsgbody().getBytes());
if (bo.hasArea())
sb.append("==area==" + bo.getArea() + "\n");
if (bo.hasRegion())
sb.append("==region==" + bo.getRegion() + "\n");
if (bo.hasShop())
sb.append("==shop==" + bo.getShop() + "\n");
if (bo.hasRet())
sb.append("==ret==" + bo.getRet() + "\n");
if (bo.hasTermid())
sb.append("==termid==" + bo.getTermid() + "\n");
System.out.println(sb.toString());
catch (Exception e)
e.printStackTrace();
public byte[] recvMsg(InputStream inpustream)
byte[] temp = null;
try
byte len[] = new byte[1024];
int count = inpustream.read(len);
temp = new byte[count];
for (int i = 0; i < count; i++)
temp[i] = len[i];
return temp;
catch (Exception e)
System.out.println(e.toString());
return temp;
本回答被提问者采纳
如何在 iOS 中链接 protobuf
【中文标题】如何在 iOS 中链接 protobuf【英文标题】:How to link protobufs in iOS 【发布时间】:2018-01-20 11:40:37 【问题描述】:我一直在努力让 protobufs 3 为 iOS 编译/运行。一切都编译,但在运行时我得到:
dyld: Library not loaded: /usr/local/lib/libprotobuf.15.dylib
Referenced from: /path/to/TheApp.app/TheApp
Reason: no suitable image found. Did find:
/usr/local/lib/libprotobuf.15.dylib: mach-o, but not built for iOS simulator
这是我的步骤:
-
使用this excellent script为所有架构编译静态库。
将静态库添加到编译目标的
General
选项卡下的Linked Frameworks and Libraries
部分。
构建 => 成功
【问题讨论】:
【参考方案1】:首先,我认为构建脚本实际上并不是在构建静态库。我浏览了脚本并使用lipo
和otool
等工具检查了构建输出。看起来正确。
然后我在构建输出中遇到了这个警告:
URGENT: building for iOS simulator, but linking against dylib (/usr/local/lib/libprotobuf.dylib) built for OSX
我仔细检查了构建目标,以确保我的目标是 iOS。好的。
然后我开始寻找为什么它会链接到动态库,即使一切都是静态的,并在互联网上看到一篇文章说 OSX 更喜欢链接到 DLL 而不是静态库。如果你想解决这个问题,你必须设置你的构建命令some kind of style。我在 Xcode 编辑器中,所以我没有做翻译这个练习。
但是,鉴于此,我删除了对动态库的引用,以查看回退到静态:
rm /usr/local/lib/libprotobuf.dylib
构建。跑。成功。
所以原因是已知的,但这个答案是不完整的。请编辑此答案并提供有关如何让 Xcode 强制静态链接与获取 dylib 的详细信息,以及仅删除 dylib 参考的详细信息
【讨论】:
以上是关于protobuf 怎么在iOS中实用的主要内容,如果未能解决你的问题,请参考以下文章
Jmeter protobuf 测试。无法读取 Protobuf 消息
尴尬的事情又发生Newtonsoft.Json vs Protobuf.net
尴尬的事情又发生Newtonsoft.Json vs Protobuf.net