Android上使用grpc的方法教程

Android上使用grpc的方法教程,第1张

概述前言最近的一个项目使用到了grpc实现跨平台的远程调用,在安卓端使用的时候遇到了一些坑,这里记录一下。

前言

最近的一个项目使用到了grpc实现跨平台的远程调用,在安卓端使用的时候遇到了一些坑,这里记录一下。

首先根据grpc androID的官方Demo配置grpc依赖,测试它的hello world工程。

编译谷歌官方的helloworld工程

添加rotobuf-gradle-plugin插件

首先添加rotobuf-gradle-plugin插件,他是用来从proto文件自动生成java代码的:

//Project的build.gradle中添加rotobuf-gradle-plugin插件buildscript { ... dependencIEs { ... classpath "com.Google.protobuf:protobuf-gradle-plugin:0.8.0" ... } ...}
//App的build.gradle中添加下面配置apply plugin: 'com.Google.protobuf'protobuf { protoc { artifact = 'com.Google.protobuf:protoc:3.0.0' } plugins { javalite {  artifact = "com.Google.protobuf:protoc-gen-javalite:3.0.0" } grpc {  artifact = 'io.grpc:protoc-gen-grpc-java:1.0.0' // CURRENT_GRPC_VERSION } } generateProtoTasks { all().each { task ->  task.plugins {  javalite {}  grpc {   // Options added to --grpc_out   option 'lite'  }  } } }}

添加proto文件并自动生成java代码

在src/main/目录下创建一个proto目录,并将官方的helloworld.proto放到proto目录下

之后只需要rebuild一下就能看到build/generated/source/proto/目录下根据helloworld.proto生成了几个java类


添加安卓端grpc的依赖

//App的build.gradle中添加下面配置 dependencIEs { ... compile 'io.grpc:grpc-okhttp:1.1.2' compile 'io.grpc:grpc-protobuf-lite:1.1.2' compile 'io.grpc:grpc-stub:1.1.2' compile 'javax.annotation:javax.annotation-API:1.2' ...}
configurations.all { resolutionStrategy.force 'com.Google.code.findBUGs:Jsr305:3.0.1' }

我这个时候报了这个错误

Warning:Conflict with dependency ‘com.Google.code.findBUGs:Jsr305'. Resolved versions for app (3.0.0) and test app (2.0.1) differ. See http://g.co/androIDstudio/app-test-app-conflict for details.

这是因为com.Google.code.findBUGs:Jsr305的版本不一致导致的

可以在App的build.gradle的androID标签中配置一下解决

androID { ... configurations.all { resolutionStrategy.force 'com.Google.code.findBUGs:Jsr305:3.0.1' } ...}

编写demo代码

public class MainActivity extends AppCompatActivity { private static final String TAG = "GrpcDemo"; private static final int PROT = 55055; private static final String name = "linjw"; private static final String HOST = "localhost"; @OverrIDe protected voID onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVIEw(R.layout.activity_main); startServer(PROT); startClIEnt(HOST,PROT,name); } private voID startServer(int port){ try {  Server server = ServerBuilder.forPort(port)   .addService(new GreeterImpl())   .build()   .start(); } catch (IOException e) {  e.printstacktrace();  Log.d(TAG,e.getMessage()); } } private voID startClIEnt(String host,int port,String name){ new GrpcTask(host,port,name).execute(); } private class GreeterImpl extends GreeterGrpc.GreeterImplBase { public voID sayHello(HelloRequest request,StreamObserver<HelloReply> responSEObserver) {  responSEObserver.onNext(sayHello(request));  responSEObserver.onCompleted(); } private HelloReply sayHello(HelloRequest request) {  return HelloReply.newBuilder()   .setMessage("hello "+ request.getname())   .build(); } } private class GrpcTask extends AsyncTask<VoID,VoID,String> { private String mHost; private String mname; private int mPort; private ManagedChannel mChannel; public GrpcTask(String host,String name) {  this.mHost = host;  this.mname = name;  this.mPort = port; } @OverrIDe protected voID onPreExecute() { } @OverrIDe protected String doInBackground(VoID... nothing) {  try {  mChannel = ManagedChannelBuilder.forAddress(mHost,mPort)   .usePlaintext(true)   .build();  GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(mChannel);  HelloRequest message = HelloRequest.newBuilder().setname(mname).build();  HelloReply reply = stub.sayHello(message);  return reply.getMessage();  } catch (Exception e) {  StringWriter sw = new StringWriter();  PrintWriter pw = new PrintWriter(sw);  e.printstacktrace(pw);  pw.flush();  return "Failed... : " + System.lineseparator() + sw;  } } @OverrIDe protected voID onPostExecute(String result) {  try {  mChannel.shutdown().awaitTermination(1,TimeUnit.SECONDS);  } catch (InterruptedException e) {  Thread.currentThread().interrupt();  }  Log.d(TAG,result); } }}

