Reputation: 2928
I have a application which has a dynamic feature module. In dynamic feature module, there is a form with images, input fields and also it has a buttton which access another third-party library.
Third-party library has a activity and fragment. While opening fragment inside activity, I am receiving below error, although there is container in activity's layout:
No view found for id 0x7f080053 (com.app.sample:id/container) for fragment SampleFragment{eed53f7 (5e4c0693-09a2-4725-a6de-1df49dd818f0) id=0x7f080053}
When accessing drawables in this third-party library, getting below error:
java.lang.NoSuchFieldError: No static field ic_back of type I in class Lcom.third.library/R$drawable; or its superclasses (declaration of 'com.third.library.R$drawable' appears in /data/app/com.app.sample-QtC8XuamC1fHEVU4FUpWaA==/split_thirdparty.apk)
It is fine when I use this library in a application without dynamic feature module.
Upvotes: 3
Views: 2225
Reputation: 76669
Generally, when SplitCompat.installActivity(this)
isn't called in Activity2
, this won't work. While not having the source code, you'd have to extract the package and re-package it properly, because the Activity2
(or even the whole library package) likely isn't compatible with DFM.
After you enable SplitCompat for your base app, you need to enable SplitCompat for each activity that your app downloads in a dynamic feature module.
Here's another answer of mine, which demonstrates access through reflection.
Upvotes: 3
Reputation: 324
For the resources, this code part can be usage
R.id.settings
would be:
getResources().getIdentifier("settings", "id", "com.library.package");
Upvotes: 0
Reputation: 16699
Dynamic Delivery is relatively new feature so it has a lot of limitations. One of those limitations it that you cannot access code and resources of a Dynamic Module in a conventional way, thus it cannot be a dependency for other modules. Currently you can access Dynamic Module via reflection and having dynamic features defined through public interfaces in a common library module and loading their actual implementations (located in the dynamic feature modules) at runtime with a ServiceLoader
. It has its performance downsides. They can be minimized with R8 using ServiceLoaderRewriter
but not completely removed.
While using reflection is very bug prone we can minimize it either with @AutoService
— AutoService
is an annotation processor that will scan the project for classes annotated with @AutoService
, for any class it finds it will automatically generate a service definition file for it.
Here is small example of how it is done
// 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)
}
}
And to actually access code of Dynamic Feature use
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
}
}
Taken from here. Also there a lot more info there so I would recommend you to check it.
Generally I just would not recommend to use Dynamic Feature as dependency and plan your app architecture accordingly.
Hope it helps.
Upvotes: 0