© P.J. McNerney 2020
P. McNerneyBeginning Bazelhttps://doi.org/10.1007/978-1-4842-5194-2_9

9. Bazel and Android

P. J. McNerney1 
(1)
Blackhawk, CO, USA
 

In the prior chapters, you used Bazel to develop functionality that would most likely be deployed to some backend server. However, Bazel can be (and is) used for more than just backend projects, able to handle mobile clients as well. In this chapter, we will explore using Bazel to build Android applications.

Setup

As previously, we will be building off of our prior chapters. Again, first verify that all of the Bazel-generated files are eliminated. Then, copy the work from the last chapter:
$ cd chapter_08
chapter_08$ bazel clean
chapter_08$ ls
WORKSPACE   client    proto   server
chapter_08$ cd ..
$ cp -rf chapter_08 chapter_09
$ cd chapter_09
chapter_09$

Workspace

As you might have already guessed, we need to augment our WORKSPACE file with an additional dependency. In this case, we are specifying the rules for building an Android project.

Open the WORKSPACE file and add the following.
<existing content omitted for brevity>
http_archive(
    name = "rules_android",
    urls = ["https://github.com/bazelbuild/rules_android/archive/v0.1.1.zip"],
    strip_prefix = "rules_android-0.1.1",
)
android_sdk_repository(name = "androidsdk")
Listing 9-1

Modifying the WORKSPACE file for the Android rules

Note

In earlier chapters, we mentioned that there are certain rules that you get out of the box (e.g., java_library, cc_library, etc.). The rules for android_library and android_binary technically started as more out-of-the-box rules. However, as Bazel has matured, they have begun removing rules from this core set and creating explicit packages for these rules, for the sake of maintainability.

This should make sense from a development perspective; by making the rules more modular and less part of a monolithic package, they can be revised at their appropriate pace without requiring a rebuild of the entire Bazel system.

Within the WORKSPACE file, we are calling a rule android_sdk_repository. This is used to specify the path to the Android SDK with respect to this project. In this particular case, without any other additional specification within the rule itself, the rule defaults to using the ANDROID_HOME environment variable. We will set this shortly.

Note

The reliance on an environment variable in this case might set off some alarms, given Bazel’s approach to maintaining control over its dependencies. In this particular case, the environment variable may be considered a convenience; however, it is possible to specify an explicit path to the Android SDKs, even relative to your current WORKSPACE file, within the android_sdk_repository rule.

This kind of specification is highly useful when you are checking Android SDK dependencies into source control. This once again returns Bazel to the type of hermetic build that it prefers.

Android Studio

In the course of this chapter, we are downloading Android Studio for the purpose of giving us an easy Android emulator on which to run our work as well as create a convenient location for the Android SDKs. Technically speaking, you can actually use the work you’ve done with Bazel to drive an Android Studio (and IntelliJ) project (akin to using something gradle). However, this integration is outside of the scope of this chapter of this book.

Note

To that end, you might either have a favorite Android emulator you prefer instead or want to just hook up your Android device to the computer to try this out. In these cases, you can largely skip using Android Studio (though please take particular care to make sure you have the Android SDKs you need as specified under the upcoming Environment section).

Go to https://developer.android.com/studio and follow the instructions for downloading and installing Android Studio on your particular platform.

The version of Android Studio used for the examples in this book is 3.4.2. Later versions may have visual changes, so the screenshots may not line up precisely.

Environment

As indicated previously, we need to set the ANDROID_HOME environment variable in order to ensure that Bazel knows where to find the Android SDKs. Make sure to set your ANDROID_HOME variable in your environment with the value pointing to the location of the Android SDK on your machine.

The default locations for the Android SDKs from Android Studio depends on the particular OS. Set the environment variables as appropriate to your system:

For Linux:
export ANDROID_HOME=$HOME/Android/Sdk/
For MacOS:
export ANDROID_HOME=$HOME/Library/Android/sdk
For Windows:
set ANDROID_HOME=%LOCALAPPDATA%AndroidSdk

One thing to note is that the preceding commands will only set the environment variable for the lifetime of your particular console session. You may want to consider making these a part of the default profile for your particular console and OS.

