目录
- 各种配置文件
- 编写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"; | |
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>() { | |
public void onNext(HelloReply value) { | |
//Log.d(TAG, "sayHello onNext."); | |
Log.d(TAG, value.getMessage()); | |
} | |
public void onError(Throwable t) { | |
Log.d(TAG, "sayHello onError."); | |
} | |
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文件中添加网络权限
<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> |
运行上述代码,如果能在控制台看到下面的这句话就说明环境搭建成功了。
结语
这次的环境搭建真的非常艰难,前前后后遇到了各种问题。不得不说,安卓编程对于版本太敏感了,只要有一个版本没有对应上项目都可能跑不通。