第一步:添加相应的网络库和插件等
在app的根目录下的build.gradle加上网络库
然后再项目的根目录的build.gradle加上
compile 'com.google.code.findbugs:jsr305:3.0.0'
compile 'com.google.guava:guava:18.0'
compile 'io.grpc:grpc-okhttp:1.0.0'
compile 'io.grpc:grpc-protobuf-lite:1.0.0'
compile 'io.grpc:grpc-stub:1.0.0'
compile 'javax.annotation:javax.annotation-api:1.2'
和
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'
}
}
generateProtoTasks {
all().each { task ->
task.plugins {
javalite {}
grpc {
// Options added to --grpc_out
option 'lite'
}
}
}
}
}
顶部加上这个插件
apply plugin: 'com.google.protobuf'
这个插件好像是把proto文件自动生成代码,在build文件夹里面生成的代码。
这个插件可以在设置里面搜索到
在没加上这个插件,proto文件是这样的
加上这个插件,然后点击rebuild project,proto文件成为
classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.0"
这样配置就完成了。
刚刚开始配置的时候,会出现很多的报错。大多都是版本的问题,有些是和gradle版本冲突了,这里我的gradle版本 2.14.1
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
gradle插件版本是:
classpath 'com.android.tools.build:gradle:2.2.3'
配置这些网络库出现过这个问题
解决方法是
在app的build.gradle加上这个
configurations.all {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9'
}
第二步:把proto文件放入到main文件下的proto文件夹下
点击rebuild project,等待生成代码。
第三步:调用网络请求的代码,这里可以参照grpc的github上的例子(gitbub链接
点击打开链接),里面有明确的demo,这个demo是没有tls加密的请求。下面介绍一下通过tsl加密的请求方法
这里这个方法也是在github上找的到一个项目里面的一个方法,放上方法的代码
import android.annotation.TargetApi;
import android.net.SSLCertificateSocketFactory;
import android.os.Build;
import android.support.annotation.Nullable;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.security.auth.x500.X500Principal;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.okhttp.NegotiationType;
import io.grpc.okhttp.OkHttpChannelBuilder;
/**
* A helper class to create a OkHttp based channel.
*/
public class ZnzGrpcChannelBuilder {
/**
* 用来生成ManagedChannel的
* @param host ip地址
* @param port 端口号
* @param serverHostOverride 这个不知道是啥,是服务器端给我的
* @param useTls 是否使用tls加密 ,ture代表使用https加密,false代表不使用,
* @param testCa 证书的流
* @param androidSocketFactoryTls 不知道是啥,传null
* @return
*/
public static ManagedChannel build(String host, int port, @Nullable String serverHostOverride,
boolean useTls, @Nullable InputStream testCa, @Nullable String androidSocketFactoryTls) {
ManagedChannelBuilder<?> channelBuilder = ManagedChannelBuilder.forAddress(host, port);
if (serverHostOverride != null) {
// Force the hostname to match the cert the server uses.
channelBuilder.overrideAuthority(serverHostOverride);
}
if (useTls) {
try {
SSLSocketFactory factory;
if (androidSocketFactoryTls != null) {
factory = getSslCertificateSocketFactory(testCa, androidSocketFactoryTls);
} else {
factory = getSslSocketFactory(testCa);
}
((OkHttpChannelBuilder) channelBuilder).negotiationType(NegotiationType.TLS);
((OkHttpChannelBuilder) channelBuilder).sslSocketFactory(factory);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
// 是否使用tls加密,true不使用
channelBuilder.usePlaintext(true);
}
return channelBuilder.build();
}
private static SSLSocketFactory getSslSocketFactory(@Nullable InputStream testCa)
throws Exception {
if (testCa == null) {
return (SSLSocketFactory) SSLSocketFactory.getDefault();
}
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, getTrustManagers(testCa), null);
return context.getSocketFactory();
}
@TargetApi(14)
private static SSLCertificateSocketFactory getSslCertificateSocketFactory(
@Nullable InputStream testCa, String androidSocketFatoryTls) throws Exception {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH /* API level 14 */) {
throw new RuntimeException(
"android_socket_factory_tls doesn't work with API level less than 14.");
}
SSLCertificateSocketFactory factory = (SSLCertificateSocketFactory)
SSLCertificateSocketFactory.getDefault(5000 /* Timeout in ms*/);
// Use HTTP/2.0
byte[] h2 = "h2".getBytes();
byte[][] protocols = new byte[][]{h2};
if (androidSocketFatoryTls.equals("alpn")) {
Method setAlpnProtocols =
factory.getClass().getDeclaredMethod("setAlpnProtocols", byte[][].class);
setAlpnProtocols.invoke(factory, new Object[]{protocols});
} else if (androidSocketFatoryTls.equals("npn")) {
Method setNpnProtocols =
factory.getClass().getDeclaredMethod("setNpnProtocols", byte[][].class);
setNpnProtocols.invoke(factory, new Object[]{protocols});
} else {
throw new RuntimeException("Unknown protocol: " + androidSocketFatoryTls);
}
if (testCa != null) {
factory.setTrustManagers(getTrustManagers(testCa));
}
return factory;
}
private static TrustManager[] getTrustManagers(InputStream testCa) throws Exception {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(testCa);
X500Principal principal = cert.getSubjectX500Principal();
ks.setCertificateEntry(principal.getName("RFC2253"), cert);
// Set up trust manager factory to use our key store.
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(ks);
return trustManagerFactory.getTrustManagers();
}
}
使用就直接调用build方法,如果有https加密就useTls传入true,然后传入证书的流即可,这样可以拿到ManagedChannel对象,然后参照官方的demo调用网络请求了。
介绍一下proto文件里面的内容,我们就看官方给的helloworld.proto文件,
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;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
SayHello是一个方法,helloRequest是入参,helloReply是返回的类型
我们看一下官方的demo里面的方法:
@Override
protected String doInBackground(Void... nothing) {
try {
ManagedChannel mChannel = ManagedChannelBuilder.forAddress(mHost, mPort)
.usePlaintext(true)
.build();
GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(mChannel);
HelloRequest message = HelloRequest.newBuilder().setName(mMessage).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;
}
}
写的也是很简单,可以对其进行适当的封装,可以使用AsyncTask调用,也可以使用rxjava进行调用。