Additionally, the preceding values are only the default locations for the SDK; it is possible that during the course of installation of Android Studio, you may have installed into a different location. In order to find that location, open the SDK Manager in Android Studio.
../images/481224_1_En_9_Chapter/481224_1_En_9_Fig1_HTML.jpg
Figure 9-1

Starting the SDK Manager in Android Studio

Within the SDK Manager, you will be able to find the location of the Android SDK. Use that value to set the value of the ANDROID_HOME environment variable.
../images/481224_1_En_9_Chapter/481224_1_En_9_Fig2_HTML.jpg
Figure 9-2

Verifying the location of the Android SDK

Downloading SDKs

While we have the SDK Manager up and running, we should also ensure that we have at least one Android SDK to begin development. Select at least Android 8.1 (Oreo) (i.e., API Level 27) and then click OK to begin downloading the SDKs (if you have selected more than one).
../images/481224_1_En_9_Chapter/481224_1_En_9_Fig3_HTML.jpg
Figure 9-3

Selecting versions of the Android SDK to download

Once you’ve downloaded the SDK(s), click Finish.
../images/481224_1_En_9_Chapter/481224_1_En_9_Fig4_HTML.jpg
Figure 9-4

Downloading the Android SDKs

Creating the Emulator

Finally, let’s create an instance of the Android Emulator. From the main screen, open the AVD Manager.
../images/481224_1_En_9_Chapter/481224_1_En_9_Fig5_HTML.jpg
Figure 9-5

Starting the AVD Manager in Android Studio

At this point, we don’t have any emulator profiles, so let’s create one by clicking Create Virtual Device.
../images/481224_1_En_9_Chapter/481224_1_En_9_Fig6_HTML.jpg
Figure 9-6

Creating a virtual device

From the Select Hardware screen, select a device (e.g., Pixel 2) from the Phone category and then click Next.
../images/481224_1_En_9_Chapter/481224_1_En_9_Fig7_HTML.jpg
Figure 9-7

Selecting a particular device

From the System Image screen, select the particular version (e.g., Oreo) of the Android SDK that you want to use and then click Next.
../images/481224_1_En_9_Chapter/481224_1_En_9_Fig8_HTML.jpg
Figure 9-8

Selecting the version of the Android SDK

Finally, you can give your particular emulation profile a name (if you would like). Click Finish to complete the creation of your virtual device.
../images/481224_1_En_9_Chapter/481224_1_En_9_Fig9_HTML.jpg
Figure 9-9

Naming and completing the virtual device

Creating the Android Echo Client in Bazel

Having done all the preparation, we are now ready to start actually creating our Android application. In this case, we are going to create a mobile version of our echo client.

However, before we get to the actual gRPC code, we’ll start with a simple shell version that just echoes locally (i.e., input text returns immediately). This is simply to get used to the basics of developing an Android application in Bazel.

Let’s create a new directory for our Android work:
chapter_09$ cd client/echo_client/
chapter_09/client/echo_client$ mkdir android
chapter_09/client/echo_client$ cd android
chapter_09/client/echo_client/android$
Within the client/echo_client/android directory, create the EchoClientMainActivity.java file and add the following.
package client.echo_client.android;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class EchoClientMainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.echo_client_main_activity);
        Button textSenderButton = findViewById(R.id.text_sender);
        EditText clientTextEditor = findViewById(R.id.text_input);
        TextView serverResultsText = findViewById(R.id.server_result_text);
        textSenderButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                 serverResultsText.setText(clientTextEditor.getText().toString());
           }});
   }
}
Listing 9-2

Creating a basic Android echo client

Save the file to EchoClientMainActivity.java. As evidenced in the preceding code, we are creating a simple text editor to input text; upon the push of the button, the text is then reflected in a text view.

Now let’s create the layout file that actually creates the UI:
chapter_09/client/echo_client/android$ mkdir -p res/layout
Create the following file under client/echo_client/android/res/layout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:gravity="top"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
   <EditText
     android:id="@+id/text_input"
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
     android:inputType="text"/>
  <Button
      android:id="@+id/text_sender"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="center_horizontal"
      android:text="Send to Server"/>
  <TextView
      android:id="@+id/server_result_text"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="center_horizontal"
      android:inputType="textMultiLine"
      android:text="Result text here"/>
</LinearLayout>
Listing 9-3

Creating the layout file

