This tutorial is to show you the basic set up to get GRPC working with an Android app using Java as the primary language.
Prerequisites
Set Up
Were going to be borrowing the example java server from the main grpc-java repo
change directories to the examples folder
execute
./gradlew installDist
then run
./build/install/examples/bin/hello-world-server
In the
Welcome to Android Studio
window, clickCreate New Project
.In the
Select a Project Template
window, selectEmpty Activity
and clickNext.
-
In the Configure your project window, complete the following:
- Enter
HelloWorldGrpc
in theName
field. - Select
Java Language
drop-down menu. - Click
Finish
- Enter
-
Open
AndroidManifest.xml
add this line above the application block.<uses-permission android:name="android.permission.INTERNET" />
- For reference here is what it should look like
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.helloworldgrpc"> <uses-permission android:name="android.permission.INTERNET" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.HelloWorldGrpc"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
-
Open the project gradle file and add this line to the dependencies section
-
classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.14"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersbuildscript { repositories { google() jcenter() } dependencies { classpath "com.android.tools.build:gradle:4.1.2" classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.14" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } }
-
-
Next we add some lines to the module gradle file
- Add com.google.protobuf to the top in the plugins object
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
plugins { id 'com.android.application' id 'com.google.protobuf' } - Add the protobuf block, I add this right above the dependencies block
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.12.0' } plugins { grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.35.0' } } generateProtoTasks { all().each { task -> task.builtins { java { option 'lite' } } task.plugins { grpc { option 'lite' } } } } } - Add the dependencies to the block, the
okhttp
,grpc-protobuf-lite
,grpc-stub
,annotations-api
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersdependencies { implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.3.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' // GRPC Deps implementation 'io.grpc:grpc-okhttp:1.35.0' implementation 'io.grpc:grpc-protobuf-lite:1.35.0' implementation 'io.grpc:grpc-stub:1.35.0' implementation 'org.apache.tomcat:annotations-api:6.0.53' }
- Add com.google.protobuf to the top in the plugins object
-
Now time to add the proto file
- Your going to want to go to the terminal and create the proto directory in the main folder
- Then create the proto file, whats great about using gradle and GRPC dependencies is that the proto files are automatically compiled for you
touch HelloWorld.proto
- Add this to the file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
syntax = "proto3"; option java_multiple_files = true; option java_package = "com.example.helloworldgrpc"; option java_outer_classname = "HelloWorldProto"; package helloworld; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }
- Your going to want to go to the terminal and create the proto directory in the main folder
-
Lets now add the text fields and buttons to the main activity
- Open the
activity_main.xml
file - Your going to want to delete the
TextView
componentYour going to want to add these components to the view
-
PlainText
three of them, one for the host input, another for the port input and a third for the message -
TextView
for the result message -
Button
for the sending action - It doesn't matter how you arrange them, if you wanted to get this done quickly then copy the xml file from step 9
- Open the
-
Add ID's and settings for the components
For the host and port, I like to default those to the grpc server- Host
PlainText
component id should equalhost
- Port
PlainText
component id should equalport
- Message
PlainText
component id should equalmessage
- Send/Submit
Button
component id should equalsend
- Result
TextView
component id should equalresult
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/result" android:layout_width="358dp" android:layout_height="473dp" android:layout_marginTop="16dp" android:layout_marginBottom="16dp" android:text="Result" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/send" /> <EditText android:id="@+id/host" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginTop="16dp" android:ems="10" android:hint="Host" android:inputType="textPersonName" android:text="10.0.2.2" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <EditText android:id="@+id/port" android:layout_width="153dp" android:layout_height="wrap_content" android:layout_marginStart="12dp" android:layout_marginTop="16dp" android:layout_marginEnd="16dp" android:ems="10" android:hint="Port" android:inputType="textPersonName" android:text="50051" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="1.0" app:layout_constraintStart_toEndOf="@+id/host" app:layout_constraintTop_toTopOf="parent" /> <EditText android:id="@+id/message" android:layout_width="380dp" android:layout_height="58dp" android:layout_marginTop="16dp" android:ems="10" android:hint="Message" android:inputType="textPersonName" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/host" /> <Button android:id="@+id/send" android:layout_width="177dp" android:layout_height="36dp" android:layout_marginTop="16dp" android:onClick="sendGrpcMessage" android:text="Submit" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/message" /> </androidx.constraintlayout.widget.ConstraintLayout>
- Host
-
Now we move on to the code of the
MainActivity
. Open up the MainActivity file and declare these varshostEdit
portEdit
messageEdit
sendButton
-
resultText
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characterspublic class MainActivity extends AppCompatActivity { private EditText hostEdit; private EditText portEdit; private EditText messageEdit; private Button sendButton; private TextView resultText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
-
Add this code to
onCreate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); hostEdit = (EditText) findViewById(R.id.host); portEdit = (EditText) findViewById(R.id.port); messageEdit = (EditText) findViewById(R.id.message); sendButton = (Button) findViewById(R.id.send); resultText = (TextView) findViewById(R.id.result); resultText.setMovementMethod(new ScrollingMovementMethod()); } -
Add the
GrpcTask
and code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersprivate static class GrpcTask extends AsyncTask<String, Void, String> { private final WeakReference<Activity> activityReference; private ManagedChannel channel; private GrpcTask(Activity activity) { this.activityReference = new WeakReference<Activity>(activity); } @Override protected String doInBackground(String... params) { String host = params[0]; String message = params[1]; String portStr = params[2]; int port = TextUtils.isEmpty(portStr) ? 0 : Integer.valueOf(portStr); try { channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build(); GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(channel); HelloRequest request = HelloRequest.newBuilder().setName(message).build(); HelloReply reply = stub.sayHello(request); return reply.getMessage(); } catch (Exception e) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); pw.flush(); return String.format("Failed... : %n%s", sw); } } @Override protected void onPostExecute(String result) { try { channel.shutdown().awaitTermination(1, TimeUnit.SECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } Activity activity = activityReference.get(); if (activity == null) { return; } TextView resultText = (TextView) activity.findViewById(R.id.result); Button sendButton = (Button) activity.findViewById(R.id.send); resultText.setText(result); sendButton.setEnabled(true); } } -
Add the
sendGrpcMessage
function that will tie to the submit button
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characterspublic void sendGrpcMessage(View view) { ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)) .hideSoftInputFromWindow(hostEdit.getWindowToken(), 0); sendButton.setEnabled(false); resultText.setText(""); new GrpcTask(this) .execute( hostEdit.getText().toString(), messageEdit.getText().toString(), portEdit.getText().toString()); } Go back to
activity_main.xml
and set the button onClick listener tosendGrpcMessage
-
Run the app on the emulator
- For the host use
10.0.2.2
- For the port use
50051
- Then add a message
- Click Submit
- You should get back Hello and what ever you placed in the message component and see it in the result component
- For the host use
Link to the code for https://github.com/efernie/Android-Java-Grpc-Tutorial
A Kotlin version is coming soon
Top comments (0)