Совместное использование кода между iOS и Android с использованием Bazel и j2objc

У меня есть библиотека с общим кодом, который использует android.util.Log:

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

И у меня есть правило j2objc для iOS, которое отлично работает:

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

Но когда я использую common в своем проекте Android:

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

Но когда я запускаю bazel build //android:app, я получаю:

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

Что имеет смысл, так как android.* библиотеки не должны быть доступны в правиле java_library. Я что-то упускаю? Разве это не рекомендуемый способ настройки проекта?

Спасибо!


person Vitor Pereira    schedule 07.06.2018    source источник
comment
вы можете предоставить собственную android.util.Log реализацию или удалить MyVeryOwnLogger реализацию из общей   -  person Selvin    schedule 07.06.2018
comment
@Selvin, конечно, но тогда я не использую код повторно. Идея состоит в том, чтобы использовать библиотеку android_util в iOS и нативный пакет android.util в Android.   -  person Vitor Pereira    schedule 07.06.2018
comment
Я бы 1. создал java_library с именем android_util с одним файлом android/util/Log.java 2. добавил его как deps (deps = ["//common", "android_util"]) в common_ios...   -  person Selvin    schedule 07.06.2018
comment
Код iOS работает по назначению. Я, наверное, недостаточно ясно выразился. Вы можете видеть, что это зависит от //common, но также и от android_util_lib для ведения журнала. Проблема в том, что на Android правило //common не может найти классы android.*, хотя от него зависит правило android_binary. Это заставляет меня думать, что моя настройка bazel не соответствует правильной практике. РЕДАКТИРОВАТЬ: добавлена ​​команда bazel, которая выдает ошибку.   -  person Vitor Pereira    schedule 07.06.2018


Ответы (1)


java_library не сможет скомпилировать код, зависящий от Android, потому что у него не будет ни одной из зависимостей Android, предоставляемых android_library.

Пробовали ли вы запускать приложение для iOS с зависимостью от common, которая использует классы Android? Я немного удивлен, что это работает.

В любом случае, я рекомендую переместить вещи, зависящие от платформы, из common в правила для конкретной платформы.

Так, например, скажем, у вас есть какой-то класс бизнес-логики Model в common, для которого требуется регистратор, создайте некоторый интерфейс, такой как Logger в common, и Model возьмите экземпляр Logger. Тогда у вас может быть правило android_library, которое зависит от common и предоставляет реализацию Logger для Android, которая использует все классы в android.util.*. Тогда ваше правило android_binary зависит как от common, так и от android_library. Затем в коде приложения вы можете создать экземпляр регистратора для Android и передать его в Model.

Для половины вещей iOS вы можете аналогичным образом иметь правило target-c, которое обеспечивает ведение журнала для iOS (хотя я менее знаком с тем, как все это будет работать в Objective-C или iOS).

Вы также можете рассмотреть возможность разделения common на отдельные правила, что улучшит инкрементальность (например, поместить ведение журнала в отдельное правило). Все зависит от структуры вашего кода.

person ahumesky    schedule 07.06.2018
comment
Правило j2objc_library зависит от @bazel_j2objc//:android_util_lib, который является реализацией нескольких полезных классов android.*, предоставляемых j2objc (см. ="nofollow noreferrer">developers.google.com/j2objc/guides/). На стороне Android, очевидно, нет необходимости в такой повторной реализации, поскольку во время выполнения доступны все эти классы. Так что проблема скорее в том, как мне сказать об этом Базелю. - person Vitor Pereira; 07.06.2018
comment
Спасибо за указатель, я удалю этот бит из своего ответа, так как он не имеет значения. Я думаю, что чистое решение для компиляции java_library по-прежнему состоит в том, чтобы разделить его на отдельные компоненты с частями Android в android_library. java_library сам по себе не сможет скомпилировать код Android. Тем не менее, можно напрямую зависеть от android.jar, используя, например. @androidsdk//:platforms/android-25/android.jar, однако это не будет синхронизировано с флагом --android_sdk. - person ahumesky; 08.06.2018
comment
Однако вы можете использовать недокументированное правило, которое учитывает --android_sdk: ``` java_import( name = android_jar, jars = [:android_tools_defaults_jar], neverlink = True, ) android_tools_defaults_jar( name = android_tools_defaults_jar )``` - person ahumesky; 08.06.2018
comment
android_tools_defaults_jar недокументирован главным образом потому, что он используется только для внутренних целей, и мы, возможно, однажды захотим избавиться от него и заменить его соответствующим набором config_settings + selects, но, насколько я знаю, у нас нет ближайших планов сделать это. - person ahumesky; 08.06.2018
comment
Кроме того, в любом случае вы захотите использовать java_import с neverlink = True, чтобы ваш код скомпилировался только для классов в банке, и они никуда не попали. - person ahumesky; 08.06.2018
comment
Я бы все же предпочел не зависеть от внутренних API. Том Болл из j2objc предложил, чтобы тип правила зависел от того, какая цель создается. Либо поместите мой код в android_library, либо в java_library + j2objc_library. Это то, что я в итоге сделал, и пока все работает нормально. Кстати, спасибо, что рассказали мне о neverlink! - person Vitor Pereira; 08.06.2018