这段代码运行会崩溃:

Caused by: io.grpc.ManagedChannelProvIDer$ProvIDerNotFoundException: No functional server found. Try adding a dependency on the grpc-netty artifact

猜测Google使用netty替代了okhttp,尝试换成grpc-netty的依赖:

dependencIEs { ... compile 'io.grpc:grpc-netty:1.1.2' compile 'io.grpc:grpc-protobuf-lite:1.1.2' compile 'io.grpc:grpc-stub:1.1.2' compile 'javax.annotation:javax.annotation-API:1.2' ...}

这么编译会报错

com.androID.build.API.transform.transformException: com.androID.builder.packaging.DuplicatefileException: Duplicate files copIEd in APK meta-inf/INDEX.List

需要加上下面的配置解决

androID { ... packagingOptions { pickFirst 'meta-inf/INDEX.List' pickFirst 'meta-inf/liCENSE' pickFirst 'meta-inf/io.netty.versions.propertIEs' } ...}

当然,还需要加上INTERNET权限,要不然运行的时候还是会崩溃。

最终就能看的下面的打印,这样安卓grpc的helloworld就成功了。

03-03 00:04:20.000 6137-6137/linjw.com.grpcdemo D/GrpcDemo: hello linjw

使用com.Google.protobuf.Any

Any可以携带任意类型的数据,用法相当于c语言的voID指针。在项目中是很常用的,但是谷歌在javalite的版本不支持Any。

如果在proto文件中使用了Any的话生成java代码就会有报错,例如将helloworld的proto文件改成下面的样子:

// copyright 2015,Google Inc.// All rights reserved.//// Redistribution and use in source and binary forms,with or without// modification,are permitted provIDed that the following conditions are// met://// * Redistributions of source code must retain the above copyright// notice,this List of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above// copyright notice,this List of conditions and the following disclaimer// in the documentation and/or other materials provIDed with the// distribution.// * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived from// this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE copYRIGHT HolDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,INCLUDING,BUT NOT// liMITED TO,THE IMPLIED WARRANTIES OF MERCHANTABIliTY AND fitness FOR// A PARTIculaR PURPOSE ARE disCLaimED. IN NO EVENT SHALL THE copYRIGHT// OWNER OR CONTRIBUTORS BE liABLE FOR ANY DIRECT,INDIRECT,INCIDENTAL,// SPECIAL,EXEMPLARY,OR CONSEQUENTIAL damAGES (INCLUDING,PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA,OR PROFITS; OR BUSInesS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF liABIliTY,WHETHER IN CONTRACT,STRICT liABIliTY,OR TORT// (INCLUDING NEGliGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE,EVEN IF ADVISED OF THE POSSIBIliTY OF SUCH damAGE.Syntax = "proto3";option java_multiple_files = true;option java_package = "io.grpc.examples.helloworld";option java_outer_classname = "HelloWorldProto";option objc_class_prefix = "HLW";package helloworld;import "Google/protobuf/any.proto";// The greeting service deFinition.service Greeter { // Sends a greeting rpc SayHello (Google.protobuf.Any) returns (HelloReply) {}}// The request message containing the user's name.message HelloRequest { string name = 1;}// The response message containing the greetingsmessage HelloReply { string message = 1;}

报错如下