Save the file to echo_client_main_activity.xml under client/echo_client/android/res/layout.

For our Android app, we also need an AndroidManifest.xml file.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="client.echo_client.android"
    android:versionCode="1"
    android:versionName="1.0" >
  <uses-sdk
      android:minSdkVersion="19"
      android:targetSdkVersion="27" />
  <application
    android:label="Beginning Bazel Android Echo Client">
    <activity
        android:name=".EchoClientMainActivity"
        android:label="Beginning Bazel Android Echo Client" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
  </application>
</manifest>
Listing 9-4

AndroidManifest.xml

Save this to client/echo_client/android/AndroidManifest.xml.

Finally, let’s create our BUILD file and define our targets.
load("@rules_android//android:rules.bzl", "android_library", "android_binary")
android_library(
    name = "echo_client_android_activity",
    srcs = ["EchoClientMainActivity.java"],
    manifest = "AndroidManifest.xml",
    custom_package = "client.echo_client.android",
    resource_files = [
        "res/layout/echo_client_main_activity.xml"
    ],
)
android_binary(
    name = "echo_client_android_app",
    manifest = "AndroidManifest.xml",
    custom_package = "client.echo_client.android",
    deps = [ ":echo_client_android_activity",],
)
Listing 9-5

Creating the BUILD file for the Android client

Save this to client/echo_client/android/BUILD.

Although the Android build rules are new, you have seen this pattern several times throughout this book. As expected, we needed to explicitly load the android_library and android_binary rules from the rules_android package.

For the each of the rules, there are a number of attributes that are familiar (i.e., name, srcs, dep). There are a few attributes worth highlighting:
  • manifest
    • Points at the AndroidManifest.xml file.

    • Required for both android_library and android_binary.

  • resource_files
    • Contains the set of Android resource files (e.g., layout.xml, strings.xml, etc.).

    • Strictly speaking, this is optional; however, in this particular example, removing this attribute here will cause the build to fail (since it no longer depends upon the files required for the generated classes).

  • custom_package
    • This explicitly specifies the package used by the app.

    • Both android_library and android_binary have an expectation about the directory structure.

    • Specifically, they expect that the directory starts with either java or javatests as a way of inferring the Java package.

    • If the directory does not start with java, then it is necessary to explicitly set the custom_package attribute.

Now, technically speaking, we did not strictly need to have both an android_library instance and an android_binary instance. The android_binary rule actually has a sufficient set of options that we could have put everything (i.e., Java sources and resource files) we needed there. However, the separation here is intended to illustrate both rules.

Let’s run a test build to make sure that everything is working as intended. For the sake of simplicity, we will just build the final binary:
chapter_09/client/echo_client/android$ bazel build :echo_client_android_app
INFO: Analyzed target //client/echo_client/android:echo_client_android_app (1 packages loaded, 5 targets configured).
INFO: Found 1 target...
Target //client/echo_client/android:echo_client_android_app up-to-date:
  bazel-bin/client/echo_client/android/echo_client_android_app_deploy.jar
  bazel-bin/client/echo_client/android/echo_client_android_app_unsigned.apk
  bazel-bin/client/echo_client/android/echo_client_android_app.apk
INFO: Elapsed time: 0.935s, Critical Path: 0.70s
INFO: 3 processes: 3 darwin-sandbox.
INFO: Build completed successfully, 4 total actions

Congratulations! You have built your first Android application using Bazel. We are now ready to test it out on the emulator.

Starting Up the Android Emulator Instance

Having previously created your virtual device, you can now start it up. Open the AVD Manager, which will now have a listing of all your virtual devices (in this example, there is only one). Click the “play” button to start up an instance of your virtual device.
../images/481224_1_En_9_Chapter/481224_1_En_9_Fig10_HTML.jpg
Figure 9-10

Starting the virtual device

You should see a blank screen as follows.
../images/481224_1_En_9_Chapter/481224_1_En_9_Fig11_HTML.jpg
Figure 9-11

Emulator after start-up

Bazel Mobile Install

Having built and set up our emulator, we are now ready to deploy our application. On first blush, we could make use of the Android Debug Bridge (ADB) commands to get our application onto the emulator. However, Bazel provides a very useful command mobile-install. In a similar fashion to run, mobile-install builds the target application and then installs onto the connected device (in this case, the emulator).

