动态功能模块的第三方库无法访问资源

时间:2020-01-23 18:37:23

标签: android android-library dynamic-feature-module

我有一个具有动态功能模块的应用程序。在动态功能模块中,有一个包含图像,输入字段的表单,并且还具有一个可以访问另一个第三方库的按钮。

第三方库具有活动和片段。在活动内部打开片段时,尽管活动布局中有容器,但我收到以下错误消息:

未找到片段SampleFragment {eed53f7(5e4c0693-09a2-4725-a6de-1df49dd818f0)id = 0x7f080053}的ID 0x7f080053(com.app.sample:id / container)的视图

访问此第三方库中的可绘制对象时,出现以下错误:

java.lang.NoSuchFieldError:类Lcom.third.library / R $ drawable中没有类型I的静态字段ic_back;或其超类(“ com.third.library.R $ drawable的声明”出现在/data/app/com.app.sample-QtC8XuamC1fHEVU4FUpWaA == / split_thirdparty.apk)

当我在没有动态功能模块的应用程序中使用此库时,这很好。 enter image description here

3 个答案:

答案 0 :(得分:3)

通常,当未在SplitCompat.installActivity(this)中调用Activity2时,此方法将无效。在没有源代码的情况下,您必须提取软件包并重新正确打包,因为Activity2(甚至整个库软件包)可能与DFM不兼容。

为基本应用程序启用SplitCompat后,您需要为应用程序在动态功能模块中下载的每个活动启用SplitCompat

这是我的另一个answer,它通过反射演示了访问。

答案 1 :(得分:0)

动态传递是一个相对较新的功能,因此有很多限制。这些限制之一是您不能以常规方式访问动态模块的代码和资源,因此它不能成为其他模块的依赖项。当前,您可以通过反射访问动态模块,并通过公共库模块中的公共接口定义动态功能,并在运行时使用ServiceLoader加载其实际实现(位于动态功能模块中)。它具有性能方面的缺点。可以使用ServiceLoaderRewriter使用R8将其最小化,但不能完全删除。

尽管反射很容易出错,我们可以使用@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)
    }
}

要真正访问动态功能的代码,请使用


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
    }
}

取自here。另外还有很多信息,所以我建议您检查一下。

通常,我只是不建议使用动态功能作为依赖项并相应地计划您的应用程序体系结构。

希望有帮助。

答案 2 :(得分:0)

对于资源,此代码部分可以用作用法

R.id.settings将是:

getResources().getIdentifier("settings", "id", "com.library.package");
相关问题