Google/protobuf/any.proto: file not found.helloworld.proto: import “Google/protobuf/any.proto” was not found or had errors.helloworld.proto:44:17: “Google.protobuf.Any” is not defined.

使用grpc-jave代替grpc-javalite

但是现在做的这个项目的linux端实现已经用了Any,要改的话需要耗费比较大的精力。幸好尝试了下,发现安卓上也能跑支持Any的grpc-java。

首先我们要使用grpc-protobuf依赖替换grpc-protobuf-lite依赖

dependencIEs { ... compile 'io.grpc:grpc-netty:1.1.2' compile 'io.grpc:grpc-protobuf:1.1.2' compile 'io.grpc:grpc-stub:1.1.2' compile 'javax.annotation:javax.annotation-API:1.2' ...}

接着修改protobuf-gradle-plugin配置使得自动生成java的代码而不是javalite的代码

protobuf { protoc {  artifact = 'com.Google.protobuf:protoc:3.0.0' } plugins {  grpc {   artifact = 'io.grpc:protoc-gen-grpc-java:1.0.0' // CURRENT_GRPC_VERSION  } } generateProtoTasks {  all().each { task ->   task.builtins {    java {}   }   task.plugins {    grpc {}   }  } }}

对应的修改helloworld的代码就能运行了

public class MainActivity extends AppCompatActivity { private static final String TAG = "GrpcDemo"; private static final int PROT = 55055; private static final String name = "linjw"; private static final String HOST = "localhost"; @OverrIDe protected voID onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentVIEw(R.layout.activity_main);  startServer(PROT);  startClIEnt(HOST,name); } private voID startServer(int port){  try {   Server server = ServerBuilder.forPort(port)     .addService(new GreeterImpl())     .build()     .start();  } catch (IOException e) {   e.printstacktrace();   Log.d(TAG,e.getMessage());  } } private voID startClIEnt(String host,String name){  new GrpcTask(host,name).execute(); } private class GreeterImpl extends GreeterGrpc.GreeterImplBase {  public voID sayHello(Any request,StreamObserver<HelloReply> responSEObserver) {   try {    responSEObserver.onNext(sayHello(request.unpack(HelloRequest.class)));    responSEObserver.onCompleted();   } catch (InvalIDProtocolBufferException e) {    e.printstacktrace();   }  }  private HelloReply sayHello(HelloRequest request) {   return HelloReply.newBuilder()     .setMessage("hello "+ request.getname())     .build();  } } private class GrpcTask extends AsyncTask<VoID,String> {  private String mHost;  private String mname;  private int mPort;  private ManagedChannel mChannel;  public GrpcTask(String host,String name) {   this.mHost = host;   this.mname = name;   this.mPort = port;  }  @OverrIDe  protected voID onPreExecute() {  }  @OverrIDe  protected String doInBackground(VoID... nothing) {   try {    mChannel = ManagedChannelBuilder.forAddress(mHost,mPort)      .usePlaintext(true)      .build();    GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(mChannel);    HelloRequest message = HelloRequest.newBuilder().setname(mname).build();    HelloReply reply = stub.sayHello(Any.pack(message));    return reply.getMessage();   } catch (Exception e) {    StringWriter sw = new StringWriter();    PrintWriter pw = new PrintWriter(sw);    e.printstacktrace(pw);    pw.flush();    return "Failed... : " + System.lineseparator() + sw;   }  }  @OverrIDe  protected voID onPostExecute(String result) {   try {    mChannel.shutdown().awaitTermination(1,TimeUnit.SECONDS);   } catch (InterruptedException e) {    Thread.currentThread().interrupt();   }   Log.d(TAG,result);  } }}

完整的demo代码可以点这里在我的github中查看(也可以通过本地下载)

AndroID方法数不能超过65535的问题

最后使用grpc,方法数会超过65535,可以使用com.androID.support:multIDex去解决

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如有疑问大家可以留言交流,谢谢大家对编程小技巧的支持。

总结

以上是内存溢出为你收集整理的Android上使用grpc的方法教程全部内容,希望文章能够帮你解决Android上使用grpc的方法教程所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1213704.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-04
下一篇 2022-06-04

发表评论

登录后才能评论

评论列表(0条)

保存