/ Android

gRPC client side implementation for Android

gRPC is a modern RPC framework developed by Google to call remote methods as easy as if they are local methods. There are a lots of article about gRPC comparison over REST or JSON. So I am not going to talk about it. I will show you how to configure basic gRPC stuf to communicate with Backend Server. For server side implementation read this article.

How it works?

Let me explain how the entire code system works within android studio
Screenshot-from-2018-07-20-16-34-31
To support protobuf, firstly you will need a proto file which will describe the structure or base format of data to be shared. Backend (e.g the webservice) must use the same proto file. Using the PROTO tool you can generate the languages spesific file (e.g the java class file) and copy it to your project. But there a better way to hand over this task to android sutdio which we will use here.
Once it is generated, you can use it as data model in your code.

Add Dependencies

Firstly add protobuf classpath and maven plugin repository in you project level build.gradle file

buildscript {
    // other code
    
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.3'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.5'
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        mavenLocal()
        maven { url "https://plugins.gradle.org/m2/" }
    }
}

After that add gRPC related dependincies in your app level build.gradle file

implementation 'javax.annotation:javax.annotation-api:1.2'
implementation 'io.grpc:grpc-protobuf-lite:1.12.0'
implementation 'io.grpc:grpc-okhttp:1.12.0'
implementation 'io.grpc:grpc-stub:1.12.0'

Good news is there is a plguin to generate java classes in Gradel base system which is added above in project classpath. But it need to integraet with android studio build system to generate java class file at the time of build. To do that add those code to your app level build.gradle file

protobuf {
    protoc {
        artifact = 'com.google.protobuf:protoc:3.0.0'
    }
    plugins {
        grpc {
            artifact = 'io.grpc:protoc-gen-grpc-java:1.0.0-pre2'
        }
        javalite {
            artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'
        }
    }
    generateProtoTasks {
        all()*.plugins {
            javalite {}
        }
        ofNonTest()*.plugins {
            grpc {
                // Options added to --grpc_out
                option 'lite'
            }
        }
    }
}

Add Proto File

You need to keep all proto file in src/main/proto/ directory because the plugin will use this directory to generate java class. Now create LoginService.proto in this directory.

syntax = "proto3";

option java_multiple_files = true;
option java_generic_services = true;
package com.example.learn;

message LoginRequest {
    string username = 1;
    string password = 2;
}

message LoginResponse {
    int32 responseCode = 1;
    string message = 2;
}

service LoginService {
    rpc logIn (LoginRequest) returns (LoginResponse);
}

This will be the exact same file used by server. Now build the project and the plugin will generate necessary java class.

Communicate with Serve

To communcate with server first you have to open a connection by which you will send request

val connectionChannel: ManagedChannel by lazy {
   OkHttpChannelBuilder.forAddress("192.168.0.102", 8080)
             .usePlaintext()
             .build()
}

To send request for login create an object of Login server by using protoc generated class LoginServiceGrpc and request message

val loginService = LoginServiceGrpc.newBlockingStub(connectionChannel)

val requestMessage = LoginRequest.newBuilder()
            .setUsername("Shuza")
            .setPassword("123")
            .build()

Now you can send request for login using the loginService object as like any other method of your project. But android doesn't support network call in main thread so you have to call it in a different thread. Here I use RxJava for threading as gRPC use Observable pattern

Single.fromCallable { loginService.logIn(requestMessage) }
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : SingleObserver<LoginResponse> {
                override fun onSuccess(response: LoginResponse) {
                    // here is your response
                }

                override fun onSubscribe(d: Disposable) {}

                override fun onError(e: Throwable) {
                     // here is your exception
                }
         })

Run

Your project is ready to send request and get response from server. Just run it as an android project.

You will find the sources over on GitHub.