Home » Android » android – Can I preserve older versions of library used by a dependency?

android – Can I preserve older versions of library used by a dependency?

Posted by: admin June 15, 2020 Leave a comment

Questions:

I have an Android project where Glide v4 is one of its dependency.

This project has another dependency, let’s call it dependency A , where it depends on Glide v3 instead.
I don’t know if it matters, but dependency A can only be included as an aar.

So this is part of my build.gradle:

implementation(name: 'dependency_a', ext: 'aar')
implementation ("com.github.bumptech.glide:glide:4.7.1") {
    exclude group: "com.android.support"
}
annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1'

The app can be compiled; but when code in dependency A runs that uses Glide v3:

Glide.with(context).load(imageUrl).asBitmap().into(new SimpleTarget<Bitmap>() {...}

The app crashes with this message:

java.lang.NoSuchMethodError: No virtual method load(Ljava/lang/String;)Lcom/bumptech/glide/DrawableTypeRequest; in class Lcom/bumptech/glide/RequestManager; or its super classes (declaration of 'com.bumptech.glide.RequestManager' appears in /data/app/{my.package.name}}-LItMzBkBqXw3lyYYdKp-SA==/base.apk:classes15.dex)

I am finding a way to preserve Glide v3 in dependency A, but still use Glide v4 for my app and other dependencies.

Is it even possible?

Why don’t I simply use Glide v3 for my app as well

This is because another dependency B needs me to use Glide v4.

How to&Answers:

Gradle’s dependency resolution is about choosing one version when multiple alternatives are available or required.

Ultimately there can only be one Class for a given class full name in a given ClassLoader, so the possibilities are :

  • Change the package name. For example Spongy Castle moved from org.bouncycastle.* to org.spongycastle.* to avoid conflicts with the platform’s version.

  • Use multiple class loaders. I believe that Android support custom class loader, but this would probably involve quite a bit of work with subtle pitfalls.

I think that unfortunately, none of this is a practical solution in your case.

Answer:

I guess you don’t have any options but to used the updated one which is Glide v4, because as you already state you are also using Glide v4. Also, it would be good if you used updated dependency/libraries because there are performance improvements and bug fixes applied in new versions.

Answer:

Gradle resolves version conflicts by picking the highest version of a module as mentioned here. So if you have v3 and v4 as your depencency, v4 will be used.

You are getting the crash since there are major changes from v3 to v4 for Glide, Dependency A cannot use methods of v4.

Solution 1 – Dependency B has to use v3 to avoid conflicts. Upgrade to v4 when Dependency A has upgraded to v4.

Solution 2 – If Dependency A can function normally without Glide dependency then, Glide can be excluded from Dependency A.

Answer:

Could your app be split into multiple binaries? Could one binary be linked with dependency A and Glade 3, and the other binary be linked with dependency B and Glade 4?

This would only make sense if the parts of the app that depend on A and Glade 3, and the parts of the app that depend on B and Glade 4, could be cleanly differentiated, so that each binary serves a particular, well-defined purpose. This approach would be conceptually similar to object oriented design, or the Unix philosophy of combining single-purpose tools to facilitate complex workflows, or the COM architecture on Windows.

When evaluating whether or not such a split is feasible, you’ll want to consider user workflows and data stores, as well as characteristics that are specific to your app. If users would move sequentially from binary A to binary B, for example, if binary A was part of the startup sequence, and users never return to binary A, that suggests that a split may be possible. On the other hand, if users would bounce back and forth between binary A and binary B, that could make a split much more difficult. Likewise, if data is stored in a database, and each binary can access the data independently, a split may be feasible. Conversely, if the data is primarily stored in process, and/or there is a lot of data to stream between the processes, then a split might not be feasible.

When working with multiple binaries in this fashion, they likely need to communicate using some sort of API, for example, the command line, pipes, file sockets, network sockets, or even simply a shared external data store that both binaries access asynchronously.

In general, the more you can limit interactions between the binaries, the better. You may be able to create a simple wrapper around dependency A and Glade 3, and call that wrapper from the remainder of your code.

Finally, if you evaluate and discover it may be feasible to split your app into multiple binaries, before proceeding, also consider the relative effort of splitting your app versus specifying new dependencies for A and B.