android 使用grpc+https网络请求

第一步:添加相应的网络库和插件等

在app的根目录下的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文件成为

然后再项目的根目录的build.gradle加上
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进行调用。

你可能感兴趣的:(android 使用grpc+https网络请求)