As an added bonus, we can also add the option start_app in order to immediately start the app as soon as it is installed. Using this option makes mobile-install a functional mobile equivalent to run used in prior chapters.

Run the following command to build, deploy, and start the application:
chapter_09/client/echo_client/android$ bazel mobile-install --start_app :echo_client_android_app
../images/481224_1_En_9_Chapter/481224_1_En_9_Fig12_HTML.jpg
Figure 9-12

Initial screen of the app

Congratulations! Your application is alive and will locally echo whatever you write into the text editor.

Note

The mobile-install command is not just a convenient proxy for the ADB functionality. Since it is tied into the Bazel build system, it can also be used for deploying incremental changes to your mobile applications. This can greatly improve your development times, allowing you to take a more iterative approach to working on various aspects of the mobile application (e.g., the UI). However, the particulars around using this incremental deployment are outside of the scope of this book.

Adding gRPC Support

While the prior example was useful for creating a basic Android application, it is not a very functional app. Carrying over our theme from prior chapters, let’s now add the real echo client functionality to this application. Fortunately, you have already done the heavy lifting in prior chapters; we get to reuse that here.

Before we jump into the Android code itself, we have to first make sure we add the appropriate permission; otherwise, we will get errors when we attempt to perform interprocess communication.

Open the AndroidManifest.xml file and add the following permission.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="client.echo_client.android"
    android:versionCode="1"
    android:versionName="1.0" >
  <uses-sdk
      android:minSdkVersion="19"
      android:targetSdkVersion="27" />
  <uses-permission android:name="android.permission.INTERNET"/>
  <application
    android:label="Beginning Bazel Android Echo Client">
    <activity
        android:name=".EchoClientMainActivity"
        android:label="Beginning Bazel Android Echo Client" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
  </application>
</manifest>
Listing 9-6

Adding permission to access networking to the Android app

Save the changes to AndroidManifest.xml.

Now let’s make the necessary changes to the Android code itself. Open the EchoClientMainActivity.java file and add the following changes in bold.
package java.com.beginning_bazel.client.echo_client;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import transmission_object.TransmissionObjectOuterClass.TransmissionObject;
import transceiver.TransceiverOuterClass.EchoRequest;
import transceiver.TransceiverOuterClass.EchoResponse;
import transceiver.TransceiverGrpc;
public class EchoClientMainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.echo_client_main_activity);
        Button textSenderButton = findViewById(R.id.text_sender);
        EditText clientTextEditor = findViewById(R.id.text_input);
        TextView serverResultsText = findViewById(R.id.server_result_text);
        textSenderButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                final String clientText =
                   clientTextEditor.getText().toString();
                if (!clientText.isEmpty()) {
                    ManagedChannel channel =
                      ManagedChannelBuilder
                          .forAddress("10.0.2.2", 1234)
                          .usePlaintext()
                          .build();
                    TransceiverGrpc.TransceiverBlockingStub stub =
                       TransceiverGrpc.newBlockingStub(channel);
                    EchoRequest request = EchoRequest.newBuilder()
                      .setFromClient(
                         TransmissionObject.newBuilder()
                            .setMessage(clientText)
                            .setValue(3.145f)
                            .build();
                      .build();
                    try {
                        EchoResponse response = stub.echo(request);
                        serverResultsText.setText(response.toString());
                    } catch (Throwable t) {
                        Log.d("EchoClientMainActivity", "error:", t);
                    } finally {
                        channel.shutdown();
                    }
                }
            }});
    }
}
Listing 9-7

Modifying the Android client to support gRPC

Save the changes to EchoClientMainActivity.java .

Note

A careful reader will note that we have changed the address from localhost to 10.0.2.2. Within the emulator localhost refers to the emulated device, rather than the machine the emulator is running on. Android Studio designates a special IP address (i.e., 10.0.2.2) in order to connect to processes running on your development machine. You don’t need to change anything on the server side.

Should one decide to use a different emulation platform, please consult with that platform’s documentation to see if it designates a different address (or uses a different strategy) in order to connect to processes running on your development machine.

All of the added code should look familiar to you; with only a couple of changes, it is identical to the code on the command line Java client from the previous chapter.

Note

