2

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

第三方库有一个activity和fragment。在活动中打开片段时,我收到以下错误,尽管活动的布局中有容器:

未找到片段 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 中)

当我在没有动态功能模块的应用程序中使用这个库时很好。 在此处输入图像描述

4

3 回答 3

3

通常,当SplitCompat.installActivity(this)不调用时Activity2,这将不起作用。虽然没有源代码,但您必须提取包并正确重新打包,因为Activity2(甚至整个库包)可能与 DFM 不兼容。

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

这是我的另一个答案,它演示了通过反射进行访问。

于 2020-01-31T13:25:02.593 回答
0

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

R.id.settings将会:

getResources().getIdentifier("settings", "id", "com.library.package");
于 2020-01-31T13:42:02.193 回答
0

动态交付是相对较新的功能,因此它有很多限制。其中一个限制是您无法以常规方式访问动态模块的代码和资源,因此它不能成为其他模块的依赖项。目前,您可以通过反射访问动态模块,并通过公共库模块中的公共接口定义动态功能,并在运行时使用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)
    }
}

并实际访问动态功能使用的代码


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

取自这里。那里还有更多信息,所以我建议您检查一下。

一般来说,我只是不建议使用动态功能作为依赖项并相应地规划您的应用程序架构。

希望能帮助到你。

于 2020-01-31T12:30:43.713 回答