Android 动态功能模块的第三方库无法访问资源
我有一个应用程序,它有一个动态功能模块。在动态特征模块中,有一个包含图像、输入字段的表单,还有一个访问另一个第三方库的Button 第三方库有一个活动和片段。在活动内部打开片段时,我收到以下错误,尽管活动的布局中有容器: 找不到片段SampleFragment{eed53f7(5e4c0693-09a2-4725-a6de-1df49dd818f0)id为0x7f080053(com.app.sample:id/container)的视图id=0x7f080053} 访问此第三方库中的drawables时,出现以下错误: 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中) 在没有动态功能模块的应用程序中使用此库是很好的。Android 动态功能模块的第三方库无法访问资源,android,android-library,dynamic-feature-module,Android,Android Library,Dynamic Feature Module,我有一个应用程序,它有一个动态功能模块。在动态特征模块中,有一个包含图像、输入字段的表单,还有一个访问另一个第三方库的Button 第三方库有一个活动和片段。在活动内部打开片段时,我收到以下错误,尽管活动的布局中有容器: 找不到片段SampleFragment{eed53f7(5e4c0693-09a2-4725-a6de-1df49dd818f0)id为0x7f080053(com.app.sample:id/container)的视图id=0x7f080053} 访问此第三方库中的drawa
动态交付是一项相对较新的功能,因此它有很多局限性。其中一个限制是您不能以常规方式访问动态模块的代码和资源,因此它不能依赖于其他模块。目前,您可以通过反射访问动态模块,并通过公共库模块中的公共接口定义动态功能,并在运行时使用。它有它的性能缺点。使用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)
}
}
//所有功能定义都扩展了此接口,T是该功能所需的依赖项
接口特性{
fun getMainScreen():片段
趣味getLaunchIntent(上下文:上下文):Intent
乐趣注入(依赖项:T)
}
接口视频功能:功能{
接口依赖关系{
val okHttpClient:okHttpClient
val上下文:上下文
val处理程序:处理程序
val backgroundDispatcher:CoroutineDispatcher
}
}
内部var videoComponent:videoComponent?=无效的
专用设备
@自动服务(VideoFeature::class)
类VideoFeatureImpl:VideoFeature{
重写getLaunchIntent(上下文:context):Intent=Intent(上下文,VideoActivity::class.java)
重写getMainScreen():Fragment=createVideoFragment()
覆盖乐趣注入(依赖项:VideoFeature.dependencies){
if(videoComponent!=null){
返回
}
videoComponent=DaggerVideoComponent.factory()
.创建(依赖项,此)
}
}
并实际访问动态特性使用的代码
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
}
}
inline fun FeatureManager.getFeature(
依赖项:D
):T?{
如果(isFeatureInstalled()),则返回{
val serviceIterator=ServiceLoader.load(
T::class.java,
T::class.java.classLoader
).iterator()
if(serviceIterator.hasNext()){
val feature=serviceIterator.next()
feature.apply{inject(dependencies)}
}否则{
无效的
}
}否则{
无效的
}
}
摘自。还有更多的信息,所以我建议你检查一下
一般来说,我不建议使用动态特性作为依赖项,并相应地规划应用程序架构
希望有帮助。通常,当在
活动2中未调用SplitCompat.installActivity(this)
时,这将不起作用。虽然没有源代码,但您必须提取包并正确地重新打包,因为活动2
(甚至整个库包)可能与DFM不兼容
为基础应用程序启用SplitCompat后,需要为应用程序在动态功能模块中下载的每个活动启用SplitCompat
下面是我的另一个示例,演示了如何通过反射进行访问。对于资源,可以使用此代码部分
R.id.settings
将是:
getResources().getIdentifier("settings", "id", "com.library.package");
第三方库是否是一个开放库(例如在github上提供),以便我们可以复制?它是否仅用于dynamic-feature-module1
或App1
模块或dynamic-feature-module1
级别的其他模块?可能值得一读,因为没有最少代码的错误消息相当抽象。