{"id":19892004,"url":"https://github.com/liuyuweitarek/simple_sample_grpc","last_synced_at":"2026-05-03T12:31:18.160Z","repository":{"id":128616270,"uuid":"430154972","full_name":"liuyuweitarek/Simple_Sample_gRPC","owner":"liuyuweitarek","description":"Step-by-Step Guide to Implementing a Simple gRPC Connection between Android (Client) and Python (Server)","archived":false,"fork":false,"pushed_at":"2021-11-21T16:19:36.000Z","size":9272,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-01T05:26:25.939Z","etag":null,"topics":["android-client","grpc","java","python-server","python3"],"latest_commit_sha":null,"homepage":"https://medium.com/@liuyuwei.tarek/step-by-step-implement-simple-sample-of-grpc-connection-android-as-client-and-python-as-server-78eb3dbad600","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/liuyuweitarek.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-11-20T16:37:08.000Z","updated_at":"2023-09-11T15:21:30.000Z","dependencies_parsed_at":"2023-05-04T03:14:47.994Z","dependency_job_id":null,"html_url":"https://github.com/liuyuweitarek/Simple_Sample_gRPC","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/liuyuweitarek/Simple_Sample_gRPC","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liuyuweitarek%2FSimple_Sample_gRPC","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liuyuweitarek%2FSimple_Sample_gRPC/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liuyuweitarek%2FSimple_Sample_gRPC/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liuyuweitarek%2FSimple_Sample_gRPC/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/liuyuweitarek","download_url":"https://codeload.github.com/liuyuweitarek/Simple_Sample_gRPC/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liuyuweitarek%2FSimple_Sample_gRPC/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272289214,"owners_count":24907797,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-27T02:00:09.397Z","response_time":76,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android-client","grpc","java","python-server","python3"],"created_at":"2024-11-12T18:20:54.247Z","updated_at":"2026-05-03T12:31:13.125Z","avatar_url":"https://github.com/liuyuweitarek.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Simple-Sample-gRPC : Implement gRPC Connection: Android as Client | Python as Server\n\n\n## Demo\n\n![image](https://github.com/liuyuweitarek/Simple_Sample_gRPC/blob/main/Demo/simple_grpc_demo.gif)\n\n## Quick Start\n\n1. Clone Project\n    \n    ```bash\n    $ git clone https://github.com/liuyuweitarek/Simple_Sample_gRPC.git\n    ```\n    \n2. Start Python gRPC Server\n    \n    ```bash\n    $ cd Simple_Sample_gRPC/Python_gRPC_Server\n    $ python run.py\n    ```\n    \n3. Install Android App\n    \n    If you use Android emulator and set up python server on your localhost, please input 10.0.2.2  in App UI.\n    \n\n## Step by Step\n\nFollow the steps on the gRPC documents. ([https://grpc.io/docs/languages/python/quickstart/](https://grpc.io/docs/languages/python/quickstart/)) and record some details here. \n\n1. Define your proto file and place it under your android project folder.\n    \n    e.g.  \n    \n    ```bash\n    $ mkdir ./Simple_gRPC/Android_gRPC_Client/src/main/proto\n    $ vim interaction.proto\n    ```\n    \n    interaction.proto\n    \n    ```protobuf\n    /**\n     * Send Message between  Android APP Client and Python Server.\n     */\n    \n    syntax = \"proto3\";\n    \n     option java_multiple_files = true;\n     option java_package = \"com.interaction.robot.interaction\";\n     option java_outer_classname = \"InteractProto\";\n     option objc_class_prefix = \"ST\";\n    \n     package interaction;\n    \n     // The interact service definition.\n     service Interact {\n       // Sends connection confirm\n       rpc SimpleConnect (ConnectRequest) returns (ConnectReply) {}\n    \n       // Sends information\n       rpc SimpleSend (Input) returns (Output) {}\n    \n     }\n    \n     // The connect request message contains the status\n     message ConnectRequest {\n       string status = 1;\n     }\n    \n     // The connect response message contains the status\n     message ConnectReply {\n       string status = 1;\n     }\n    \n     // The input message contains the utterance\n     message Input {\n       string utterance = 1;\n     }\n    \n     // The output info message contains the utterance\n     message Output {\n       string utterance = 1;\n     }\n    ```\n    \n2. Using python module \"grpcio\" and \"grpcio-tools\" to generate your python server configuration and protocol objects.\n    \n    ```bash\n    $ pip install grpcio grpcio-tools\n    ```\n    \n    ```bash\n    python -m grpc_tools.protoc --proto_path={.proto_filepath} {.proto filename} --python_out={generated_python_filepath} --grpc_python_out={generated_python_grpc__filepath}\n    \n    # (e.g.)\n    # $ cd to the .proto filepath\n    # $ python -m grpc_tools.protoc --proto_path=. ./interaction.proto --python_out=../../../../Python_gPRC_Server/. --grpc_python_out=../../../../Python_gPRC_Server/.\n    ```\n    \n3.  How to use Python Server\n    \n    In last step, we generated two files, *_pb2.py and *_pb2_grpc.py, which contained objects of python gRPC protocol and settings. In the purpose of using them in a clean way, we'll define a new server object and set up a server folder.\n    \n    \n    - Python_gRPC_Server\n        - interaction_pb2.py\n        - interaction_pb2_grpc.py\n        - InteracterServer.py\n            \n            Define Server which maintains the connection settings and API usage.\n            \n            ```python\n            \"\"\"\n            File: InteracterServer.py\n            Author: Yuwei Liu\n            Institution: Modeling and Informatics Laboratory\n            Version: v0.1.0\n            \"\"\"\n            \n            import os\n            import grpc\n            import time\n            from random import randrange\n            from concurrent import futures\n            import socket\n            import logging\n            import json\n            import interaction_pb2\n            import interaction_pb2_grpc \n            \n            class Server(interaction_pb2_grpc.InteractServicer):\n                \"\"\" \n                This is the only class in the interacter package.\n                It creates a gRPC server with the computer's local ip address with a specified port.\n                \"\"\"\n            \n                logging.basicConfig(level=os.environ.get(\"LOGLEVEL\",\"INFO\"))\n                log = logging.getLogger(__name__)\n                \n                is_connected = False\n                client_type = ''\n                client_ip = ''\n                client_command = None\n                client_response = ''\n            \n                ERR_EMPTY_ARGS = 'Cannot have empty args!'\n            \n                def __init__(self, port):\n                    \"\"\" \n                    The constructor for Server class. \n              \n                    Arguments: \n                       port (int): The port where the server will be listening for incoming client connections. \n                    \"\"\"\n            \n                    self.server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))\n                    interaction_pb2_grpc.add_InteractServicer_to_server(self, self.server)\n                    self.server.add_insecure_port('[::]:' + str(port))\n                    self.log.info('gRPC server started on address '+ self.get_ip() + ':' + str(port))\n                    self.server.start()\n                    \n            \n                def SimpleConnect(self, request, context):\n                    \"\"\" \n                    This method is called when a client connects to the server. \n                    \"\"\"\n                    self.is_connected = True\n                    handshake = json.loads(request.status)\n                    self.client_type = handshake[\"intent\"]\n                    self.client_ip = handshake[\"value\"]\n                    \n                    return interaction_pb2.ConnectReply(status=\"I got it. --from Python Server\")\n            \n                def SimpleSend(self, request, context):\n                    \"\"\" \n                    This method is called every time a message is received from the client. \n                    If the robot returns an error message, it will be printed in the log.\n                    \"\"\"\n                    \n                    json_response = json.loads(request.utterance)\n            \n                    if 'value' in json_response:\n                        self.client_response = json_response['value']\n                    else:\n                        self.client_response = None\n            \n                    if json_response['intent'] == 'error':\n                        self.log.warning(self.client_response)\n            \n                    self.client_command = None\n                    while self.client_command == None:\n                        time.sleep(.2)\n            \n                    return interaction_pb2.Output(utterance=self.client_command)\n            \t\t\n            \t\tdef Other_Client_API(self, value_to_client=value):\n            \t\t\t\toutput = {'intent': 'client_function', 'value': str(value)}\n                    self.client_command = json.dumps(output)\n                \n                    while self.client_command != None:\n                        time.sleep(0.1)\n            \n                    return self.client_response\n            ```\n            \n        - run.py\n            \n            Here we could use the APIs and add other services\n            \n            ```python\n            \"\"\"\n            File: interacter.py\n            Author: Yuwei Liu\n            Institution: Modeling and Informatics Laboratory\n            Version: v0.1.0\n            \"\"\"\n            \n            from InteracterServer import Server\n            import time\n            import os\n            import sys\n            import argparse\n            from threading import Thread\n            import subprocess\n            \n            class MainLoop(object):\n                def __init__(self, args):\n                    self.path = os.path.dirname(os.path.abspath(__file__))\n            \n                    self.server = Server(50051)\n            \n                    #Wait until the robot has connected\n                    while not self.server.is_connected:\n                        time.sleep(1)\n            \n                    print('client connected: ' + self.server.client_type)\n            \n                def start(self):\n            \t\t\t\tself.server.other_client_function(value=\"haha\")\n                    input(\"Success Start...\")\n            \n            if __name__ == \"__main__\":\n                parser = argparse.ArgumentParser()\n                args = parser.parse_args()\n                mainLoop = MainLoop(args)\n                mainLoop.start()\n            ```\n            \n4.  Set Android Java Client\n    \n    Please notify TAG \"// \u003c!Edit Here\u003e--/\u003e\" in the files below.\n    \n    - Import gRPC to Global Gradle\n        \n        ./Simple_gRPC/build.gradle :\n        \n        ```groovy\n        // Top-level build file where you can add configuration options common to all sub-projects/modules.\n        \n        buildscript {\n            \n            repositories {\n                google()\n                jcenter()\n            }\n            dependencies {\n                classpath 'com.android.tools.build:gradle:3.2.1'\n        \t\t\t\t\n        \t\t\t\t//\u003c!Add Protobuf Classpath\u003e\n                classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.8'  \n        \t\t\t\t//--/\u003e\n                \n        \t\t\t\t// NOTE: Do not place your application dependencies here; they belong\n                // in the individual module build.gradle files\n            }\n        }\n        \n        allprojects {\n            repositories {\n                google()\n                jcenter()\n            }\n        }\n        \n        task clean(type: Delete) {\n            delete rootProject.buildDir\n        }\n        ```\n        \n    - Import gRPC to APP Gradle\n        \n        The version of gRPC in this sample is 1.4.0.\n        \n        ./Simple_gRPC/Android_gRPC_Client/build.gradle：\n        \n        \n        ```groovy\n        apply plugin: 'com.android.application'\n        apply plugin: 'com.google.protobuf'  //\u003cEdit Here\u003e\n        //\u003c!Edit Here\u003e\n        ext {\n            grpcVersion = '1.4.0'\n        }\n        //--/\u003e\n        \n        android {\n            compileSdkVersion 30\n            buildToolsVersion \"30.0.3\"\n            defaultConfig {\n                applicationId \"ntu.mil.simple_grpc\"\n                minSdkVersion 26\n                targetSdkVersion 30\n                versionCode 1\n                versionName \"1.0\"\n                testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n            }\n            buildTypes {\n                release {\n                    minifyEnabled false\n                    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n                }\n            }\n        }\n        \n        //\u003c!Edit Here\u003e\n        protobuf {\n            protoc {\n                artifact = 'com.google.protobuf:protoc:3.3.0'\n            }\n            plugins {\n                javalite {\n                    artifact = \"com.google.protobuf:protoc-gen-javalite:3.0.0\"\n                }\n                grpc {\n                    artifact = \"io.grpc:protoc-gen-grpc-java:${grpcVersion}\"\n                }\n            }\n            generateProtoTasks {\n                all().each { task -\u003e\n                    task.plugins {\n                        javalite {}\n                        grpc {\n                            option 'lite'\n                        }\n                    }\n                }\n            }\n        }\n        //--/\u003e\n        \n        dependencies {\n            implementation fileTree(dir: 'libs', include: ['*.jar'])\n            implementation 'androidx.appcompat:appcompat:1.3.1'\n            implementation 'androidx.constraintlayout:constraintlayout:2.1.1'\n            testImplementation 'junit:junit:4.12'\n            androidTestImplementation 'androidx.test.ext:junit:1.1.0'\n            androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'\n        \t\t\n        \t\t//\u003c!Edit Here\u003e\n            // For Dealing with Command\n            implementation 'com.google.code.gson:gson:2.8.5'\n        \n            //gRPC Client\n            implementation \"io.grpc:grpc-okhttp:${grpcVersion}\"\n            implementation \"io.grpc:grpc-protobuf-lite:${grpcVersion}\"\n            implementation \"io.grpc:grpc-stub:${grpcVersion}\"\n            implementation 'javax.annotation:javax.annotation-api:1.3.2'\n            protobuf 'com.google.protobuf:protobuf-java:3.3.1'\n        \t\t//--/\u003e\n        ```\n        \n    - Add Network permission \n        \n        ./Simple_gRPC/Android_gRPC_Client/src/main/AndroidManifest.xml：\n        \n        ```xml\n        \u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n        \u003cmanifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            package=\"ntu.mil.simple_grpc\"\u003e\n        \t\t\n        \t\t//\u003c!Edit Here\u003e\n            \u003cuses-permission android:name=\"android.permission.INTERNET\" /\u003e\n            //--/\u003e\n        \t\t\n        \t\t\u003capplication\n                android:allowBackup=\"true\"\n                android:icon=\"@mipmap/ic_launcher\"\n                android:label=\"@string/app_name\"\n                android:roundIcon=\"@mipmap/ic_launcher_round\"\n                android:supportsRtl=\"true\"\n                android:theme=\"@style/AppTheme\"\u003e\n                \u003cactivity android:name=\".SimpleGrpcActivity\"\u003e\n                    \u003cintent-filter\u003e\n                        \u003caction android:name=\"android.intent.action.MAIN\" /\u003e\n                        \u003ccategory android:name=\"android.intent.category.LAUNCHER\" /\u003e\n                    \u003c/intent-filter\u003e\n                \u003c/activity\u003e\n            \u003c/application\u003e\n        \n        \u003c/manifest\u003e\n        ```\n        \n    - Setup UI\n        \n        ./Simple_gRPC/Android_gRPC_Client/src/main/res (could just watch the code)\n        \n    - Setup Android gRPC Client Connection\n        \n         ./src/main/java/SimpleGrpcActivity.java (could just watch the code)\n        \n        ```java\n        public void connect(){\n                mIp = ip_1.getText().toString() + \".\"\n                        + ip_2.getText().toString() + \".\"\n                        + ip_3.getText().toString() + \".\"\n                        + ip_4.getText().toString();\n                mPort = Integer.parseInt(host_port.getText().toString());\n        \n                Log.i(TAG,\"Attempting to connect to server with ip \" + mIp);\n        \n                try {\n                    ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(mIp, mPort)\n                            .usePlaintext(true)\n                            .build();\n                    mInteracter = InteractGrpc.newBlockingStub(managedChannel);\n        \n                    String jsonHandshake = new Gson().toJson(new ServerCommand(\"Android APP\", mLocalIp.getText().toString()));\n                    ConnectRequest connectRequest = ConnectRequest.newBuilder().setStatus(jsonHandshake).build();\n                    ConnectReply connectReply = mInteracter.simpleConnect(connectRequest);\n        \n                    mConnectState = connectReply.getStatus();\n                    mTextState.setText(mConnectState);\n        \n                } catch (Exception e) {\n                    Log.e(TAG, \"connect() Fail: \" + e);\n                    mTextState.setText(\"connect() Fail: \" + e);\n                }\n            }\n        ```\n        \n    - Setup Protocol setters and getters\n        \n        ./src/main/java/ServerCommand.java (could just watch the code)\n        \n        ```java\n        public class ServerCommand {\n            private String intent;\n            private String value;\n        \n            public ServerCommand(String intent, String value){\n                this.intent = intent;\n                this.value = value;\n            }\n        \n            public String getIntent() {\n                return intent;\n            }\n        \n            public void setIntent(String intent) {\n                this.intent = intent;\n            }\n        \n            public String getValue() {\n                return value;\n            }\n        \n            public void setValue(String value) {\n                this.value = value;\n            }\n        \n            @Override\n            public String toString() {\n                return \"ServerCommand{\" +\n                        \"intent='\" + intent + '\\'' +\n                        \", value='\" + value + '\\'' +\n                        '}';\n            }\n        }\n        ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliuyuweitarek%2Fsimple_sample_grpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fliuyuweitarek%2Fsimple_sample_grpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliuyuweitarek%2Fsimple_sample_grpc/lists"}