Sharing code between iOS and Android using Bazel and j2objc

333 Views Asked by At

I have a library with common code which uses android.util.Log:

java_library(
    name = "common",
    srcs = glob(["*.java"]),
)

And I have an j2objc rule for iOS which works just fine:

j2objc_library(
    name = "common_ios",
    deps = ["//common"],
    jre_deps = ["@bazel_j2objc//:android_util_lib"],
)

But when I use common in my Android project:

android_binary(
    name = "app",
    srcs = glob(["*.java"]),
    manifest = "//android:manifest",
    resource_files = ["//android:resources"],
    deps = ["//common"],
)

But when I run bazel build //android:app, I get:

common/MyVeryOwnLogger.java:3: error: package android.util does not exist
import android.util.Log;

Which makes sense, as android.* libs should not be available in a java_library rule. Am I missing something? Is this not the recommended way to setup a project?

Thanks!

1

There are 1 best solutions below

6
ahumesky On

A java_library won't be able to compile code that depends on Android because it won't have any of the Android dependencies that android_library provides.

Have you tried running your iOS app with a dependency on common that uses Android classes? I'm a little surprised that that works.

In any case, I recommend moving things that are platform dependent out of common and into platform-specific rules.

So, for example, say you have some kind of business logic Model class in common that requires a logger, create some interface like Logger in common, and have Model take an instance of Logger. Then you can have an android_library rule that depends on common and provides an implementation of Logger for Android that uses all the classes in android.util.*. Then your android_binary rule depends on both common and the android_library. In your app code, you can then instantiate an instance of the Android-specific logger and pass that to Model.

For the iOS half of things, you can similarly have an objective-c rule that provides iOS-specific logging (though I'm less familiar with how all that would work in objective-c or iOS).

You might also consider breaking up common into separate rules, which will improve incrementality (e.g. putting logging into its own rule). This all depends on the structure of your code.