In both the last chapter and this one, we are making use of the blocking stub version for calling into the backend. Although convenient for us here, in general, you would not want to make such an I/O call on a UI thread, since such a call could make the UI unresponsive. Instead, you likely would want to investigate some of the other generated versions (e.g., using a Future) of this call as a best fit for your application.

Finally, let’s add the necessary dependencies to the BUILD file. Once again, this should look very familiar to you, with few changes from the prior chapter.
load("@rules_android//android:rules.bzl", "android_library", "android_binary")
android_library(
    name = "echo_client_android_activity",
    srcs = ["EchoClientMainActivity.java"],
    manifest = "AndroidManifest.xml",
    custom_package = "client.echo_client.android",
    resource_files = [
        "res/layout/echo_client_main_activity.xml"
    ],
    deps = [
        "//proto:transceiver_java_proto",
        "//proto:transceiver_java_proto_grpc",
        "//proto:transmission_object_java_proto",
        "@io_grpc_grpc_java//api",
        "@io_grpc_grpc_java//okhttp",
        "@io_grpc_grpc_java//stub",
    ],
)
android_binary(
    name = "echo_client_android_app",
    manifest = "AndroidManifest.xml",
    deps = [ ":echo_client_android_activity",],
)
Listing 9-8

Adding dependencies into the Android BUILD file

Note

Once again, an astute reader will see that we have replaced our former @io_grpc_grpc_java//netty runtime dependency with the @io_grpc_grpc_java/okhttp static dependency. To be sure, netty is most appropriate for supporting both client and server functionality. OkHttp is designed to be lightweight for client-only, hence its inclusion into Android here.

Save the changes to the BUILD file.

For sanity’s sake, let’s build the app once more. However, you might get a surprising error message this time.
chapter_09/client/echo_client/android$ bazel build :echo_client_android_app
ERROR: <stack trace>
'single_file' is no longer supported. use allow_single_file instead. You can use --incompatible_disable_deprecated_attr_params=false to temporarily disable this check.
ERROR: <file_path>/external/io_grpc_grpc_java/protobuf-lite/BUILD.bazel:1:1: error loading package '@com_google_protobuf_javalite//': Extension file 'protobuf.bzl' has errors and referenced by '@io_grpc_grpc_java//protobuf-lite:protobuf-lite'
ERROR: Analysis of target '//client/echo_client/android:echo_client_android_app' failed; build aborted: error loading package '@com_google_protobuf_javalite//': Extension file 'protobuf.bzl' has errors

In this particular case, you haven’t done anything wrong; you might have run into this error due to the evolving nature of Bazel. In this case, one of your dependencies has an error due to a deprecated attribute. All is not lost, however, and the highlighted line above gives us an answer as to how to proceed.

If we add in the flag –-incompatible_disable_deprecated_attr_params=false to the build (and mobile-install) command, you can see the issue correct itself.

chapter_09/client/echo_client/android$ bazel build –-incompatible_disable_deprecated_attr_params=false :echo_client_android_app
INFO: Writing tracer profile to '/private/var/tmp/_bazel_pj/72676801ec24996691dac393febb05db/command.profile.gz'
INFO: Analyzed target //client/echo_client/android:echo_client_android_app (80 packages loaded, 2140 targets configured).
INFO: Found 1 target...
Target //client/echo_client/android:echo_client_android_app up-to-date:
  bazel-bin/client/echo_client/android/echo_client_android_app_deploy.jar
  bazel-bin/client/echo_client/android/echo_client_android_app_unsigned.apk
  bazel-bin/client/echo_client/android/echo_client_android_app.apk
INFO: Elapsed time: 11.048s, Critical Path: 6.06s
INFO: 13 processes: 9 darwin-sandbox, 4 worker.
INFO: Build completed successfully, 14 total actions

Strictly speaking, although this works, this should not be considered a permanent solution. When you actually encounter something like this, the correct solution will be to fix the problem in the dependency (possibly submitting a change for it). This also illustrates the advantage of keeping your advantages as local as possible, to make it easier to control your own destiny.

One thing this does illustrate, however, is that Bazel, even in its own rapid evolution, seeks to provide you with “escape valves” to keep development moving forward. While not permanent solutions, these do enable you to more easily transition between versions of the software.

Running the Android Client Against the Backend

Having augmented our Android client to make RPCs against a local server, let’s now start both the server and the client up.

