Android搭建grpc环境过程分步详解

手机APP/开发
485
0
0
2023-05-05
目录
  • 各种配置文件
  • 编写proto文件并编译
  • 编写简单的demo代码
  • 结语

下面介绍的这个版本搭配是我研究好久好久才跑通的,这在我的电脑上是一组可行的配置,如果你使用了同样的配置跑不通,那可能是环境中某一部分还是有不同的地方,需要你自己再去找一下解决问题的办法,那么话不多说,直接上配置吧。

各种配置文件

首先我们需要设置三个配置文件,如下图所示

我们先来看一下项目设置setting.gradle,按照我的理解,这里应该是设置一些gradle仓库地址,还有项目中包含的模块等等信息。

我的配置是这样写的

pluginManagement {
  repositories {
    gradlePluginPortal()
    google()
    mavenCentral()
  }
}
dependencyResolutionManagement {
  repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
  repositories {
    google()
    mavenCentral()
    maven { url 'https://jitpack.io' }
    maven { url 'https://repo.eclipse.org/content/repositories/paho-releases/'}
  }
}
rootProject.name = "grpc_project_plus"
include ':app'

接着是项目的的build.gradle,这里面需要引入一些插件和进行gradle版本设置,其中gradle版本设置也是一个坑,版本号要设置对才行

buildscript {
  repositories {
    maven{ url 'https://maven.aliyun.com/repository/jcenter'}
    maven { url 'https://maven.aliyun.com/repository/google' }
    maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
    maven { url 'https://maven.aliyun.com/repository/public' }
    google()
    mavenCentral()
  }
  dependencies {
    classpath "com.android.tools.build:gradle:7.2.0"
    classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.17"
  }
}
task clean(type: Delete) {
  delete rootProject.buildDir
}

从上面的配置中我们可以看出,我们使用的gradle插件的版本是7.2.0,然后配置的gradle版本是7.4,具体的设置方法就是到gradle的配置文件中指定

当然也有一个简单的办法,就是到project structure中去指定

上面这张图按照我的理解,上面是插件的版本号,下面就是gradle的版本号,这两个不对应的话容易出问题,这里顺便说一下,我的Android Studio的版本应该是2021.3.1,就是海豚的图标。(经过这次的环境搭建,我现在对于版本号真的非常敏感,调版本号真的太折磨人了)

最后就是模块的build.gradle,我找到的一个能跑通demo的设置如下

plugins {
  id 'com.android.application'
  id 'com.google.protobuf'
}
android {
  namespace 'com.example.grpc_project_plus'
  compileSdk 32
  defaultConfig {
    applicationId "com.example.grpc_project_plus"
    minSdk 29
    targetSdk 32
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
  }
  buildTypes {
    release {
      minifyEnabled false
      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
  }
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
  configurations.all {
    resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.1'
    exclude group: 'com.google.guava', module: 'listenablefuture'
  }
  sourceSets {
    main {
      proto {
        srcDir 'src/main/proto'
      }
    }
  }
  packagingOptions {
    pickFirst 'META-INF/INDEX.LIST'
    pickFirst 'META-INF/LICENSE'
    pickFirst 'META-INF/io.netty.versions.properties'
  }
}
protobuf {
  protoc {
    artifact = 'com.google.protobuf:protoc:3.17.2'
  }
  plugins {
    /*javalite {
      artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0"
    }*/
    grpc {
      artifact = 'io.grpc:protoc-gen-grpc-java:1.39.0' // CURRENT_GRPC_VERSION
    }
  }
  generateProtoTasks {
    all().each { task ->
      task.builtins {
        java { option 'lite' }
      }
      task.plugins {
        grpc { // Options added to --grpc_out
          option 'lite' }
      }
    }
  }
}
dependencies {
  implementation 'androidx.appcompat:appcompat:1.4.1'
  implementation 'com.google.android.material:material:1.5.0'
  implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
  testImplementation 'junit:junit:4.13.2'
  androidTestImplementation 'androidx.test.ext:junit:1.1.3'
  androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
  /*implementation 'io.grpc:grpc-okhttp:1.1.2'
  implementation 'io.grpc:grpc-netty:1.1.2'
  implementation 'io.grpc:grpc-protobuf-lite:1.1.2'
  implementation 'io.grpc:grpc-stub:1.1.2'
  implementation 'javax.annotation:javax.annotation-api:1.2'*/
  // You need to build grpc-java to obtain these libraries below.
  implementation 'io.grpc:grpc-netty:1.39.0'
  implementation 'io.grpc:grpc-okhttp:1.39.0' // CURRENT_GRPC_VERSION
  implementation 'io.grpc:grpc-protobuf-lite:1.39.0' // CURRENT_GRPC_VERSION
  implementation 'io.grpc:grpc-stub:1.39.0' // CURRENT_GRPC_VERSION
  implementation 'org.apache.tomcat:annotations-api:6.0.53'
}

编写proto文件并编译

配置好了上述环境后,我们需要编译proto文件。

首先在main目录下新建一个文件夹proto,然后编写hello.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;
}

这是一个简单的grpc接口调用,具体的语法我就不说了,这篇文章主要是讲环境搭建。

接着编译项目,如果编译成功的话,可以在build文件夹中看到grpc相关的java文件。

编写简单的demo代码

这是最后一步,在主Activity中编写简单的客户端和服务端代码测试grpc服务是否可以正常使用。

public class MainActivity extends AppCompatActivity {
private static final String TAG = "GrpcDemo";
private static final int PROT = 56322;
private static final String NAME = "hello world";
private static final String HOST = "localhost";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "start");
startServer(PROT);
Log.d(TAG, "start server.");
startClient(HOST, PROT, NAME);
Log.d(TAG, "start client.");
}
private void startServer(int port){
try {
NettyServerBuilder.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){
ManagedChannel mChannel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext()
.build();
GreeterGrpc.GreeterStub stub = GreeterGrpc.newStub(mChannel);
HelloRequest message = HelloRequest.newBuilder().setName(name).build();
stub.sayHello(message, new StreamObserver<HelloReply>() {
@Override
public void onNext(HelloReply value) {
//Log.d(TAG, "sayHello onNext.");
Log.d(TAG, value.getMessage());
}
@Override
public void onError(Throwable t) {
Log.d(TAG, "sayHello onError.");
}
@Override
public void onCompleted() {
Log.d(TAG, "sayHello onCompleted.");
}
});
}
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(request.getName())
.build();
}
}
}

然后需要在AndroidManifest.xml文件中添加网络权限

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Grpc_project_plus"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
</application>
</manifest>

运行上述代码,如果能在控制台看到下面的这句话就说明环境搭建成功了。

结语

这次的环境搭建真的非常艰难,前前后后遇到了各种问题。不得不说,安卓编程对于版本太敏感了,只要有一个版本没有对应上项目都可能跑不通。