Сторонняя библиотека динамического c функционального модуля не может получить доступ к ресурсам - PullRequest
1 голос
/ 23 января 2020

У меня есть приложение с динамическим c функциональным модулем. В функциональном модуле Dynami c есть форма с изображениями, полями ввода, а также кнопка для доступа к другой сторонней библиотеке.

Сторонняя библиотека имеет активность и фрагмент. При открытии фрагмента внутри действия я получаю сообщение об ошибке ниже, хотя в макете действия есть контейнер:

Не найдено представление для идентификатора 0x7f080053 (com.app.sample: id / container) для фрагмента SampleFragment { eed53f7 (5e4c0693-09a2-4725-a6de-1df49dd818f0) id = 0x7f080053}

При доступе к чертежам в этой сторонней библиотеке, ошибка ниже:

java .lang.NoSuchFieldError: Нет данных c поле ic_back типа I в классе Lcom.third.library / R $ drawable; или его суперклассы (объявление 'com.third.library.R $ drawable' появляется в /data/app/com.app.sample-QtC8XuamC1fHEVU4FUpWaA==/split_thirdparty.apk)

Это нормально когда я использую эту библиотеку в приложении без динамического c функционального модуля. enter image description here

Ответы [ 3 ]

3 голосов
/ 31 января 2020

Как правило, когда SplitCompat.installActivity(this) не вызывается в Activity2, это не будет работать. Не имея исходного кода, вам придется извлечь пакет и правильно упаковать его, поскольку Activity2 (или даже весь пакет библиотеки), скорее всего, не совместим с DFM.

После включения SplitCompat для базового приложения вам необходимо включить SplitCompat для каждого действия , которое ваше приложение загружает в динамический c функциональный модуль.

Вот еще один ответ моего, который демонстрирует доступ через отражение.

0 голосов
/ 31 января 2020

Для ресурсов эта часть кода может быть использована

R.id.settings будет:

getResources().getIdentifier("settings", "id", "com.library.package");
0 голосов
/ 31 января 2020

Dynami c Доставка является относительно новой функцией, поэтому она имеет множество ограничений. Одно из этих ограничений заключается в том, что вы не можете получить доступ к коду и ресурсам модуля Dynami c обычным способом, поэтому он не может быть зависимостью для других модулей. В настоящее время вы можете получить доступ к модулю Dynami c с помощью отражения и иметь функции Dynami c, определенные через интерфейсы publi c в модуле общей библиотеки, и загружать их фактические реализации (расположенные в функциональных модулях Dynami c) во время выполнения с помощью ServiceLoader. У него есть свои минусы производительности. Их можно свернуть с помощью R8, используя ServiceLoaderRewriter, но не полностью удалить.

Хотя использование отражения очень подвержено ошибкам, мы можем минимизировать его либо с помощью @AutoService - AutoService - это процессор аннотаций, который будет сканировать проект на наличие классов, помеченных @AutoService, для любого найденного им класса он автоматически создаст для него файл определения сервиса.

Вот небольшой пример того, как он выполнено

// All feature definitions extend this interface, T is the dependencies that the feature requires
interface Feature<T> {
    fun getMainScreen(): Fragment
    fun getLaunchIntent(context: Context): Intent
    fun inject(dependencies: T)
}

interface VideoFeature : Feature<VideoFeature.Dependencies> {
    interface Dependencies {
        val okHttpClient: OkHttpClient
        val context: Context
        val handler: Handler
        val backgroundDispatcher: CoroutineDispatcher
    }
}

internal var videoComponent: VideoComponent? = null
    private set

@AutoService(VideoFeature::class)
class VideoFeatureImpl : VideoFeature {
    override fun getLaunchIntent(context: Context): Intent = Intent(context, VideoActivity::class.java)

    override fun getMainScreen(): Fragment = createVideoFragment()

    override fun inject(dependencies: VideoFeature.Dependencies) {
        if (videoComponent != null) {
            return
        }

        videoComponent = DaggerVideoComponent.factory()
                .create(dependencies, this)
    }
}

И для фактического доступа к коду Dynami c Использование функции


inline fun <reified T : Feature<D>, D> FeatureManager.getFeature(
        dependencies: D
): T? {
    return if (isFeatureInstalled<T>()) {
        val serviceIterator = ServiceLoader.load(
                T::class.java,
                T::class.java.classLoader
        ).iterator()

        if (serviceIterator.hasNext()) {
            val feature = serviceIterator.next()
            feature.apply { inject(dependencies) }
        } else {
            null
        }
    } else {
        null
    }
}

Взято из здесь . Также там гораздо больше информации, поэтому я бы порекомендовал вам проверить ее.

Как правило, я просто не рекомендовал бы использовать Dynami c Feature в качестве зависимости и соответственно планировать архитектуру вашего приложения.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...