Previously, you needed two console instances, since your client and server were both command line tools. Here, you will be able to use just one.

First, let’s build, deploy, and start our updated Android app. Run the following command:
bazel mobile-install --incompatible_disable_deprecated_attr_params=false --start_app :echo_client_android_app
After confirming that the application is up and running, run the following command to start the server:
chapter_09$ bazel run server/echo_server
INFO: Deleting stale sandbox base /private/var/tmp/_bazel_pj/72676801ec24996691dac393febb05db/sandbox
Target //server/echo_server:echo_server up-to-date:
  bazel-bin/server/echo_server/darwin_amd64_stripped/echo_server
INFO: Elapsed time: 16.670s, Critical Path: 0.30s
INFO: 0 processes.
INFO: Build completed successfully, 1 total action
INFO: Build completed successfully, 1 total action
2019/08/01 16:39:03 Spinning up the Echo Server in Go
Now, write up some text and click “Send to Server.” You should get a response in your Android client, as follows.
../images/481224_1_En_9_Chapter/481224_1_En_9_Fig13_HTML.jpg
Figure 9-13

Screen showcasing the app with displayed response from the backend

Congratulations! You have created your Android echo client, communicating with the local echo server.

Final Word

Over the course of the latest chapter, you augmented your knowledge by learning how to build Android applications using Bazel. Furthermore, you were able to take what you have learned in earlier chapters to create an application that communicated with the work you’ve done previously. Although this is clearly a toy example of remote communication, it serves as a seed for larger projects.

Having demonstrated Bazel’s ability to work with building Android project, we will expand in the next chapter to also work on iOS applications.

Exercise – Using Java Lite Protos On Android

Over the course of the last chapter, you were able to make use of your work from earlier chapters to easily add gRPC support to your Android application. One note that was glossed over during the course of this work is that the output of the java_proto_library tends to be rather verbose in terms of sheer number of functions; that is, the number of generated classes, inner classes, static classes, and so on tends to be large. While this is less of an issue for programs that run on servers, this actually starts to become an issue at scale for Android programs. Veterans of writing Android programs are familiar with the dreaded function count within a single DEX file (i.e., 64K functions).

Although you can adopt a multidex strategy to handle this increased number of functions, this can become complicated depending on the version of the Android SDK. Fortunately, at least in the case of the java_proto_library, we have a viable alternative in the java_lite_proto_library. This rule produces proto Java code that has fewer overall features, while still retaining the core functionality that is used most of the time.

Notably, the java_lite_proto_library is (currently) one of those out-of-the-box rules which also requires some outside support (which might give an indication about the migration path for this particular set of rules). The rule is specified nearly identically to the java_proto_library. Protos generated from java_lite_proto_library do not implement all of the functionality of the original version but can be often used as drop-in replacements for the most common use cases (as is the case here).

Fortunately, you can easily get the support you need by adding the following lines to your WORKSPACE file:
http_archive(
    name = "com_google_protobuf_javalite",
    strip_prefix = "protobuf-javalite",
    urls = ["https://github.com/google/protobuf/archive/javalite.zip"],
)

To that end, you will also need to ensure that the grpc library that you are using also produces code that is compatible with the output of the java_lite_proto_library. Fortunately, our existing rule of java_grpc_library already handles this for us; all you need to do is to add the option flavor = "lite" to the application.

For example:
java_grpc_library(
    name = "transceiver_java_lite_proto_grpc",
    srcs = [":transceiver_proto"],
    deps = [":transceiver_java_lite_proto"],
    flavor = "lite",
    visibility = ["//client/echo_client:__subpackages__"],
)

Once you’ve created your java_lite_proto_library and java_grpc_library (with “lite” proto support) instances, redirect your app’s android_library to point at these newly created rules. The way we are using protobufs in this instance means you don’t have to change any of your Android code. You should be able to build and run the code, with no functional change.

However, you should look at the size of your app before/after this change. You should see a significant reduction in size (and if you really want to know the difference, use Android Studio’s profiling tool to see the difference in the number of functions).

For toy projects, this difference will not amount to much; however, as you grow your Android apps to significant sizes using protobufs, you will want to make use of the “lite” versions to help keep your application sizes small and avoid the use of multidex.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.249.90